diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ae5ce6f1..d5f8f01c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -34,3 +34,13 @@ jobs: if [[ $(grep -r "^ \{3,\}\(\*\|-\)" website/docs/* | wc -l) -gt 0 ]] ; then \ echo "Too many level of arugments in docs" ; grep -nr "^ \{3,\}\(\*\|-\)" website/docs/* ; exit 1 ; \ fi + - name: Check link for pages in sidebar + run: | + cd website/docs + missing="" + for i in $(find . -type f | sed 's/^.//' | sed 's/.markdown$//') ; do \ + grep -q $i ../junos.erb || missing+="Missing link to $i in website sidebar\n" ; \ + done + if [[ ${missing} != "" ]] ; then \ + echo -e "${missing}" ; exit 1 ; \ + fi \ No newline at end of file diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d2f4a445..a0cf1614 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,8 +1,8 @@ name: Go Tests on: [push, pull_request] jobs: - build: - name: Build + build-1_15: + name: Build 1.15 runs-on: ubuntu-latest steps: - name: Set up Go 1.15 @@ -15,14 +15,28 @@ jobs: - name: Build run: go build -v . + build-1_16: + name: Build 1.16 + runs-on: ubuntu-latest + steps: + - name: Set up Go 1.16 + uses: actions/setup-go@v1 + with: + go-version: 1.16 + id: go + - name: Check out code + uses: actions/checkout@v2 + - name: Build + run: go build -v . + test: name: Test runs-on: ubuntu-latest steps: - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v1 with: - go-version: 1.15 + go-version: 1.16 id: go - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/golangci-lint-latest.yml b/.github/workflows/golangci-lint-latest.yml index 698b3082..dfbaddf6 100644 --- a/.github/workflows/golangci-lint-latest.yml +++ b/.github/workflows/golangci-lint-latest.yml @@ -2,7 +2,7 @@ name: GolangCI-Lint-Latest on: push: branches: - - master + - main jobs: run: name: Run diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 8069082d..a4704cfe 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -10,5 +10,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v2 with: - version: v1.36 + version: v1.38 args: -c .golangci.yml -v diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 16edfa53..a42c9fe3 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -37,15 +37,13 @@ jobs: goos: [linux, windows, darwin, freebsd] goarch: [amd64, arm64] exclude: - - goos: darwin - goarch: arm64 - goos: windows goarch: arm64 steps: - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v1 with: - go-version: 1.15 + go-version: 1.16 id: go - name: Check out code uses: actions/checkout@v2 @@ -124,3 +122,57 @@ jobs: asset_path: ./${{ env.REPO_NAME }}_${{ env.RELEASE_VERSION }}_SHA256SUMS asset_name: ${{ env.REPO_NAME }}_${{ env.RELEASE_VERSION }}_SHA256SUMS asset_content_type: application/octet-stream + website: + name: Deploy Website + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Clone original Terraform Website + run: git clone https://github.com/hashicorp/terraform-website.git /tmp/terraform-website + - name: Copy necessary files and co + working-directory: ./.terraform-website/ + run: | + cp /tmp/terraform-website/content/config.rb . + cp /tmp/terraform-website/content/Gemfile . + cp /tmp/terraform-website/content/Gemfile.lock . + cp /tmp/terraform-website/content/middleman_helpers.rb . + cp -r /tmp/terraform-website/content/source/assets ./source/ + cp /tmp/terraform-website/content/source/layouts/inner.erb ./source/layouts/ + echo "redirect 'index.html', to: 'docs/providers/junos/index.html'" >> config.rb + - name: Setup ruby + uses: actions/setup-ruby@v1 + with: + ruby-version: "2.x" + - name: Install middleman + working-directory: ./.terraform-website/ + run: | + gem install bundler bundler:1.17.3 + # json fail with (1.8.3.1) in Gemfile.lock + bundle update json --jobs 4 --retry 3 + bundle install --jobs 4 --retry 3 + - name: Build Website + working-directory: ./.terraform-website/ + run: bundle exec middleman build --verbose + - name: Download google files from S3 + uses: ItsKarma/aws-cli@v1.70.0 + with: + args: s3 cp s3://terraform-provider-junos.jeremm.fr/google72955f25e01c2a06.html .terraform-website/build/ + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Upload Website on S3 + uses: ItsKarma/aws-cli@v1.70.0 + with: + args: s3 sync .terraform-website/build/ s3://terraform-provider-junos.jeremm.fr/ --delete + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: Invalidate Cloudfront Distribution + uses: chetan/invalidate-cloudfront-action@v1.3 + env: + PATHS: '/docs/*' + AWS_REGION: 'eu-west-1' + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + DISTRIBUTION: ${{ secrets.DISTRIBUTION_ID }} diff --git a/.github/workflows/terraform-fmt.yml b/.github/workflows/terraform-fmt.yml index 571739ab..d4c1f0a5 100644 --- a/.github/workflows/terraform-fmt.yml +++ b/.github/workflows/terraform-fmt.yml @@ -5,10 +5,10 @@ jobs: name: terrafmt runs-on: ubuntu-latest steps: - - name: Set up Go 1.15 + - name: Set up Go 1.16 uses: actions/setup-go@v2 with: - go-version: 1.15 + go-version: 1.16 id: go - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index b20daf3c..9d78026f 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -2,20 +2,14 @@ name: Website on: push: branches: - - 'master' - paths: - - '.github/workflows/website.yml' - - '.terraform-website/**' - - 'website/**' - release: - types: - - published - + - main jobs: deploy: - name: Deploy Website + name: Update Website runs-on: ubuntu-latest - if: startsWith(github.event.head_commit.message, '[website]') + if: | + startsWith(github.event.head_commit.message, '[website]') || + (github.event.release.name != '' && github.event.release.draft == false) steps: - name: Checkout code uses: actions/checkout@v2 diff --git a/.golangci.yml b/.golangci.yml index bbbbd1e5..e474e1e8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -14,6 +14,8 @@ linters: - exhaustivestruct - paralleltest - gci + - cyclop + - forcetypeassert linters-settings: gocyclo: # minimal code complexity to report, 30 by default diff --git a/CHANGELOG.md b/CHANGELOG.md index 85683041..c51508b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,31 @@ ENHANCEMENTS: BUG FIXES: +## 1.14.0 (March 19, 2021) +FEATURES: +* add `junos_chassis_cluster` resource (Fixes parts of [#106](https://github.com/jeremmfr/terraform-provider-junos/issues/106)) +* add `junos_group_dual_system` resource (Fixes [#120](https://github.com/jeremmfr/terraform-provider-junos/issues/120)) +* add `junos_null_commit_file` resource (Fixes parts of [#136](https://github.com/jeremmfr/terraform-provider-junos/issues/136)) +* add `junos_security_address_book` resource (Fixes [#137](https://github.com/jeremmfr/terraform-provider-junos/issues/137)) Thanks [@tagur87](https://github.com/tagur87) +* add `junos_security_global_policy` resource (Fixes [#138](https://github.com/jeremmfr/terraform-provider-junos/issues/138)) +* add provider argument `file_permission` +* add provider argument `fake_create_with_setfile` - **Don't use in normal terraform run** and **be carefully with this option** +See docs for more informations (Fixes parts of [#136](https://github.com/jeremmfr/terraform-provider-junos/issues/136)) + +ENHANCEMENTS: +* add `cluster`, `family_evpn` arguments in `junos_bgp_group` and `junos_bgp_neighbor` resource +* add new `bgp_multipath` block argument to replace `multipath` bool argument in `junos_bgp_group` and `junos_bgp_neighbor` resource +`bgp_multipath` let add optional arguments. `multipath` is now **deprecated** +* add `esi` argument in `junos_interface_physical` resource and data source (Fixes [#126](https://github.com/jeremmfr/terraform-provider-junos/issues/126)) Thans [@dejongm](https://github.com/dejongm) +* add `ether_opts`, `gigether_opts` and `parent_ether_opts` arguments in `junos_interface_physical` resource and data source to add more options and replace `ae_lacp`, `ae_link_speed`, `ae_minimum_links`, `ether802_3ad` arguments which are now deprecated (Fixes [#133](https://github.com/jeremmfr/terraform-provider-junos/issues/133), [#127](https://github.com/jeremmfr/terraform-provider-junos/issues/127), parts of [#106](https://github.com/jeremmfr/terraform-provider-junos/issues/106)) +* add `security_inbound_protocols` and `security_inbound_services` arguments in `junos_interface_logical` resource and data source (Fixes [#141](https://github.com/jeremmfr/terraform-provider-junos/issues/141)) +* add `feature_profile_web_filtering_juniper_enhanced_server` argument in `utm` argument of `junos_security` resource (Fixes [#155](https://github.com/jeremmfr/terraform-provider-junos/issues/155)) + +BUG FIXES: +* fix change `description` to null in `junos_interface_logical` and `junos_interface_physical` resource +* fix `prefix` list order issue in `junos_policyoptions_prefix_list` resource (Fixes [#150](https://github.com/jeremmfr/terraform-provider-junos/issues/150)) +* fix validation for `name` of `address_book` and `address_boob_set` in `junos_security_zone` resource (Fixes [#153](https://github.com/jeremmfr/terraform-provider-junos/issues/153)) + ## 1.13.1 (February 18, 2021) BUG FIXES: * fix source nat pool network address not allowed (Fixes [#128](https://github.com/jeremmfr/terraform-provider-junos/issues/128)) diff --git a/README.md b/README.md index a017686b..15b2861a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ terraform-provider-junos [![Installs](https://img.shields.io/badge/dynamic/json?logo=terraform&label=installs&query=$.data.attributes.downloads&url=https%3A%2F%2Fregistry.terraform.io%2Fv2%2Fproviders%2F713)](https://registry.terraform.io/providers/jeremmfr/junos) [![Registry](https://img.shields.io/badge/registry-doc%40latest-lightgrey?logo=terraform)](https://registry.terraform.io/providers/jeremmfr/junos/latest/docs) [![Website](https://img.shields.io/badge/website-doc%40latest-lightgrey)](https://terraform-provider-junos.jeremm.fr/) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jeremmfr/terraform-provider-junos/blob/master/LICENSE) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jeremmfr/terraform-provider-junos/blob/main/LICENSE) [![Go Status](https://github.com/jeremmfr/terraform-provider-junos/workflows/Go%20Tests/badge.svg)](https://github.com/jeremmfr/terraform-provider-junos/actions) [![Lint Status](https://github.com/jeremmfr/terraform-provider-junos/workflows/GolangCI-Lint/badge.svg)](https://github.com/jeremmfr/terraform-provider-junos/actions) [![Go Report Card](https://goreportcard.com/badge/github.com/jeremmfr/terraform-provider-junos)](https://goreportcard.com/report/github.com/jeremmfr/terraform-provider-junos) @@ -22,7 +22,7 @@ Requirements Optional --- -- [Go](https://golang.org/doc/install) 1.14 (to build the provider plugin) +- [Go](https://golang.org/doc/install) 1.15 (to build the provider plugin) Automatic install --- diff --git a/go.mod b/go.mod index 7540e185..e4b256c6 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module terraform-provider-junos -go 1.14 +go 1.15 require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.4 github.com/jeremmfr/go-netconf v0.3.1 github.com/jeremmfr/junosdecode v1.0.0 - golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 ) diff --git a/go.sum b/go.sum index 93f099a2..8f40cf2f 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -44,7 +43,6 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/g github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= @@ -60,7 +58,6 @@ github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= @@ -98,7 +95,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -106,19 +102,15 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18h github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -133,13 +125,10 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -162,13 +151,11 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= -github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= github.com/hashicorp/go-getter v1.5.0 h1:ciWJaeZWSMbc5OiLMpKp40MKFPqO44i0h3uyfXPBkkk= github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= @@ -178,7 +165,6 @@ github.com/hashicorp/go-hclog v0.15.0 h1:qMuK0wxsoW4D0ddCCYwPSTm4KQv1X1ke3WmPWZ0 github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= @@ -187,27 +173,23 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.12.0 h1:Tb1VC2gqArl9EJziJjoazep2MyxMk00tnNKV/rgMba0= -github.com/hashicorp/terraform-exec v0.12.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= +github.com/hashicorp/terraform-exec v0.13.0 h1:1Pth+pdWJAufJuWWjaVOVNEkoRTOjGn3hQpAqj4aPdg= +github.com/hashicorp/terraform-exec v0.13.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= github.com/hashicorp/terraform-json v0.8.0 h1:XObQ3PgqU52YLQKEaJ08QtUshAfN3yu4u8ebSW0vztc= github.com/hashicorp/terraform-json v0.8.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= -github.com/hashicorp/terraform-plugin-go v0.1.0 h1:kyXZ0nkHxiRev/q18N40IbRRk4AV0zE/MDJkDM3u8dY= -github.com/hashicorp/terraform-plugin-go v0.1.0/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0 h1:2c+vG46celrDCsfYEIzaXxvBaAXCqlVG77LwtFz8cfs= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0/go.mod h1:JBItawj+j8Ssla5Ib6BC/W9VQkOucBfnX7VRtyx1vw8= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/terraform-plugin-go v0.2.1 h1:EW/R8bB2Zbkjmugzsy1d27yS8/0454b3MtYHkzOknqA= +github.com/hashicorp/terraform-plugin-go v0.2.1/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.4 h1:6k0WcxFgVqF/GUFHPvAH8FIrCkoA1RInXzSxhkKamPg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.4/go.mod h1:z+cMZ0iswzZOahBJ3XmNWgWkVnAd2bl8g+FhyyuPDH4= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -236,7 +218,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -252,7 +233,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mitchellh/cli v1.1.1 h1:J64v/xD7Clql+JVKSvkYojLOXu1ibnY9ZjGLwSt/89w= github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -260,7 +240,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -269,7 +248,6 @@ github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -287,20 +265,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -317,7 +291,6 @@ github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -328,14 +301,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -379,7 +350,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -388,7 +358,6 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -399,9 +368,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= @@ -422,7 +389,6 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dzugGxJ/SQHoNufZJq1w= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -430,6 +396,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -437,7 +404,6 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -446,10 +412,11 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -502,7 +469,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= @@ -517,23 +483,19 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -559,18 +521,14 @@ google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6D google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -586,7 +544,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/junos/config.go b/junos/config.go index 1af76f29..baa09cd9 100644 --- a/junos/config.go +++ b/junos/config.go @@ -1,6 +1,9 @@ package junos import ( + "fmt" + "strconv" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" ) @@ -17,7 +20,9 @@ type Config struct { junosSSHKeyFile string junosKeyPass string junosGroupIntDel string + junosFilePermission string junosDebugNetconfLogPath string + junosFakeCreateSetFile string } // Session : read session information for Junos Device. @@ -28,14 +33,40 @@ func (c *Config) Session() (*Session, diag.Diagnostics) { junosUserName: c.junosUserName, junosPassword: c.junosPassword, junosSSHKeyPEM: c.junosSSHKeyPEM, - junosSSHKeyFile: c.junosSSHKeyFile, junosKeyPass: c.junosKeyPass, junosGroupIntDel: c.junosGroupIntDel, - junosLogFile: c.junosDebugNetconfLogPath, junosSleepLock: c.junosCmdSleepLock, junosSleepShort: c.junosCmdSleepShort, junosSleepSSHClosed: c.junosSSHSleepClosed, } + // junosSSHKeyFile + sshKeyFile := c.junosSSHKeyFile + if err := replaceTildeToHomeDir(&sshKeyFile); err != nil { + return sess, diag.FromErr(err) + } + sess.junosSSHKeyFile = sshKeyFile + + // junosFilePermission + filePermission, err := strconv.ParseInt(c.junosFilePermission, 8, 64) + if err != nil { + return sess, diag.FromErr(fmt.Errorf("failed to convert value from '%s' to int64 : %w", + c.junosFilePermission, err)) + } + sess.junosFilePermission = filePermission + + // junosLogFile + junosLogFile := c.junosDebugNetconfLogPath + if err := replaceTildeToHomeDir(&junosLogFile); err != nil { + return sess, diag.FromErr(err) + } + sess.junosLogFile = junosLogFile + + // junosFakeCreateSetFile + junosFakeCreateSetFile := c.junosFakeCreateSetFile + if err := replaceTildeToHomeDir(&junosFakeCreateSetFile); err != nil { + return sess, diag.FromErr(err) + } + sess.junosFakeCreateSetFile = junosFakeCreateSetFile return sess, nil } diff --git a/junos/data_source_interface_logical.go b/junos/data_source_interface_logical.go index 4dd8846b..79c5b542 100644 --- a/junos/data_source_interface_logical.go +++ b/junos/data_source_interface_logical.go @@ -309,6 +309,17 @@ func dataSourceInterfaceLogical() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "security_inbound_protocols": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "security_inbound_services": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "security_zone": { Type: schema.TypeString, Computed: true, diff --git a/junos/data_source_interface_physical.go b/junos/data_source_interface_physical.go index f8afa19e..4e8d1ef7 100644 --- a/junos/data_source_interface_physical.go +++ b/junos/data_source_interface_physical.go @@ -40,20 +40,277 @@ func dataSourceInterfacePhysical() *schema.Resource { Computed: true, }, "ae_lacp": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, + Deprecated: "use parent_ether_opts { lacp } instead", }, "ae_link_speed": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, + Deprecated: "use parent_ether_opts { link_speed } instead", }, "ae_minimum_links": { - Type: schema.TypeInt, + Type: schema.TypeInt, + Computed: true, + Deprecated: "use parent_ether_opts { minimum_links } instead", + }, + "esi": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "mode": { + Type: schema.TypeString, + Computed: true, + }, + "auto_derive_lacp": { + Type: schema.TypeBool, + Computed: true, + }, + "df_election_type": { + Type: schema.TypeString, + Computed: true, + }, + "identifier": { + Type: schema.TypeString, + Computed: true, + }, + "source_bmac": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "ether_opts": { + Type: schema.TypeList, Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ae_8023ad": { + Type: schema.TypeString, + Computed: true, + }, + "auto_negotiation": { + Type: schema.TypeBool, + Computed: true, + }, + "no_auto_negotiation": { + Type: schema.TypeBool, + Computed: true, + }, + "flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "no_flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "no_loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "redundant_parent": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, "ether802_3ad": { - Type: schema.TypeString, + Type: schema.TypeString, + Computed: true, + Deprecated: "use ether_opts { ae_8023ad } or gigether_opts { ae_8023ad } instead", + }, + "gigether_opts": { + Type: schema.TypeList, Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ae_8023ad": { + Type: schema.TypeString, + Computed: true, + }, + "auto_negotiation": { + Type: schema.TypeBool, + Computed: true, + }, + "no_auto_negotiation": { + Type: schema.TypeBool, + Computed: true, + }, + "flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "no_flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "no_loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "redundant_parent": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "parent_ether_opts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bfd_liveness_detection": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "local_address": { + Type: schema.TypeString, + Computed: true, + }, + "authentication_algorithm": { + Type: schema.TypeString, + Computed: true, + }, + "authentication_key_chain": { + Type: schema.TypeString, + Computed: true, + }, + "authentication_loose_check": { + Type: schema.TypeBool, + Computed: true, + }, + "detection_time_threshold": { + Type: schema.TypeInt, + Computed: true, + }, + "holddown_interval": { + Type: schema.TypeInt, + Computed: true, + }, + "minimum_interval": { + Type: schema.TypeInt, + Computed: true, + }, + "minimum_receive_interval": { + Type: schema.TypeInt, + Computed: true, + }, + "multiplier": { + Type: schema.TypeInt, + Computed: true, + }, + "neighbor": { + Type: schema.TypeString, + Computed: true, + }, + "no_adaptation": { + Type: schema.TypeBool, + Computed: true, + }, + "transmit_interval_minimum_interval": { + Type: schema.TypeInt, + Computed: true, + }, + "transmit_interval_threshold": { + Type: schema.TypeInt, + Computed: true, + }, + "version": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "no_flow_control": { + Type: schema.TypeBool, + Computed: true, + }, + "lacp": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "mode": { + Type: schema.TypeString, + Computed: true, + }, + "admin_key": { + Type: schema.TypeInt, + Computed: true, + }, + "periodic": { + Type: schema.TypeString, + Computed: true, + }, + "sync_reset": { + Type: schema.TypeString, + Computed: true, + }, + "system_id": { + Type: schema.TypeString, + Computed: true, + }, + "system_priority": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "no_loopback": { + Type: schema.TypeBool, + Computed: true, + }, + "link_speed": { + Type: schema.TypeString, + Computed: true, + }, + "minimum_bandwidth": { + Type: schema.TypeString, + Computed: true, + }, + "minimum_links": { + Type: schema.TypeInt, + Computed: true, + }, + "redundancy_group": { + Type: schema.TypeInt, + Computed: true, + }, + "source_address_filter": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "source_filtering": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, }, "trunk": { Type: schema.TypeBool, diff --git a/junos/func_common.go b/junos/func_common.go index 4bd455f5..7c3e3bbf 100644 --- a/junos/func_common.go +++ b/junos/func_common.go @@ -2,33 +2,22 @@ package junos import ( "fmt" - "log" "net" "os" + "strconv" "strings" - "time" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func logFile(message string, file string) { - // create your file with desired read/write permissions - f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - log.Fatal(err) - } - - // defer to close when you're done with it, not because you think it's idiomatic! - defer f.Close() - - // set output of logs to f - log.SetOutput(f) - log.SetPrefix(time.Now().Format("2006-01-02 15:04:05")) +type FormatName int - log.Printf("%s", message) -} +const ( + FormatDefault FormatName = iota + FormatAddressName +) func appendDiagWarns(diags *diag.Diagnostics, warns []error) { for _, w := range warns { @@ -99,7 +88,49 @@ func validateCIDR(cidr string) error { return nil } -func validateNameObjectJunos(exclude []string, length int) schema.SchemaValidateDiagFunc { +func validateWildcardFunc() schema.SchemaValidateDiagFunc { + return func(i interface{}, path cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + v := i.(string) + err := validateWildcardWithMask(v) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: err.Error(), + AttributePath: path, + }) + } + + return diags + } +} + +func validateWildcardWithMask(wildcard string) error { + if !strings.Contains(wildcard, "/") { + return fmt.Errorf("%v missing mask", wildcard) + } + if strings.Contains(wildcard, ":") { + return fmt.Errorf("wildcards do not support IPv6 addresses, %v is IPv6", wildcard) + } + wildcardSplit := strings.Split(wildcard, "/") + ip := net.ParseIP(wildcardSplit[0]).To4() + if ip == nil { + return fmt.Errorf("ip %v not a valid ip address", wildcardSplit[0]) + } + mask := net.ParseIP(wildcardSplit[1]).To4() + if mask == nil { + return fmt.Errorf("mask %v is improperly formatted, must be in x.x.x.x notation", wildcardSplit[1]) + } + for _, octet := range strings.Split(mask.String(), ".") { + if !stringInSlice(octet, []string{"255", "254", "252", "248", "240", "224", "192", "128", "0"}) { + return fmt.Errorf("mask %v must be in subnet mask format, octet [%v] is not", mask, octet) + } + } + + return nil +} + +func validateNameObjectJunos(exclude []string, length int, format FormatName) schema.SchemaValidateDiagFunc { return func(i interface{}, path cty.Path) diag.Diagnostics { var diags diag.Diagnostics v := i.(string) @@ -110,10 +141,27 @@ func validateNameObjectJunos(exclude []string, length int) schema.SchemaValidate AttributePath: path, }) } - f := func(r rune) bool { + f1 := func(r rune) bool { return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0' || r > '9') && r != '-' && r != '_' } - if strings.IndexFunc(v, f) != -1 { + f2 := func(r rune) bool { + return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0' || r > '9') && + r != '-' && r != '_' && r != ':' && r != '.' && r != '/' + } + resultRune := -1 + switch format { + case FormatDefault: + resultRune = strings.IndexFunc(v, f1) + case FormatAddressName: + resultRune = strings.IndexFunc(v, f2) + default: + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "internal error: validateNameObjectJunos function called with a bad argument", + AttributePath: path, + }) + } + if resultRune != -1 { diags = append(diags, diag.Diagnostic{ Severity: diag.Error, Summary: fmt.Sprintf("%s invalid name (bad character)", i), @@ -150,6 +198,42 @@ func validateAddress() schema.SchemaValidateDiagFunc { return diags } } +func validateFilePermission() schema.SchemaValidateDiagFunc { + return func(i interface{}, path cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + v, ok := i.(string) + + if !ok { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "expected type to be string", + AttributePath: path, + }) + + return diags + } + + if len(v) > 4 || len(v) < 3 { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: fmt.Sprintf("bad mode for file - string length should be 3 or 4 digits: %s", v), + AttributePath: path, + }) + } + + fileMode, err := strconv.ParseInt(v, 8, 64) + + if err != nil || fileMode > 0777 || fileMode < 0 { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: fmt.Sprintf("bad mode for file - must be three octal digits: %s", v), + AttributePath: path, + }) + } + + return diags + } +} func stringInSlice(str string, list []string) bool { for _, v := range list { @@ -255,3 +339,15 @@ func checkStringHasPrefixInList(s string, list []string) bool { return false } + +func replaceTildeToHomeDir(path *string) error { + if strings.HasPrefix(*path, "~") { + homeDir, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("failed to read user home directory : %w", err) + } + *path = homeDir + strings.TrimPrefix(*path, "~") + } + + return nil +} diff --git a/junos/func_resource_bgp.go b/junos/func_resource_bgp.go index d1c8dfcf..206ef241 100644 --- a/junos/func_resource_bgp.go +++ b/junos/func_resource_bgp.go @@ -42,6 +42,7 @@ type bgpOptions struct { authenticationKey string authenticationKeyChain string bgpType string // group only + cluster string localAddress string localAs string localInterface string @@ -52,6 +53,8 @@ type bgpOptions struct { exportPolicy []string importPolicy []string bfdLivenessDetection []map[string]interface{} + bgpMultipath []map[string]interface{} + familyEvpn []map[string]interface{} familyInet []map[string]interface{} familyInet6 []map[string]interface{} gracefulRestart []map[string]interface{} @@ -90,8 +93,10 @@ func delBgpOpts(d *schema.ResourceData, typebgp string, m interface{}, jnprSess delPrefix+"authentication-key", delPrefix+"authentication-key-chain", delPrefix+"bfd-liveness-detection", + delPrefix+"cluster", delPrefix+"damping", delPrefix+"export", + delPrefix+"family evpn", delPrefix+"family inet", delPrefix+"family inet6", delPrefix+"graceful-restart", @@ -114,11 +119,7 @@ func delBgpOpts(d *schema.ResourceData, typebgp string, m interface{}, jnprSess delPrefix+"type", ) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func setBgpOptsSimple(setPrefix string, d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) @@ -150,6 +151,24 @@ func setBgpOptsSimple(setPrefix string, d *schema.ResourceData, m interface{}, j if d.Get("authentication_key_chain").(string) != "" { configSet = append(configSet, setPrefix+"authentication-key-chain "+d.Get("authentication_key_chain").(string)) } + for _, v := range d.Get("bgp_multipath").([]interface{}) { + configSet = append(configSet, setPrefix+"multipath") + if v != nil { + bgpMultipah := v.(map[string]interface{}) + if bgpMultipah["allow_protection"].(bool) { + configSet = append(configSet, setPrefix+"multipath allow-protection") + } + if bgpMultipah["disable"].(bool) { + configSet = append(configSet, setPrefix+"multipath disable") + } + if bgpMultipah["multiple_as"].(bool) { + configSet = append(configSet, setPrefix+"multipath multiple-as") + } + } + } + if v := d.Get("cluster").(string); v != "" { + configSet = append(configSet, setPrefix+"cluster "+v) + } if d.Get("damping").(bool) { configSet = append(configSet, setPrefix+"damping") } @@ -247,11 +266,8 @@ func setBgpOptsSimple(setPrefix string, d *schema.ResourceData, m interface{}, j if d.Get("remove_private").(bool) { configSet = append(configSet, setPrefix+"remove-private") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readBgpOptsSimple(item string, confRead *bgpOptions) error { var err error @@ -285,6 +301,9 @@ func readBgpOptsSimple(item string, confRead *bgpOptions) error { if strings.HasPrefix(item, "authentication-key-chain ") { confRead.authenticationKeyChain = strings.TrimPrefix(item, "authentication-key-chain ") } + if strings.HasPrefix(item, "cluster ") { + confRead.cluster = strings.TrimPrefix(item, "cluster ") + } if item == "damping" { confRead.damping = true } @@ -366,8 +385,23 @@ func readBgpOptsSimple(item string, confRead *bgpOptions) error { if item == "multihop" { confRead.multihop = true } - if item == "multipath" { + if strings.HasPrefix(item, "multipath") { confRead.multipath = true + if len(confRead.bgpMultipath) == 0 { + confRead.bgpMultipath = append(confRead.bgpMultipath, map[string]interface{}{ + "allow_protection": false, + "disable": false, + "multiple_as": false, + }) + } + switch { + case item == "multipath allow-protection": + confRead.bgpMultipath[0]["allow_protection"] = true + case item == "multipath disable": + confRead.bgpMultipath[0]["disable"] = true + case item == "multipath multiple-as": + confRead.bgpMultipath[0]["multiple_as"] = true + } } if item == "no-advertise-peer-as" { confRead.noAdvertisePeerAs = true @@ -561,9 +595,12 @@ func setBgpOptsFamily(setPrefix, familyType string, familyOptsList []interface{} sess := m.(*Session) configSet := make([]string, 0) setPrefixFamily := setPrefix + "family " - if familyType == inetWord { + switch familyType { + case "evpn": + setPrefixFamily += "evpn " + case inetWord: setPrefixFamily += "inet " - } else if familyType == inet6Word { + case inet6Word: setPrefixFamily += "inet6 " } for _, familyOpts := range familyOptsList { @@ -625,10 +662,12 @@ func readBgpOptsFamily(item, familyType string, opts []map[string]interface{}) ( "prefix_limit": make([]map[string]interface{}, 0, 1), } setPrefix := "family " - if familyType == inetWord { + switch familyType { + case "evpn": + setPrefix += "evpn " + case inetWord: setPrefix += "inet " - } - if familyType == inet6Word { + case inet6Word: setPrefix += "inet6 " } trimSplit := strings.Split(strings.TrimPrefix(item, setPrefix), " ") diff --git a/junos/provider.go b/junos/provider.go index aedd0dc3..6772c319 100644 --- a/junos/provider.go +++ b/junos/provider.go @@ -9,27 +9,33 @@ import ( ) const ( - idSeparator = "_-_" - defaultWord = "default" - inetWord = "inet" - inet6Word = "inet6" - emptyWord = "empty" - matchWord = "match" - permitWord = "permit" - thenWord = "then" - prefixWord = "prefix" - actionNoneWord = "none" - addWord = "add" - deleteWord = "delete" - setWord = "set" - setLineStart = setWord + " " - st0Word = "st0" - opsfV2 = "ospf" - ospfV3 = "ospf3" - passiveW = "passive" - discardW = "discard" - disableW = "disable" - dynamicDB = "dynamic-db" + idSeparator = "_-_" + defaultWord = "default" + inetWord = "inet" + inet6Word = "inet6" + emptyWord = "empty" + matchWord = "match" + permitWord = "permit" + thenWord = "then" + prefixWord = "prefix" + actionNoneWord = "none" + addWord = "add" + deleteWord = "delete" + setWord = "set" + setLineStart = setWord + " " + st0Word = "st0" + opsfV2 = "ospf" + ospfV3 = "ospf3" + activeW = "active" + passiveW = "passive" + discardW = "discard" + disableW = "disable" + dynamicDB = "dynamic-db" + preemptWord = "preempt" + flowControlWords = "flow-control" + noFlowControlWords = "no-flow-control" + loopbackWord = "loopback" + noLoopbackWord = "no-loopback" ) var ( @@ -95,11 +101,22 @@ func Provider() *schema.Provider { Optional: true, DefaultFunc: schema.EnvDefaultFunc("JUNOS_SLEEP_SSH_CLOSED", 0), }, + "file_permission": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("JUNOS_FILE_PERMISSION", "644"), + ValidateDiagFunc: validateFilePermission(), + }, "debug_netconf_log_path": { Type: schema.TypeString, Optional: true, DefaultFunc: schema.EnvDefaultFunc("JUNOS_LOG_PATH", ""), }, + "fake_create_with_setfile": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("JUNOS_FAKECREATE_SETFILE", ""), + }, }, ResourcesMap: map[string]*schema.Resource{ "junos_aggregate_route": resourceAggregateRoute(), @@ -107,12 +124,15 @@ func Provider() *schema.Provider { "junos_application_set": resourceApplicationSet(), "junos_bgp_group": resourceBgpGroup(), "junos_bgp_neighbor": resourceBgpNeighbor(), + "junos_chassis_cluster": resourceChassisCluster(), "junos_firewall_filter": resourceFirewallFilter(), "junos_firewall_policer": resourceFirewallPolicer(), + "junos_group_dual_system": resourceGroupDualSystem(), "junos_interface": resourceInterface(), "junos_interface_logical": resourceInterfaceLogical(), "junos_interface_physical": resourceInterfacePhysical(), "junos_interface_st0_unit": resourceInterfaceSt0Unit(), + "junos_null_commit_file": resourceNullCommitFile(), "junos_ospf_area": resourceOspfArea(), "junos_policyoptions_as_path": resourcePolicyoptionsAsPath(), "junos_policyoptions_as_path_group": resourcePolicyoptionsAsPathGroup(), @@ -123,6 +143,8 @@ func Provider() *schema.Provider { "junos_routing_instance": resourceRoutingInstance(), "junos_routing_options": resourceRoutingOptions(), "junos_security": resourceSecurity(), + "junos_security_address_book": resourceSecurityAddressBook(), + "junos_security_global_policy": resourceSecurityGlobalPolicy(), "junos_security_ike_gateway": resourceIkeGateway(), "junos_security_ike_policy": resourceIkePolicy(), "junos_security_ike_proposal": resourceIkeProposal(), @@ -180,7 +202,9 @@ func configureProvider(ctx context.Context, d *schema.ResourceData) (interface{} junosCmdSleepShort: d.Get("cmd_sleep_short").(int), junosCmdSleepLock: d.Get("cmd_sleep_lock").(int), junosSSHSleepClosed: d.Get("ssh_sleep_closed").(int), + junosFilePermission: d.Get("file_permission").(string), junosDebugNetconfLogPath: d.Get("debug_netconf_log_path").(string), + junosFakeCreateSetFile: d.Get("fake_create_with_setfile").(string), } return config.Session() diff --git a/junos/provider_test.go b/junos/provider_test.go index 615b000a..5e9e0263 100644 --- a/junos/provider_test.go +++ b/junos/provider_test.go @@ -41,6 +41,9 @@ func testAccPreCheck(t *testing.T) { if os.Getenv("JUNOS_KEYFILE") == "" && os.Getenv("JUNOS_PASSWORD") == "" && os.Getenv("JUNOS_KEYPEM") == "" { t.Fatal("JUNOS_KEYPEM, JUNOS_KEYFILE or JUNOS_PASSWORD must be set for acceptance tests") } + if os.Getenv("JUNOS_FAKECREATE_SETFILE") != "" { + t.Fatal("can't run testacc with JUNOS_FAKECREATE_SETFILE") + } if err := testAccProvider.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)); err != nil { t.Fatal(err) diff --git a/junos/resource_aggregate_route.go b/junos/resource_aggregate_route.go index deb893e4..321d374b 100644 --- a/junos/resource_aggregate_route.go +++ b/junos/resource_aggregate_route.go @@ -46,7 +46,7 @@ func resourceAggregateRoute() *schema.Resource { Optional: true, ForceNew: true, Default: defaultWord, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "active": { Type: schema.TypeBool, @@ -96,6 +96,14 @@ func resourceAggregateRoute() *schema.Resource { func resourceAggregateRouteCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setAggregateRoute(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("destination").(string) + idSeparator + d.Get("routing_instance").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -335,11 +343,8 @@ func setAggregateRoute(d *schema.ResourceData, m interface{}, jnprSess *NetconfO if d.Get("preference").(int) > 0 { configSet = append(configSet, setPrefix+" preference "+strconv.Itoa(d.Get("preference").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readAggregateRoute(destination string, instance string, m interface{}, jnprSess *NetconfObject) (aggregateRouteOptions, error) { @@ -371,7 +376,7 @@ func readAggregateRoute(destination string, instance string, m interface{}, } itemTrim := strings.TrimPrefix(item, setLineStart) switch { - case itemTrim == "active": + case itemTrim == activeW: confRead.active = true case itemTrim == "brief": confRead.brief = true @@ -413,7 +418,7 @@ func delAggregateRouteOpts(d *schema.ResourceData, m interface{}, jnprSess *Netc } delPrefix += d.Get("destination").(string) + " " configSet = append(configSet, - delPrefix+"active", + delPrefix+activeW, delPrefix+"brief", delPrefix+"community", delPrefix+"discard", @@ -423,11 +428,8 @@ func delAggregateRouteOpts(d *schema.ResourceData, m interface{}, jnprSess *Netc delPrefix+"policy", delPrefix+"preference", ) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delAggregateRoute(destination string, instance string, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) @@ -437,11 +439,8 @@ func delAggregateRoute(destination string, instance string, m interface{}, jnprS } else { configSet = append(configSet, "delete routing-instances "+instance+" routing-options aggregate route "+destination) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillAggregateRouteData(d *schema.ResourceData, aggregateRouteOptions aggregateRouteOptions) { diff --git a/junos/resource_application.go b/junos/resource_application.go index 0e28e00b..0ab371a8 100644 --- a/junos/resource_application.go +++ b/junos/resource_application.go @@ -30,7 +30,7 @@ func resourceApplication() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "destination_port": { Type: schema.TypeString, @@ -50,6 +50,14 @@ func resourceApplication() *schema.Resource { func resourceApplicationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setApplication(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -226,11 +234,7 @@ func setApplication(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje configSet = append(configSet, setPrefix+" source-port "+d.Get("source_port").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readApplication(application string, m interface{}, jnprSess *NetconfObject) (applicationOptions, error) { sess := m.(*Session) @@ -268,11 +272,8 @@ func delApplication(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete applications application "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillApplicationData(d *schema.ResourceData, applicationOptions applicationOptions) { diff --git a/junos/resource_application_set.go b/junos/resource_application_set.go index db4553c4..f06270e3 100644 --- a/junos/resource_application_set.go +++ b/junos/resource_application_set.go @@ -28,7 +28,7 @@ func resourceApplicationSet() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "applications": { Type: schema.TypeList, @@ -42,6 +42,14 @@ func resourceApplicationSet() *schema.Resource { func resourceApplicationSetCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setApplicationSet(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -213,11 +221,7 @@ func setApplicationSet(d *schema.ResourceData, m interface{}, jnprSess *NetconfO configSet = append(configSet, setPrefix+" application "+v.(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readApplicationSet(applicationSet string, m interface{}, jnprSess *NetconfObject) (applicationSetOptions, error) { sess := m.(*Session) @@ -250,11 +254,8 @@ func delApplicationSet(d *schema.ResourceData, m interface{}, jnprSess *NetconfO sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete applications application-set "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillApplicationSetData(d *schema.ResourceData, applicationSetOptions applicationSetOptions) { diff --git a/junos/resource_bgp_group.go b/junos/resource_bgp_group.go index 64b1f7d4..cbb36819 100644 --- a/junos/resource_bgp_group.go +++ b/junos/resource_bgp_group.go @@ -24,14 +24,14 @@ func resourceBgpGroup() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "routing_instance": { Type: schema.TypeString, Optional: true, ForceNew: true, Default: defaultWord, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "type": { Type: schema.TypeString, @@ -153,6 +153,33 @@ func resourceBgpGroup() *schema.Resource { }, }, }, + "bgp_multipath": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"multipath"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_protection": { + Type: schema.TypeBool, + Optional: true, + }, + "disable": { + Type: schema.TypeBool, + Optional: true, + }, + "multiple_as": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "cluster": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsIPAddress, + }, "damping": { Type: schema.TypeBool, Optional: true, @@ -162,6 +189,76 @@ func resourceBgpGroup() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "family_evpn": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "nlri_type": { + Type: schema.TypeString, + Optional: true, + Default: "signaling", + ValidateFunc: validation.StringInSlice([]string{"signaling"}, false), + }, + "accepted_prefix_limit": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maximum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "teardown": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 100), + }, + "teardown_idle_timeout": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 2400), + }, + "teardown_idle_timeout_forever": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "prefix_limit": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maximum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "teardown": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 100), + }, + "teardown_idle_timeout": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 2400), + }, + "teardown_idle_timeout_forever": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, "family_inet": { Type: schema.TypeList, Optional: true, @@ -443,8 +540,10 @@ func resourceBgpGroup() *schema.Resource { Optional: true, }, "multipath": { - Type: schema.TypeBool, - Optional: true, + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"bgp_multipath"}, + Deprecated: "use bgp_multipath instead", }, "out_delay": { Type: schema.TypeInt, @@ -475,6 +574,14 @@ func resourceBgpGroup() *schema.Resource { func resourceBgpGroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setBgpGroup(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string) + idSeparator + d.Get("routing_instance").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -691,17 +798,17 @@ func setBgpGroup(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) if err := setBgpOptsBfd(setPrefix, d.Get("bfd_liveness_detection").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsFamily(setPrefix, inetWord, d.Get("family_inet").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, "evpn", d.Get("family_evpn").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsFamily(setPrefix, inet6Word, d.Get("family_inet6").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, inetWord, d.Get("family_inet").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsGrafefulRestart(setPrefix, d.Get("graceful_restart").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, inet6Word, d.Get("family_inet6").([]interface{}), m, jnprSess); err != nil { return err } - return nil + return setBgpOptsGrafefulRestart(setPrefix, d.Get("graceful_restart").([]interface{}), m, jnprSess) } func readBgpGroup(bgpGroup, instance string, m interface{}, jnprSess *NetconfObject) (bgpOptions, error) { sess := m.(*Session) @@ -743,12 +850,16 @@ func readBgpGroup(bgpGroup, instance string, m interface{}, jnprSess *NetconfObj if err != nil { return confRead, err } + case strings.HasPrefix(itemTrim, "family evpn "): + confRead.familyEvpn, err = readBgpOptsFamily(itemTrim, "evpn", confRead.familyEvpn) + if err != nil { + return confRead, err + } case strings.HasPrefix(itemTrim, "family inet "): confRead.familyInet, err = readBgpOptsFamily(itemTrim, inetWord, confRead.familyInet) if err != nil { return confRead, err } - case strings.HasPrefix(itemTrim, "family inet6 "): confRead.familyInet6, err = readBgpOptsFamily(itemTrim, inet6Word, confRead.familyInet6) if err != nil { @@ -779,11 +890,8 @@ func delBgpGroup(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) configSet = append(configSet, "delete routing-instances "+d.Get("routing_instance").(string)+ " protocols bgp group "+d.Get("name").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillBgpGroupData(d *schema.ResourceData, bgpGroupOptions bgpOptions) { @@ -823,12 +931,18 @@ func fillBgpGroupData(d *schema.ResourceData, bgpGroupOptions bgpOptions) { if tfErr := d.Set("bfd_liveness_detection", bgpGroupOptions.bfdLivenessDetection); tfErr != nil { panic(tfErr) } + if tfErr := d.Set("cluster", bgpGroupOptions.cluster); tfErr != nil { + panic(tfErr) + } if tfErr := d.Set("damping", bgpGroupOptions.damping); tfErr != nil { panic(tfErr) } if tfErr := d.Set("export", bgpGroupOptions.exportPolicy); tfErr != nil { panic(tfErr) } + if tfErr := d.Set("family_evpn", bgpGroupOptions.familyEvpn); tfErr != nil { + panic(tfErr) + } if tfErr := d.Set("family_inet", bgpGroupOptions.familyInet); tfErr != nil { panic(tfErr) } @@ -895,8 +1009,14 @@ func fillBgpGroupData(d *schema.ResourceData, bgpGroupOptions bgpOptions) { if tfErr := d.Set("multihop", bgpGroupOptions.multihop); tfErr != nil { panic(tfErr) } - if tfErr := d.Set("multipath", bgpGroupOptions.multipath); tfErr != nil { - panic(tfErr) + if _, ok := d.GetOk("multipath"); ok { + if tfErr := d.Set("multipath", bgpGroupOptions.multipath); tfErr != nil { + panic(tfErr) + } + } else { + if tfErr := d.Set("bgp_multipath", bgpGroupOptions.bgpMultipath); tfErr != nil { + panic(tfErr) + } } if tfErr := d.Set("no_advertise_peer_as", bgpGroupOptions.noAdvertisePeerAs); tfErr != nil { panic(tfErr) diff --git a/junos/resource_bgp_group_test.go b/junos/resource_bgp_group_test.go index 70907857..80c9d587 100644 --- a/junos/resource_bgp_group_test.go +++ b/junos/resource_bgp_group_test.go @@ -29,6 +29,8 @@ func TestAccJunosBgpGroup_basic(t *testing.T) { "advertise_peer_as", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "as_override", "true"), + resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", + "cluster", "192.0.2.3"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "damping", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", @@ -36,7 +38,7 @@ func TestAccJunosBgpGroup_basic(t *testing.T) { resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "mtu_discovery", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", - "multipath", "true"), + "bgp_multipath.#", "1"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "remove_private", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", @@ -140,6 +142,10 @@ func TestAccJunosBgpGroup_basic(t *testing.T) { "type", "internal"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "advertise_external_conditional", "true"), + resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", + "bgp_multipath.#", "1"), + resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", + "bgp_multipath.0.multiple_as", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", "no_advertise_peer_as", "true"), resource.TestCheckResourceAttr("junos_bgp_group.testacc_bgpgroup", @@ -209,15 +215,16 @@ resource junos_policyoptions_policy_statement "testacc_bgpgroup" { } } resource junos_bgp_group "testacc_bgpgroup" { - name = "testacc_bgpgroup" - routing_instance = junos_routing_instance.testacc_bgpgroup.name - advertise_inactive = true - advertise_peer_as = true - as_override = true + name = "testacc_bgpgroup" + routing_instance = junos_routing_instance.testacc_bgpgroup.name + advertise_inactive = true + advertise_peer_as = true + as_override = true + bgp_multipath {} + cluster = "192.0.2.3" damping = true log_updown = true mtu_discovery = true - multipath = true remove_private = true passive = true hold_time = 30 @@ -310,12 +317,14 @@ resource junos_bgp_group "testacc_bgpgroup" { metric_out_igp_delay_med_update = true authentication_key = "password" type = "internal" + bgp_multipath { + multiple_as = true + } graceful_restart { restart_time = 10 stale_route_time = 10 } } - ` } func testAccJunosBgpGroupConfigUpdate2() string { @@ -329,6 +338,18 @@ resource junos_bgp_group "testacc_bgpgroup" { local_as_no_prepend_global_as = true metric_out_minimum_igp_offset = -10 type = "internal" + family_evpn { + accepted_prefix_limit { + maximum = 2 + teardown = 50 + teardown_idle_timeout = 30 + } + prefix_limit { + maximum = 2 + teardown = 50 + teardown_idle_timeout = 30 + } + } } ` } @@ -339,6 +360,7 @@ resource junos_bgp_group "testacc_bgpgroup" { local_as = "65000" local_as_alias = true metric_out_minimum_igp = true + family_evpn {} } ` } diff --git a/junos/resource_bgp_neighbor.go b/junos/resource_bgp_neighbor.go index 0ea46b88..c4eedefd 100644 --- a/junos/resource_bgp_neighbor.go +++ b/junos/resource_bgp_neighbor.go @@ -31,13 +31,13 @@ func resourceBgpNeighbor() *schema.Resource { Optional: true, ForceNew: true, Default: defaultWord, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "group": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "accept_remote_nexthop": { Type: schema.TypeBool, @@ -151,6 +151,33 @@ func resourceBgpNeighbor() *schema.Resource { }, }, }, + "bgp_multipath": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"multipath"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_protection": { + Type: schema.TypeBool, + Optional: true, + }, + "disable": { + Type: schema.TypeBool, + Optional: true, + }, + "multiple_as": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "cluster": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsIPAddress, + }, "damping": { Type: schema.TypeBool, Optional: true, @@ -160,6 +187,76 @@ func resourceBgpNeighbor() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "family_evpn": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "nlri_type": { + Type: schema.TypeString, + Optional: true, + Default: "signaling", + ValidateFunc: validation.StringInSlice([]string{"signaling"}, false), + }, + "accepted_prefix_limit": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maximum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "teardown": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 100), + }, + "teardown_idle_timeout": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 2400), + }, + "teardown_idle_timeout_forever": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "prefix_limit": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maximum": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "teardown": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 100), + }, + "teardown_idle_timeout": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 2400), + }, + "teardown_idle_timeout_forever": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, "family_inet": { Type: schema.TypeList, Optional: true, @@ -437,8 +534,10 @@ func resourceBgpNeighbor() *schema.Resource { Optional: true, }, "multipath": { - Type: schema.TypeBool, - Optional: true, + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"bgp_multipath"}, + Deprecated: "use bgp_multipath instead", }, "out_delay": { Type: schema.TypeInt, @@ -469,6 +568,16 @@ func resourceBgpNeighbor() *schema.Resource { func resourceBgpNeighborCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setBgpNeighbor(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("ip").(string) + + idSeparator + d.Get("routing_instance").(string) + + idSeparator + d.Get("group").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -692,17 +801,17 @@ func setBgpNeighbor(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje if err := setBgpOptsBfd(setPrefix, d.Get("bfd_liveness_detection").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsFamily(setPrefix, inetWord, d.Get("family_inet").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, "evpn", d.Get("family_evpn").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsFamily(setPrefix, inet6Word, d.Get("family_inet6").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, inetWord, d.Get("family_inet").([]interface{}), m, jnprSess); err != nil { return err } - if err := setBgpOptsGrafefulRestart(setPrefix, d.Get("graceful_restart").([]interface{}), m, jnprSess); err != nil { + if err := setBgpOptsFamily(setPrefix, inet6Word, d.Get("family_inet6").([]interface{}), m, jnprSess); err != nil { return err } - return nil + return setBgpOptsGrafefulRestart(setPrefix, d.Get("graceful_restart").([]interface{}), m, jnprSess) } func readBgpNeighbor(ip, instance, group string, m interface{}, jnprSess *NetconfObject) (bgpOptions, error) { sess := m.(*Session) @@ -743,12 +852,16 @@ func readBgpNeighbor(ip, instance, group string, m interface{}, jnprSess *Netcon } itemTrim := strings.TrimPrefix(item, setLineStart) switch { + case strings.HasPrefix(itemTrim, "family evpn "): + confRead.familyEvpn, err = readBgpOptsFamily(itemTrim, "evpn", confRead.familyEvpn) + if err != nil { + return confRead, err + } case strings.HasPrefix(itemTrim, "family inet "): confRead.familyInet, err = readBgpOptsFamily(itemTrim, inetWord, confRead.familyInet) if err != nil { return confRead, err } - case strings.HasPrefix(itemTrim, "family inet6 "): confRead.familyInet6, err = readBgpOptsFamily(itemTrim, inet6Word, confRead.familyInet6) if err != nil { @@ -788,11 +901,8 @@ func delBgpNeighbor(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje " protocols bgp group "+d.Get("group").(string)+ " neighbor "+d.Get("ip").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillBgpNeighborData(d *schema.ResourceData, bgpNeighborOptions bgpOptions) { @@ -835,12 +945,18 @@ func fillBgpNeighborData(d *schema.ResourceData, bgpNeighborOptions bgpOptions) if tfErr := d.Set("bfd_liveness_detection", bgpNeighborOptions.bfdLivenessDetection); tfErr != nil { panic(tfErr) } + if tfErr := d.Set("cluster", bgpNeighborOptions.cluster); tfErr != nil { + panic(tfErr) + } if tfErr := d.Set("damping", bgpNeighborOptions.damping); tfErr != nil { panic(tfErr) } if tfErr := d.Set("export", bgpNeighborOptions.exportPolicy); tfErr != nil { panic(tfErr) } + if tfErr := d.Set("family_evpn", bgpNeighborOptions.familyEvpn); tfErr != nil { + panic(tfErr) + } if tfErr := d.Set("family_inet", bgpNeighborOptions.familyInet); tfErr != nil { panic(tfErr) } @@ -907,8 +1023,14 @@ func fillBgpNeighborData(d *schema.ResourceData, bgpNeighborOptions bgpOptions) if tfErr := d.Set("multihop", bgpNeighborOptions.multihop); tfErr != nil { panic(tfErr) } - if tfErr := d.Set("multipath", bgpNeighborOptions.multipath); tfErr != nil { - panic(tfErr) + if _, ok := d.GetOk("multipath"); ok { + if tfErr := d.Set("multipath", bgpNeighborOptions.multipath); tfErr != nil { + panic(tfErr) + } + } else { + if tfErr := d.Set("bgp_multipath", bgpNeighborOptions.bgpMultipath); tfErr != nil { + panic(tfErr) + } } if tfErr := d.Set("no_advertise_peer_as", bgpNeighborOptions.noAdvertisePeerAs); tfErr != nil { panic(tfErr) diff --git a/junos/resource_bgp_neighbor_test.go b/junos/resource_bgp_neighbor_test.go index ed140ce6..6e005173 100644 --- a/junos/resource_bgp_neighbor_test.go +++ b/junos/resource_bgp_neighbor_test.go @@ -29,6 +29,8 @@ func TestAccJunosBgpNeighbor_basic(t *testing.T) { "advertise_peer_as", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "as_override", "true"), + resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", + "cluster", "192.0.2.3"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "damping", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", @@ -36,7 +38,7 @@ func TestAccJunosBgpNeighbor_basic(t *testing.T) { resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "mtu_discovery", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", - "multipath", "true"), + "bgp_multipath.#", "1"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "remove_private", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", @@ -145,6 +147,10 @@ func TestAccJunosBgpNeighbor_basic(t *testing.T) { "group", "testacc_bgpneighbor"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "advertise_external_conditional", "true"), + resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", + "bgp_multipath.#", "1"), + resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", + "bgp_multipath.0.multiple_as", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", "no_advertise_peer_as", "true"), resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor", @@ -179,9 +185,9 @@ func TestAccJunosBgpNeighbor_basic(t *testing.T) { { Config: testAccJunosBgpNeighborConfigUpdate3(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor3", + resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor2", "local_as_alias", "true"), - resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor3", + resource.TestCheckResourceAttr("junos_bgp_neighbor.testacc_bgpneighbor2", "metric_out_minimum_igp", "true"), ), }, @@ -193,6 +199,9 @@ func TestAccJunosBgpNeighbor_basic(t *testing.T) { func testAccJunosBgpConfigPreCreate() string { return ` resource junos_routing_options "testacc_routing_options" { + autonomous_system { + number = "65001" + } graceful_restart {} } ` @@ -215,16 +224,17 @@ resource junos_bgp_group "testacc_bgpneighbor" { routing_instance = junos_routing_instance.testacc_bgpneighbor.name } resource junos_bgp_neighbor "testacc_bgpneighbor" { - ip = "192.0.2.4" - routing_instance = junos_routing_instance.testacc_bgpneighbor.name - group = junos_bgp_group.testacc_bgpneighbor.name - advertise_inactive = true - advertise_peer_as = true - as_override = true + ip = "192.0.2.4" + routing_instance = junos_routing_instance.testacc_bgpneighbor.name + group = junos_bgp_group.testacc_bgpneighbor.name + advertise_inactive = true + advertise_peer_as = true + as_override = true + bgp_multipath {} + cluster = "192.0.2.3" damping = true log_updown = true mtu_discovery = true - multipath = true remove_private = true passive = true hold_time = 30 @@ -322,6 +332,9 @@ resource junos_bgp_neighbor "testacc_bgpneighbor" { metric_out_igp_offset = -10 metric_out_igp_delay_med_update = true authentication_key = "password" + bgp_multipath { + multiple_as = true + } graceful_restart { restart_time = 10 stale_route_time = 10 @@ -352,26 +365,55 @@ resource junos_bgp_neighbor "testacc_bgpneighbor2" { local_as_no_prepend_global_as = true metric_out_minimum_igp_offset = -10 } +resource junos_bgp_group "testacc_bgpneighbor2b" { + name = "testacc_bgpneighbor2b" + type = "internal" +} +resource junos_bgp_neighbor "testacc_bgpneighbor2b" { + ip = "192.0.2.5" + group = junos_bgp_group.testacc_bgpneighbor2b.name + family_evpn { + accepted_prefix_limit { + maximum = 2 + teardown = 50 + teardown_idle_timeout = 30 + } + prefix_limit { + maximum = 2 + teardown = 50 + teardown_idle_timeout = 30 + } + } +} ` } func testAccJunosBgpNeighborConfigUpdate3() string { return ` -resource junos_routing_instance "testacc_bgpneighbor3" { - name = "testacc_bgpneighbor3" +resource junos_routing_instance "testacc_bgpneighbor2" { + name = "testacc_bgpneighbor2" as = "65000" } -resource junos_bgp_group "testacc_bgpneighbor3" { - name = "testacc_bgpneighbor3" - routing_instance = junos_routing_instance.testacc_bgpneighbor3.name +resource junos_bgp_group "testacc_bgpneighbor2" { + name = "testacc_bgpneighbor2" + routing_instance = junos_routing_instance.testacc_bgpneighbor2.name type = "internal" } -resource junos_bgp_neighbor "testacc_bgpneighbor3" { +resource junos_bgp_neighbor "testacc_bgpneighbor2" { ip = "192.0.2.4" - routing_instance = junos_routing_instance.testacc_bgpneighbor3.name - group = junos_bgp_group.testacc_bgpneighbor3.name + routing_instance = junos_routing_instance.testacc_bgpneighbor2.name + group = junos_bgp_group.testacc_bgpneighbor2.name local_as = "65000" local_as_alias = true metric_out_minimum_igp = true } +resource junos_bgp_group "testacc_bgpneighbor2b" { + name = "testacc_bgpneighbor2b" + type = "internal" +} +resource junos_bgp_neighbor "testacc_bgpneighbor2b" { + ip = "192.0.2.5" + group = junos_bgp_group.testacc_bgpneighbor2b.name + family_evpn {} +} ` } diff --git a/junos/resource_chassis_cluster.go b/junos/resource_chassis_cluster.go new file mode 100644 index 00000000..e9170019 --- /dev/null +++ b/junos/resource_chassis_cluster.go @@ -0,0 +1,581 @@ +package junos + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +type chassisClusterOptions struct { + configSyncNoSecBootAuto bool + controlLinkRecovery bool + heartbeatInterval int + heartbeatThreshold int + rethCount int + redundancyGroup []map[string]interface{} + fab0 []map[string]interface{} + fab1 []map[string]interface{} +} + +func resourceChassisCluster() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceChassisClusterCreate, + ReadContext: resourceChassisClusterRead, + UpdateContext: resourceChassisClusterUpdate, + DeleteContext: resourceChassisClusterDelete, + Importer: &schema.ResourceImporter{ + State: resourceChassisClusterImport, + }, + Schema: map[string]*schema.Schema{ + "fab0": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "member_interfaces": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "fab1": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "member_interfaces": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "redundancy_group": { + Type: schema.TypeList, + Required: true, + MaxItems: 128, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node0_priority": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 254), + }, + "node1_priority": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 254), + }, + "gratuitous_arp_count": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 16), + }, + "hold_down_interval": { + Type: schema.TypeInt, + Optional: true, + Default: -1, + ValidateFunc: validation.IntBetween(0, 1800), + }, + "interface_monitor": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 255), + }, + }, + }, + }, + "preempt": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "reth_count": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 128), + }, + "config_sync_no_secondary_bootup_auto": { + Type: schema.TypeBool, + Optional: true, + }, + "control_link_recovery": { + Type: schema.TypeBool, + Optional: true, + }, + "heartbeat_interval": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1000, 2000), + }, + "heartbeat_threshold": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(3, 8), + }, + }, + } +} + +func checkCompatibilityChassisCluster(jnprSess *NetconfObject) bool { + if strings.HasPrefix(strings.ToLower(jnprSess.SystemInformation.HardwareModel), "srx") { + return true + } + if strings.HasPrefix(strings.ToLower(jnprSess.SystemInformation.HardwareModel), "vsrx") { + return true + } + if strings.HasPrefix(strings.ToLower(jnprSess.SystemInformation.HardwareModel), "j") { + return true + } + + return false +} + +func resourceChassisClusterCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setChassisCluster(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("cluster") + + return nil + } + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + if !checkCompatibilityChassisCluster(jnprSess) { + return diag.FromErr(fmt.Errorf("chassis cluster "+ + "not compatible with Junos device %s", jnprSess.SystemInformation.HardwareModel)) + } + sess.configLock(jnprSess) + if err := setChassisCluster(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("create resource junos_chassis_cluster", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.SetId("cluster") + + return append(diagWarns, resourceChassisClusterReadWJnprSess(d, m, jnprSess)...) +} +func resourceChassisClusterRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + + return resourceChassisClusterReadWJnprSess(d, m, jnprSess) +} +func resourceChassisClusterReadWJnprSess( + d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) diag.Diagnostics { + mutex.Lock() + clusterOptions, err := readChassisCluster(m, jnprSess) + mutex.Unlock() + if err != nil { + return diag.FromErr(err) + } + fillChassisCluster(d, clusterOptions) + + return nil +} +func resourceChassisClusterUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + d.Partial(true) + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delChassisCluster(m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if err := setChassisCluster(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("update resource junos_chassis_cluster", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.Partial(false) + + return append(diagWarns, resourceChassisClusterReadWJnprSess(d, m, jnprSess)...) +} +func resourceChassisClusterDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delChassisCluster(m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("delete resource junos_chassis_cluster", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + + return diagWarns +} +func resourceChassisClusterImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return nil, err + } + defer sess.closeSession(jnprSess) + result := make([]*schema.ResourceData, 1) + clusterOptions, err := readChassisCluster(m, jnprSess) + if err != nil { + return nil, err + } + fillChassisCluster(d, clusterOptions) + d.SetId("cluster") + result[0] = d + + return result, nil +} + +func setChassisCluster(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + + setIntPrefix := "set interfaces " + for _, v := range d.Get("fab0").([]interface{}) { + configSet = append(configSet, "delete interfaces fab0 disable") + fab0 := v.(map[string]interface{}) + for _, v2 := range fab0["member_interfaces"].([]interface{}) { + configSet = append(configSet, setIntPrefix+ + "fab0 fabric-options member-interfaces "+v2.(string)) + } + if fab0["description"].(string) != "" { + configSet = append(configSet, setIntPrefix+"fab0 description \""+ + fab0["description"].(string)+"\"") + } + } + for _, v := range d.Get("fab1").([]interface{}) { + configSet = append(configSet, "delete interfaces fab1 disable") + fab0 := v.(map[string]interface{}) + for _, v2 := range fab0["member_interfaces"].([]interface{}) { + configSet = append(configSet, setIntPrefix+ + "fab1 fabric-options member-interfaces "+v2.(string)) + } + if fab0["description"].(string) != "" { + configSet = append(configSet, setIntPrefix+"fab1 description \""+ + fab0["description"].(string)+"\"") + } + } + + setChassisluster := "set chassis cluster " + for i, v := range d.Get("redundancy_group").([]interface{}) { + redundancyGroup := v.(map[string]interface{}) + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " node 0 priority "+strconv.Itoa(redundancyGroup["node0_priority"].(int))) + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " node 1 priority "+strconv.Itoa(redundancyGroup["node1_priority"].(int))) + if redundancyGroup["gratuitous_arp_count"].(int) != 0 { + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " gratuitous-arp-count "+strconv.Itoa(redundancyGroup["gratuitous_arp_count"].(int))) + } + if redundancyGroup["hold_down_interval"].(int) != -1 { + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " hold-down-interval "+strconv.Itoa(redundancyGroup["hold_down_interval"].(int))) + } + for _, v2 := range redundancyGroup["interface_monitor"].([]interface{}) { + interfaceMonitor := v2.(map[string]interface{}) + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " interface-monitor "+interfaceMonitor["name"].(string)+ + " weight "+strconv.Itoa(interfaceMonitor["weight"].(int))) + } + if redundancyGroup["preempt"].(bool) { + configSet = append(configSet, setChassisluster+"redundancy-group "+strconv.Itoa(i)+ + " preempt") + } + } + configSet = append(configSet, setChassisluster+"reth-count "+ + strconv.Itoa(d.Get("reth_count").(int))) + if d.Get("config_sync_no_secondary_bootup_auto").(bool) { + configSet = append(configSet, setChassisluster+"configuration-synchronize no-secondary-bootup-auto") + } + if d.Get("control_link_recovery").(bool) { + configSet = append(configSet, setChassisluster+"control-link-recovery") + } + if v := d.Get("heartbeat_interval").(int); v != 0 { + configSet = append(configSet, setChassisluster+"heartbeat-interval "+ + strconv.Itoa(v)) + } + if v := d.Get("heartbeat_threshold").(int); v != 0 { + configSet = append(configSet, setChassisluster+"heartbeat-threshold "+ + strconv.Itoa(v)) + } + + return sess.configSet(configSet, jnprSess) +} + +func delChassisCluster(m interface{}, jnprSess *NetconfObject) error { + listLinesToDelete := make([]string, 0) + listLinesToDelete = append(listLinesToDelete, "chassis cluster") + listLinesToDelete = append(listLinesToDelete, "interfaces fab0") + listLinesToDelete = append(listLinesToDelete, "interfaces fab1") + sess := m.(*Session) + configSet := make([]string, 0) + for _, line := range listLinesToDelete { + configSet = append(configSet, + "delete "+line) + } + + return sess.configSet(configSet, jnprSess) +} + +func readChassisCluster(m interface{}, jnprSess *NetconfObject) (chassisClusterOptions, error) { + sess := m.(*Session) + var confRead chassisClusterOptions + + chassisClusterConfig, err := sess.command("show configuration chassis cluster"+ + " | display set relative", jnprSess) + if err != nil { + return confRead, err + } + if chassisClusterConfig != emptyWord { + for _, item := range strings.Split(chassisClusterConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "redundancy-group "): + itemRGTrim := strings.TrimPrefix(itemTrim, "redundancy-group ") + itemRGTrimSplit := strings.Split(itemRGTrim, " ") + number, err := strconv.Atoi(itemRGTrimSplit[0]) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGTrimSplit[0], err) + } + if len(confRead.redundancyGroup) < number+1 { + confRead.redundancyGroup = append(confRead.redundancyGroup, map[string]interface{}{ + "node0_priority": 0, + "node1_priority": 0, + "gratuitous_arp_count": 0, + "hold_down_interval": -1, + "interface_monitor": make([]map[string]interface{}, 0), + "preempt": false, + }) + } + itemRGNbTrim := strings.TrimPrefix(itemRGTrim, strconv.Itoa(number)+" ") + switch { + case strings.HasPrefix(itemRGNbTrim, "node 0 priority "): + var err error + confRead.redundancyGroup[number]["node0_priority"], err = + strconv.Atoi(strings.TrimPrefix(itemRGNbTrim, "node 0 priority ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGNbTrim, err) + } + case strings.HasPrefix(itemRGNbTrim, "node 1 priority "): + var err error + confRead.redundancyGroup[number]["node1_priority"], err = + strconv.Atoi(strings.TrimPrefix(itemRGNbTrim, "node 1 priority ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGNbTrim, err) + } + case strings.HasPrefix(itemRGNbTrim, "gratuitous-arp-count "): + var err error + confRead.redundancyGroup[number]["gratuitous_arp_count"], err = + strconv.Atoi(strings.TrimPrefix(itemRGNbTrim, "gratuitous-arp-count ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGNbTrim, err) + } + case strings.HasPrefix(itemRGNbTrim, "hold-down-interval "): + var err error + confRead.redundancyGroup[number]["hold_down_interval"], err = + strconv.Atoi(strings.TrimPrefix(itemRGNbTrim, "hold-down-interval ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGNbTrim, err) + } + case strings.HasPrefix(itemRGNbTrim, "interface-monitor "): + name := strings.Split(strings.TrimPrefix(itemRGNbTrim, "interface-monitor "), " ")[0] + weight, err := strconv.Atoi(strings.TrimPrefix(itemRGNbTrim, "interface-monitor "+name+" weight ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemRGNbTrim, err) + } + confRead.redundancyGroup[number]["interface_monitor"] = append( + confRead.redundancyGroup[number]["interface_monitor"].([]map[string]interface{}), + map[string]interface{}{ + "name": name, + "weight": weight, + }) + case itemRGNbTrim == preemptWord: + confRead.redundancyGroup[number][preemptWord] = true + } + case strings.HasPrefix(itemTrim, "reth-count "): + var err error + confRead.rethCount, err = strconv.Atoi(strings.TrimPrefix(itemTrim, "reth-count ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case itemTrim == "configuration-synchronize no-secondary-bootup-auto": + confRead.configSyncNoSecBootAuto = true + case itemTrim == "control-link-recovery": + confRead.controlLinkRecovery = true + case strings.HasPrefix(itemTrim, "heartbeat-interval "): + var err error + confRead.heartbeatInterval, err = strconv.Atoi(strings.TrimPrefix(itemTrim, "heartbeat-interval ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrim, "heartbeat-threshold "): + var err error + confRead.heartbeatThreshold, err = strconv.Atoi(strings.TrimPrefix(itemTrim, "heartbeat-threshold ")) + if err != nil { + return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + } + } + } + fab0Config, err := sess.command("show configuration interfaces fab0"+ + " | display set relative", jnprSess) + if err != nil { + return confRead, err + } + if fab0Config != emptyWord { + if len(confRead.fab0) == 0 { + confRead.fab0 = append(confRead.fab0, map[string]interface{}{ + "member_interfaces": make([]string, 0), + "description": "", + }) + } + for _, item := range strings.Split(fab0Config, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "description "): + confRead.fab0[0]["description"] = strings.Trim(strings.TrimPrefix(itemTrim, "description "), "\"") + case strings.HasPrefix(itemTrim, "fabric-options member-interfaces "): + confRead.fab0[0]["member_interfaces"] = append(confRead.fab0[0]["member_interfaces"].([]string), + strings.TrimPrefix(itemTrim, "fabric-options member-interfaces ")) + } + } + } + fab1Config, err := sess.command("show configuration interfaces fab1"+ + " | display set relative", jnprSess) + if err != nil { + return confRead, err + } + if fab1Config != emptyWord { + if len(confRead.fab1) == 0 { + confRead.fab1 = append(confRead.fab1, map[string]interface{}{ + "member_interfaces": make([]string, 0), + "description": "", + }) + } + for _, item := range strings.Split(fab1Config, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "description "): + confRead.fab1[0]["description"] = strings.Trim(strings.TrimPrefix(itemTrim, "description "), "\"") + case strings.HasPrefix(itemTrim, "fabric-options member-interfaces "): + confRead.fab1[0]["member_interfaces"] = append(confRead.fab1[0]["member_interfaces"].([]string), + strings.TrimPrefix(itemTrim, "fabric-options member-interfaces ")) + } + } + } + + return confRead, nil +} + +func fillChassisCluster(d *schema.ResourceData, chassisClusterOptions chassisClusterOptions) { + if tfErr := d.Set("fab0", chassisClusterOptions.fab0); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("fab1", chassisClusterOptions.fab1); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("redundancy_group", chassisClusterOptions.redundancyGroup); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("reth_count", chassisClusterOptions.rethCount); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("config_sync_no_secondary_bootup_auto", + chassisClusterOptions.configSyncNoSecBootAuto); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("control_link_recovery", chassisClusterOptions.controlLinkRecovery); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("heartbeat_interval", chassisClusterOptions.heartbeatInterval); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("heartbeat_threshold", chassisClusterOptions.heartbeatThreshold); tfErr != nil { + panic(tfErr) + } +} diff --git a/junos/resource_chassis_cluster_test.go b/junos/resource_chassis_cluster_test.go new file mode 100644 index 00000000..83a8ef60 --- /dev/null +++ b/junos/resource_chassis_cluster_test.go @@ -0,0 +1,130 @@ +package junos_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// export TESTACC_INTERFACE= for choose interface available else it's ge-0/0/3. +// export TESTACC_INTERFACE2= for choose 2nd interface available else it's ge-0/0/4. +func TestAccJunosCluster_basic(t *testing.T) { + var testaccInterface string + var testaccInterface2 string + if os.Getenv("TESTACC_INTERFACE") != "" { + testaccInterface = os.Getenv("TESTACC_INTERFACE") + } else { + testaccInterface = defaultInterfaceTestAcc + } + if os.Getenv("TESTACC_INTERFACE2") != "" { + testaccInterface2 = os.Getenv("TESTACC_INTERFACE2") + } else { + testaccInterface2 = "ge-0/0/4" + } + if os.Getenv("TESTACC_SWITCH") == "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosClusterConfigCreate(testaccInterface, testaccInterface2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "fab0.#", "1"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "fab0.0.member_interfaces.#", "1"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "fab0.0.member_interfaces.0", testaccInterface), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.#", "2"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.0.node0_priority", "100"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.1.interface_monitor.#", "1"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.1.interface_monitor.0.name", testaccInterface2), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "reth_count", "2"), + ), + }, + { + Config: testAccJunosClusterConfigUpdate(testaccInterface, testaccInterface2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.#", "2"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "redundancy_group.1.node0_priority", "100"), + resource.TestCheckResourceAttr("junos_chassis_cluster.testacc_cluster", + "reth_count", "3"), + ), + }, + { + ResourceName: "junos_chassis_cluster.testacc_cluster", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + } +} + +func testAccJunosClusterConfigCreate(interFace, interFace2 string) string { + return fmt.Sprintf(` +resource "junos_interface_physical" "testacc_cluster_int2" { + name = "` + interFace2 + `" + description = "testacc_cluster_int2" + gigether_opts { + redundant_parent = "reth0" + } +} +resource "junos_chassis_cluster" "testacc_cluster" { + fab0 { + member_interfaces = ["` + interFace + `"] + } + redundancy_group { + node0_priority = 100 + node1_priority = 99 + } + redundancy_group { + node0_priority = 98 + node1_priority = 97 + interface_monitor { + name = junos_interface_physical.testacc_cluster_int2.name + weight = 255 + } + } + reth_count = 2 +} +`) +} +func testAccJunosClusterConfigUpdate(interFace, interFace2 string) string { + return fmt.Sprintf(` +resource "junos_interface_physical" "testacc_cluster_int2" { + name = "` + interFace2 + `" + description = "testacc_cluster_int2" + gigether_opts { + redundant_parent = "reth0" + } +} +resource "junos_chassis_cluster" "testacc_cluster" { + fab0 { + member_interfaces = ["` + interFace + `"] + } + redundancy_group { + node0_priority = 100 + node1_priority = 99 + } + redundancy_group { + node0_priority = 100 + node1_priority = 99 + interface_monitor { + name = junos_interface_physical.testacc_cluster_int2.name + weight = 255 + } + } + reth_count = 3 +} +`) +} diff --git a/junos/resource_firewall_filter.go b/junos/resource_firewall_filter.go index d851080c..56009688 100644 --- a/junos/resource_firewall_filter.go +++ b/junos/resource_firewall_filter.go @@ -31,7 +31,7 @@ func resourceFirewallFilter() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "family": { Type: schema.TypeString, @@ -52,12 +52,12 @@ func resourceFirewallFilter() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "filter": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "from": { Type: schema.TypeList, @@ -236,7 +236,7 @@ func resourceFirewallFilter() *schema.Resource { "policer": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "port_mirror": { Type: schema.TypeBool, @@ -270,6 +270,14 @@ func resourceFirewallFilter() *schema.Resource { func resourceFirewallFilterCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setFirewallFilter(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string) + idSeparator + d.Get("family").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -465,11 +473,7 @@ func setFirewallFilter(d *schema.ResourceData, m interface{}, jnprSess *NetconfO } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readFirewallFilter(filter, family string, m interface{}, jnprSess *NetconfObject) (filterOptions, error) { sess := m.(*Session) @@ -528,11 +532,8 @@ func delFirewallFilter(filter, family string, m interface{}, jnprSess *NetconfOb sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete firewall family "+family+" filter "+filter) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillFirewallFilterData(d *schema.ResourceData, filterOptions filterOptions) { if tfErr := d.Set("name", filterOptions.name); tfErr != nil { diff --git a/junos/resource_firewall_policer.go b/junos/resource_firewall_policer.go index b68f6ff4..11e6c11d 100644 --- a/junos/resource_firewall_policer.go +++ b/junos/resource_firewall_policer.go @@ -32,7 +32,7 @@ func resourceFirewallPolicer() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "filter_specific": { Type: schema.TypeBool, @@ -97,6 +97,14 @@ func resourceFirewallPolicer() *schema.Resource { func resourceFirewallPolicerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setFirewallPolicer(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -304,11 +312,7 @@ func setFirewallPolicer(d *schema.ResourceData, m interface{}, jnprSess *Netconf } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readFirewallPolicer(policer string, m interface{}, jnprSess *NetconfObject) (policerOptions, error) { sess := m.(*Session) @@ -390,11 +394,8 @@ func delFirewallPolicer(policer string, m interface{}, jnprSess *NetconfObject) sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete firewall policer "+policer) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillFirewallPolicerData(d *schema.ResourceData, policerOptions policerOptions) { if tfErr := d.Set("name", policerOptions.name); tfErr != nil { diff --git a/junos/resource_group_dual_system.go b/junos/resource_group_dual_system.go new file mode 100644 index 00000000..5552168c --- /dev/null +++ b/junos/resource_group_dual_system.go @@ -0,0 +1,549 @@ +package junos + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +type groupDualSystemOptions struct { + applyGroups bool + name string + interfaceFxp0 []map[string]interface{} + routingOptions []map[string]interface{} + security []map[string]interface{} + system []map[string]interface{} +} + +func resourceGroupDualSystem() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceGroupDualSystemCreate, + ReadContext: resourceGroupDualSystemRead, + UpdateContext: resourceGroupDualSystemUpdate, + DeleteContext: resourceGroupDualSystemDelete, + Importer: &schema.ResourceImporter{ + State: resourceGroupDualSystemImport, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"node0", "node1", "re0", "re1"}, false), + }, + "apply_groups": { + Type: schema.TypeBool, + Default: true, + Optional: true, + }, + "interface_fxp0": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + }, + "family_inet_address": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cidr_ip": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateIPMaskFunc(), + }, + "master_only": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "routing_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "static_route": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "destination": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsCIDRNetwork(0, 128), + }, + "next_hop": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "security": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "log_source_address": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "system": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_name": { + Type: schema.TypeString, + Optional: true, + }, + "backup_router_address": { + Type: schema.TypeString, + Optional: true, + }, + "backup_router_destination": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + } +} + +func resourceGroupDualSystemCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setGroupDualSystem(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + groupDualSystemExists, err := checkGroupDualSystemExists(d.Get("name").(string), m, jnprSess) + if err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if groupDualSystemExists { + sess.configClear(jnprSess) + + return diag.FromErr(fmt.Errorf("group %v already exists", d.Get("name").(string))) + } + + if err := setGroupDualSystem(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("create resource junos_group_dual_system", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + groupDualSystemExists, err = checkGroupDualSystemExists(d.Get("name").(string), m, jnprSess) + if err != nil { + return append(diagWarns, diag.FromErr(err)...) + } + if groupDualSystemExists { + d.SetId(d.Get("name").(string)) + } else { + return append(diagWarns, diag.FromErr(fmt.Errorf("group %v not exists after commit "+ + "=> check your config", d.Get("name").(string)))...) + } + + return append(diagWarns, resourceGroupDualSystemReadWJnprSess(d, m, jnprSess)...) +} +func resourceGroupDualSystemRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + + return resourceGroupDualSystemReadWJnprSess(d, m, jnprSess) +} +func resourceGroupDualSystemReadWJnprSess( + d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) diag.Diagnostics { + mutex.Lock() + groupDualSystemOpts, err := readGroupDualSystem(d.Get("name").(string), m, jnprSess) + mutex.Unlock() + if err != nil { + return diag.FromErr(err) + } + if groupDualSystemOpts.name == "" { + d.SetId("") + } else { + fillGroupDualSystemData(d, groupDualSystemOpts) + } + + return nil +} +func resourceGroupDualSystemUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + d.Partial(true) + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delGroupDualSystem(d.Get("name").(string), m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if strings.HasPrefix(d.Get("name").(string), "node") { + if err := sess.configSet([]string{"delete apply-groups \"${node}\""}, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + } else if err := sess.configSet([]string{"delete apply-groups " + d.Get("name").(string)}, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if err := setGroupDualSystem(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("update resource junos_group_dual_system", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.Partial(false) + + return append(diagWarns, resourceGroupDualSystemReadWJnprSess(d, m, jnprSess)...) +} +func resourceGroupDualSystemDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delGroupDualSystem(d.Get("name").(string), m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if strings.HasPrefix(d.Get("name").(string), "node") { + if err := sess.configSet([]string{"delete apply-groups \"${node}\""}, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + } else if err := sess.configSet([]string{"delete apply-groups " + d.Get("name").(string)}, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("delete resource junos_group_dual_system", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + + return diagWarns +} +func resourceGroupDualSystemImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return nil, err + } + defer sess.closeSession(jnprSess) + result := make([]*schema.ResourceData, 1) + + if !stringInSlice(d.Id(), []string{"node0", "node1", "re0", "re1"}) { + return nil, fmt.Errorf("invalid group id '%v' (id must be )", d.Id()) + } + groupDualSystemExists, err := checkGroupDualSystemExists(d.Id(), m, jnprSess) + if err != nil { + return nil, err + } + if !groupDualSystemExists { + return nil, fmt.Errorf("don't find group with id '%v' (id must be )", d.Id()) + } + groupDualSystemOptions, err := readGroupDualSystem(d.Id(), m, jnprSess) + if err != nil { + return nil, err + } + fillGroupDualSystemData(d, groupDualSystemOptions) + + result[0] = d + + return result, nil +} + +func checkGroupDualSystemExists(name string, m interface{}, jnprSess *NetconfObject) (bool, error) { + sess := m.(*Session) + groupDualSystemConfig, err := sess.command("show configuration groups "+name+" | display set", jnprSess) + if err != nil { + return false, err + } + if groupDualSystemConfig == emptyWord { + return false, nil + } + + return true, nil +} +func setGroupDualSystem(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + + if d.Get("apply_groups").(bool) { + if strings.HasPrefix(d.Get("name").(string), "node") { + configSet = append(configSet, "set apply-groups \"${node}\"") + } else { + configSet = append(configSet, "set apply-groups "+d.Get("name").(string)) + } + } + setPrefix := "set groups " + d.Get("name").(string) + " " + for _, v := range d.Get("interface_fxp0").([]interface{}) { + if v == nil { + return fmt.Errorf("interface_fxp0 block is empty") + } + interfaceFxp0 := v.(map[string]interface{}) + if v2 := interfaceFxp0["description"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"interfaces fxp0 description \""+v2+"\"") + } + for _, v2 := range interfaceFxp0["family_inet_address"].([]interface{}) { + familyInetAddress := v2.(map[string]interface{}) + configSet = append(configSet, setPrefix+"interfaces fxp0 unit 0 family inet address "+ + familyInetAddress["cidr_ip"].(string)) + if familyInetAddress["master_only"].(bool) { + configSet = append(configSet, setPrefix+"interfaces fxp0 unit 0 family inet address "+ + familyInetAddress["cidr_ip"].(string)+" master-only") + } + } + } + for _, v := range d.Get("routing_options").([]interface{}) { + routingOptions := v.(map[string]interface{}) + for _, v2 := range routingOptions["static_route"].([]interface{}) { + staticRoute := v2.(map[string]interface{}) + for _, v3 := range staticRoute["next_hop"].([]interface{}) { + configSet = append(configSet, setPrefix+"routing-options static route "+ + staticRoute["destination"].(string)+" next-hop "+v3.(string)) + } + } + } + for _, v := range d.Get("security").([]interface{}) { + security := v.(map[string]interface{}) + if v2 := security["log_source_address"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"security log source-address "+v2) + } + } + for _, v := range d.Get("system").([]interface{}) { + if v == nil { + return fmt.Errorf("system block is empty") + } + system := v.(map[string]interface{}) + if v2 := system["host_name"].(string); v2 != "" { + configSet = append(configSet, setPrefix+" system host-name \""+v2+"\"") + } + if v2 := system["backup_router_address"].(string); v2 != "" { + configSet = append(configSet, setPrefix+" system backup-router "+v2) + } + for _, v2 := range system["backup_router_destination"].([]interface{}) { + configSet = append(configSet, setPrefix+" system backup-router destination "+v2.(string)) + } + } + + return sess.configSet(configSet, jnprSess) +} +func readGroupDualSystem(group string, m interface{}, jnprSess *NetconfObject) (groupDualSystemOptions, error) { + sess := m.(*Session) + var confRead groupDualSystemOptions + + groupDualSystemConfig, err := sess.command("show configuration groups "+group+" | display set relative", jnprSess) + if err != nil { + return confRead, err + } + if groupDualSystemConfig != emptyWord { + confRead.name = group + for _, item := range strings.Split(groupDualSystemConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "interfaces fxp0 "): + if len(confRead.interfaceFxp0) == 0 { + confRead.interfaceFxp0 = append(confRead.interfaceFxp0, map[string]interface{}{ + "description": "", + "family_inet_address": make([]map[string]interface{}, 0), + }) + } + switch { + case strings.HasPrefix(itemTrim, "interfaces fxp0 description "): + confRead.interfaceFxp0[0]["description"] = strings.TrimPrefix(itemTrim, "interfaces fxp0 description ") + case strings.HasPrefix(itemTrim, "interfaces fxp0 unit 0 family inet address "): + if strings.HasSuffix(itemTrim, "master-only") { + confRead.interfaceFxp0[0]["family_inet_address"] = append( + confRead.interfaceFxp0[0]["family_inet_address"].([]map[string]interface{}), map[string]interface{}{ + "cidr_ip": strings.TrimSuffix(strings.TrimPrefix( + itemTrim, "interfaces fxp0 unit 0 family inet address "), " master-only"), + "master_only": true, + }) + } else { + confRead.interfaceFxp0[0]["family_inet_address"] = append( + confRead.interfaceFxp0[0]["family_inet_address"].([]map[string]interface{}), map[string]interface{}{ + "cidr_ip": strings.TrimPrefix(itemTrim, "interfaces fxp0 unit 0 family inet address "), + "master_only": false, + }) + } + } + case strings.HasPrefix(itemTrim, "routing-options static route "): + if len(confRead.routingOptions) == 0 { + confRead.routingOptions = append(confRead.routingOptions, map[string]interface{}{ + "static_route": make([]map[string]interface{}, 0), + }) + } + routeTrim := strings.TrimPrefix(itemTrim, "routing-options static route ") + routeTrimSplit := strings.Split(routeTrim, " ") + destOptions := map[string]interface{}{ + "destination": routeTrimSplit[0], + "next_hop": make([]string, 0), + } + destOptions, confRead.routingOptions[0]["static_route"] = copyAndRemoveItemMapList( + "destination", false, destOptions, confRead.routingOptions[0]["static_route"].([]map[string]interface{})) + if strings.HasPrefix(routeTrim, routeTrimSplit[0]+" next-hop ") { + destOptions["next_hop"] = append(destOptions["next_hop"].([]string), + strings.TrimPrefix(routeTrim, routeTrimSplit[0]+" next-hop ")) + } + confRead.routingOptions[0]["static_route"] = append( + confRead.routingOptions[0]["static_route"].([]map[string]interface{}), destOptions) + case strings.HasPrefix(itemTrim, "security"): + if len(confRead.security) == 0 { + confRead.security = append(confRead.security, map[string]interface{}{ + "log_source_address": "", + }) + } + if strings.HasPrefix(itemTrim, "security log source-address ") { + confRead.security[0]["log_source_address"] = strings.TrimPrefix( + itemTrim, "security log source-address ") + } + case strings.HasPrefix(itemTrim, "system"): + if len(confRead.system) == 0 { + confRead.system = append(confRead.system, map[string]interface{}{ + "host_name": "", + "backup_router_address": "", + "backup_router_destination": make([]string, 0), + }) + } + switch { + case strings.HasPrefix(itemTrim, "system host-name "): + confRead.system[0]["host_name"] = strings.Trim(strings.TrimPrefix(itemTrim, "system host-name "), "\"") + case strings.HasPrefix(itemTrim, "system backup-router destination "): + confRead.system[0]["backup_router_destination"] = append( + confRead.system[0]["backup_router_destination"].([]string), + strings.TrimPrefix(itemTrim, "system backup-router destination ")) + case strings.HasPrefix(itemTrim, "system backup-router "): + confRead.system[0]["backup_router_address"] = strings.TrimPrefix(itemTrim, "system backup-router ") + } + } + } + } + applyGroupsConfig, err := sess.command("show configuration apply-groups | display set relative", jnprSess) + if err != nil { + return confRead, err + } + if applyGroupsConfig != emptyWord { + confRead.name = group + for _, item := range strings.Split(applyGroupsConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + switch { + case item == "set "+confRead.name+" ": + confRead.applyGroups = true + case item == "set \"${node}\" " && strings.HasPrefix(confRead.name, "node"): + confRead.applyGroups = true + } + } + } + + return confRead, nil +} + +func delGroupDualSystem(group string, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0, 1) + configSet = append(configSet, "delete groups "+group) + + return sess.configSet(configSet, jnprSess) +} +func fillGroupDualSystemData(d *schema.ResourceData, groupDualSystemOptions groupDualSystemOptions) { + if tfErr := d.Set("name", groupDualSystemOptions.name); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("apply_groups", groupDualSystemOptions.applyGroups); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("interface_fxp0", groupDualSystemOptions.interfaceFxp0); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("routing_options", groupDualSystemOptions.routingOptions); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("security", groupDualSystemOptions.security); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("system", groupDualSystemOptions.system); tfErr != nil { + panic(tfErr) + } +} diff --git a/junos/resource_group_dual_system_test.go b/junos/resource_group_dual_system_test.go new file mode 100644 index 00000000..3ab436f5 --- /dev/null +++ b/junos/resource_group_dual_system_test.go @@ -0,0 +1,118 @@ +package junos_test + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccJunosGroupDualSystem_basic(t *testing.T) { + if os.Getenv("TESTACC_SRX") != "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosGroupDualSystemConfigCreate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "apply_groups", "true"), + ), + }, + { + Config: testAccJunosGroupDualSystemConfigUpdate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "interface_fxp0.#", "1"), + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "interface_fxp0.0.family_inet_address.#", "2"), + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "system.#", "1"), + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "system.0.backup_router_destination.#", "2"), + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "system.#", "1"), + resource.TestCheckResourceAttr("junos_group_dual_system.testacc_node0", + "system.0.backup_router_destination.1", "192.0.2.0/26"), + ), + }, + { + ResourceName: "junos_group_dual_system.testacc_node0", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + } +} + +func testAccJunosGroupDualSystemConfigCreate() string { + return ` +resource "junos_group_dual_system" "testacc_node0" { + name = "node0" + interface_fxp0 { + description = "test_" + family_inet_address { + cidr_ip = "192.0.2.193/26" + } + } + routing_options { + static_route { + destination = "192.0.2.0/26" + next_hop = ["192.0.2.254"] + } + static_route { + destination = "192.0.2.64/26" + next_hop = ["192.0.2.254"] + } + } + security { + log_source_address = "192.0.2.128" + } + system { + host_name = "test_node" + backup_router_address = "192.0.2.254" + backup_router_destination = [ + "192.0.2.0/26", + ] + } +} +` +} +func testAccJunosGroupDualSystemConfigUpdate() string { + return ` +resource "junos_group_dual_system" "testacc_node0" { + name = "node0" + apply_groups = false + interface_fxp0 { + description = "test_" + family_inet_address { + cidr_ip = "192.0.2.193/26" + } + family_inet_address { + cidr_ip = "192.0.2.194/26" + master_only = true + } + } + routing_options { + static_route { + destination = "192.0.2.0/26" + next_hop = ["192.0.2.254"] + } + } + security { + log_source_address = "192.0.2.128" + } + system { + host_name = "test_node" + backup_router_address = "192.0.2.254" + backup_router_destination = [ + "192.0.2.64/26", + "192.0.2.0/26", + + ] + } +} +` +} diff --git a/junos/resource_interface.go b/junos/resource_interface.go index 54095732..5964f4d1 100644 --- a/junos/resource_interface.go +++ b/junos/resource_interface.go @@ -322,22 +322,22 @@ func resourceInterface() *schema.Resource { "inet_filter_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "inet_filter_output": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "inet6_filter_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "inet6_filter_output": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "inet_rpf_check": { Type: schema.TypeList, @@ -418,12 +418,12 @@ func resourceInterface() *schema.Resource { "security_zone": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, } @@ -431,6 +431,26 @@ func resourceInterface() *schema.Resource { func resourceInterfaceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if sess.junosGroupIntDel != "" { + if err := delInterfaceElement("apply-groups "+sess.junosGroupIntDel, d, m, nil); err != nil { + return diag.FromErr(err) + } + } else { + if err := delInterfaceElement("disable", d, m, nil); err != nil { + return diag.FromErr(err) + } + if err := delInterfaceElement("description", d, m, nil); err != nil { + return diag.FromErr(err) + } + } + if err := setInterface(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -1025,12 +1045,14 @@ func setInterface(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject oldAE = oldAEtf.(string) } } - aggregatedCount, err := aggregatedCountSearchMax(d.Get("ether802_3ad").(string), oldAE, - d.Get("name").(string), m, jnprSess) - if err != nil { - return err + if jnprSess != nil { + aggregatedCount, err := aggregatedCountSearchMax(d.Get("ether802_3ad").(string), oldAE, + d.Get("name").(string), m, jnprSess) + if err != nil { + return err + } + configSet = append(configSet, "set chassis aggregated-devices ethernet device-count "+aggregatedCount) } - configSet = append(configSet, "set chassis aggregated-devices ethernet device-count "+aggregatedCount) } if d.Get("trunk").(bool) { configSet = append(configSet, setPrefix+"unit 0 family ethernet-switching interface-mode trunk") @@ -1063,7 +1085,7 @@ func setInterface(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject configSet = append(configSet, setPrefix+ "aggregated-ether-options minimum-links "+strconv.Itoa(d.Get("ae_minimum_links").(int))) } - if checkCompatibilitySecurity(jnprSess) && d.Get("security_zone").(string) != "" { + if d.Get("security_zone").(string) != "" { configSet = append(configSet, "set security zones security-zone "+ d.Get("security_zone").(string)+" interfaces "+d.Get("name").(string)) } @@ -1072,11 +1094,7 @@ func setInterface(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject " interface "+d.Get("name").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readInterface(interFace string, m interface{}, jnprSess *NetconfObject) (interfaceOptions, error) { sess := m.(*Session) @@ -1381,11 +1399,8 @@ func delInterfaceElement(element string, d *schema.ResourceData, m interface{}, return fmt.Errorf("the name %s contains too dots", d.Get("name").(string)) } configSet = append(configSet, "delete interfaces "+setName+" "+element) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delInterfaceOpts(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) @@ -1415,33 +1430,25 @@ func delInterfaceOpts(d *schema.ResourceData, m interface{}, jnprSess *NetconfOb delPrefix+"unit 0 family ethernet-switching interface-mode", delPrefix+"unit 0 family ethernet-switching vlan members", delPrefix+"native-vlan-id", - delPrefix+"aggregated-ether-options") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } + delPrefix+"aggregated-ether-options", + ) - return nil + return sess.configSet(configSet, jnprSess) } func delZoneInterface(zone string, d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security zones security-zone "+zone+" interfaces "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delRoutingInstanceInterface(instance string, d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete routing-instances "+instance+" interface "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillInterfaceData(d *schema.ResourceData, interfaceOpt interfaceOptions) { @@ -1538,7 +1545,7 @@ func fillFamilyInetAddressOld(item string, inetAddress []map[string]interface{}, vrrpGroup := genVRRPGroupOld(family) vrrpID, err := strconv.Atoi(addressConfig[2]) if err != nil { - return inetAddress, nil + return inetAddress, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) } itemTrimVrrp := strings.TrimPrefix(itemTrim, "vrrp-group "+strconv.Itoa(vrrpID)+" ") if strings.HasPrefix(itemTrim, "vrrp-inet6-group ") { diff --git a/junos/resource_interface_logical.go b/junos/resource_interface_logical.go index a4a5a2a7..667a6055 100644 --- a/junos/resource_interface_logical.go +++ b/junos/resource_interface_logical.go @@ -14,12 +14,14 @@ import ( ) type interfaceLogicalOptions struct { - vlanID int - description string - routingInstance string - securityZone string - familyInet []map[string]interface{} - familyInet6 []map[string]interface{} + vlanID int + description string + routingInstance string + securityZone string + securityInboundProtocols []string + securityInboundServices []string + familyInet []map[string]interface{} + familyInet6 []map[string]interface{} } func resourceInterfaceLogical() *schema.Resource { @@ -173,12 +175,12 @@ func resourceInterfaceLogical() *schema.Resource { "filter_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "filter_output": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "mtu": { Type: schema.TypeInt, @@ -320,12 +322,12 @@ func resourceInterfaceLogical() *schema.Resource { "filter_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "filter_output": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "mtu": { Type: schema.TypeInt, @@ -355,12 +357,24 @@ func resourceInterfaceLogical() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), + }, + "security_inbound_protocols": { + Type: schema.TypeList, + Optional: true, + RequiredWith: []string{"security_zone"}, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "security_inbound_services": { + Type: schema.TypeList, + Optional: true, + RequiredWith: []string{"security_zone"}, + Elem: &schema.Schema{Type: schema.TypeString}, }, "security_zone": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "vlan_id": { Type: schema.TypeInt, @@ -374,6 +388,17 @@ func resourceInterfaceLogical() *schema.Resource { func resourceInterfaceLogicalCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := delInterfaceNC(d, m, nil); err != nil { + return diag.FromErr(err) + } + if err := setInterfaceLogical(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -556,6 +581,12 @@ func resourceInterfaceLogicalUpdate(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } } + } else if v := d.Get("security_zone").(string); v != "" { + if err := delZoneInterfaceLogical(v, d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } } if d.HasChange("routing_instance") { oRoutingInstance, nRoutingInstance := d.GetChange("routing_instance") @@ -803,9 +834,19 @@ func setInterfaceLogical(d *schema.ResourceData, m interface{}, jnprSess *Netcon configSet = append(configSet, "set routing-instances "+d.Get("routing_instance").(string)+ " interface "+d.Get("name").(string)) } - if checkCompatibilitySecurity(jnprSess) && d.Get("security_zone").(string) != "" { + if d.Get("security_zone").(string) != "" { configSet = append(configSet, "set security zones security-zone "+ d.Get("security_zone").(string)+" interfaces "+d.Get("name").(string)) + for _, v := range d.Get("security_inbound_protocols").([]interface{}) { + configSet = append(configSet, "set security zones security-zone "+ + d.Get("security_zone").(string)+" interfaces "+d.Get("name").(string)+ + " host-inbound-traffic protocols "+v.(string)) + } + for _, v := range d.Get("security_inbound_services").([]interface{}) { + configSet = append(configSet, "set security zones security-zone "+ + d.Get("security_zone").(string)+" interfaces "+d.Get("name").(string)+ + " host-inbound-traffic system-services "+v.(string)) + } } if d.Get("vlan_id").(int) != 0 { configSet = append(configSet, setPrefix+"vlan-id "+strconv.Itoa(d.Get("vlan_id").(int))) @@ -813,11 +854,7 @@ func setInterfaceLogical(d *schema.ResourceData, m interface{}, jnprSess *Netcon configSet = append(configSet, setPrefix+"vlan-id "+intCut[1]) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readInterfaceLogical(interFace string, m interface{}, jnprSess *NetconfObject) (interfaceLogicalOptions, error) { sess := m.(*Session) @@ -962,12 +999,15 @@ func readInterfaceLogical(interFace string, m interface{}, jnprSess *NetconfObje if err != nil { return confRead, err } - regexpInts := regexp.MustCompile(`set security-zone \S+ interfaces ` + interFace + `$`) + regexpInts := regexp.MustCompile(`set security-zone \S+ interfaces ` + interFace + `( host-inbound-traffic .*)?$`) for _, item := range strings.Split(zonesConfig, "\n") { intMatch := regexpInts.MatchString(item) if intMatch { - confRead.securityZone = strings.TrimPrefix(strings.TrimSuffix(item, " interfaces "+interFace), - "set security-zone ") + itemTrimSplit := strings.Split(strings.TrimPrefix(item, "set security-zone "), " ") + confRead.securityZone = itemTrimSplit[0] + if err := readInterfaceLogicalSecurityInboundTraffic(interFace, &confRead, m, jnprSess); err != nil { + return confRead, err + } break } @@ -976,6 +1016,39 @@ func readInterfaceLogical(interFace string, m interface{}, jnprSess *NetconfObje return confRead, nil } +func readInterfaceLogicalSecurityInboundTraffic(interFace string, confRead *interfaceLogicalOptions, + m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + + intConfig, err := sess.command("show configuration security zones security-zone "+confRead.securityZone+ + " interfaces "+interFace+" | display set relative", jnprSess) + if err != nil { + return err + } + + if intConfig != emptyWord { + for _, item := range strings.Split(intConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "host-inbound-traffic protocols "): + confRead.securityInboundProtocols = append(confRead.securityInboundProtocols, + strings.TrimPrefix(itemTrim, "host-inbound-traffic protocols ")) + case strings.HasPrefix(itemTrim, "host-inbound-traffic system-services "): + confRead.securityInboundServices = append(confRead.securityInboundServices, + strings.TrimPrefix(itemTrim, "host-inbound-traffic system-services ")) + } + } + } + + return nil +} + func delInterfaceLogical(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) if err := sess.configSet([]string{"delete interfaces " + d.Get("name").(string)}, jnprSess); err != nil { @@ -1009,34 +1082,26 @@ func delInterfaceLogicalOpts(d *schema.ResourceData, m interface{}, jnprSess *Ne configSet := make([]string, 0, 1) delPrefix := "delete interfaces " + d.Get("name").(string) + " " configSet = append(configSet, + delPrefix+"description", delPrefix+"family inet", delPrefix+"family inet6") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delZoneInterfaceLogical(zone string, d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security zones security-zone "+zone+" interfaces "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delRoutingInstanceInterfaceLogical(instance string, d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete routing-instances "+instance+" interface "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillInterfaceLogicalData(d *schema.ResourceData, interfaceLogicalOpt interfaceLogicalOptions) { @@ -1052,6 +1117,12 @@ func fillInterfaceLogicalData(d *schema.ResourceData, interfaceLogicalOpt interf if tfErr := d.Set("routing_instance", interfaceLogicalOpt.routingInstance); tfErr != nil { panic(tfErr) } + if tfErr := d.Set("security_inbound_protocols", interfaceLogicalOpt.securityInboundProtocols); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("security_inbound_services", interfaceLogicalOpt.securityInboundServices); tfErr != nil { + panic(tfErr) + } if tfErr := d.Set("security_zone", interfaceLogicalOpt.securityZone); tfErr != nil { panic(tfErr) } @@ -1080,7 +1151,7 @@ func fillFamilyInetAddress(item string, inetAddress []map[string]interface{}, vrrpGroup := genVRRPGroup(family) vrrpID, err := strconv.Atoi(addressConfig[2]) if err != nil { - return inetAddress, nil + return inetAddress, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) } itemTrimVrrp := strings.TrimPrefix(itemTrim, "vrrp-group "+strconv.Itoa(vrrpID)+" ") if strings.HasPrefix(itemTrim, "vrrp-inet6-group ") { diff --git a/junos/resource_interface_logical_test.go b/junos/resource_interface_logical_test.go index 9c3f6fe0..f79f6ef2 100644 --- a/junos/resource_interface_logical_test.go +++ b/junos/resource_interface_logical_test.go @@ -219,10 +219,12 @@ resource junos_interface_physical testacc_interface_logical_phy { vlan_tagging = true } resource junos_interface_logical testacc_interface_logical { - name = "${junos_interface_physical.testacc_interface_logical_phy.name}.100" - description = "testacc_interface_${junos_interface_physical.testacc_interface_logical_phy.name}.100" - security_zone = junos_security_zone.testacc_interface_logical.name - routing_instance = junos_routing_instance.testacc_interface_logical.name + name = "${junos_interface_physical.testacc_interface_logical_phy.name}.100" + description = "testacc_interface_${junos_interface_physical.testacc_interface_logical_phy.name}.100" + security_zone = junos_security_zone.testacc_interface_logical.name + security_inbound_protocols = ["bgp"] + security_inbound_services = ["ssh"] + routing_instance = junos_routing_instance.testacc_interface_logical.name family_inet { mtu = 1400 filter_input = junos_firewall_filter.testacc_intlogicalInet.name @@ -318,11 +320,13 @@ resource junos_interface_physical testacc_interface_logical_phy { vlan_tagging = true } resource junos_interface_logical testacc_interface_logical { - name = "${junos_interface_physical.testacc_interface_logical_phy.name}.100" - vlan_id = 101 - description = "testacc_interface_${junos_interface_physical.testacc_interface_logical_phy.name}.100" - security_zone = junos_security_zone.testacc_interface_logical.name - routing_instance = junos_routing_instance.testacc_interface_logical.name + name = "${junos_interface_physical.testacc_interface_logical_phy.name}.100" + vlan_id = 101 + description = "testacc_interface_${junos_interface_physical.testacc_interface_logical_phy.name}.100" + security_zone = junos_security_zone.testacc_interface_logical.name + security_inbound_protocols = ["ospf"] + security_inbound_services = ["telnet"] + routing_instance = junos_routing_instance.testacc_interface_logical.name family_inet { mtu = 1500 filter_input = junos_firewall_filter.testacc_intlogicalInet.name diff --git a/junos/resource_interface_physical.go b/junos/resource_interface_physical.go index 937eff99..dcafa0ce 100644 --- a/junos/resource_interface_physical.go +++ b/junos/resource_interface_physical.go @@ -14,15 +14,19 @@ import ( ) type interfacePhysicalOptions struct { - trunk bool - vlanTagging bool - aeMinLink int - vlanNative int - aeLacp string - aeLinkSpeed string - description string - v8023ad string - vlanMembers []string + trunk bool + vlanTagging bool + aeMinLink int + vlanNative int + aeLacp string + aeLinkSpeed string + description string + v8023ad string + vlanMembers []string + esi []map[string]interface{} + etherOpts []map[string]interface{} + gigetherOpts []map[string]interface{} + parentEtherOpts []map[string]interface{} } func resourceInterfacePhysical() *schema.Resource { @@ -54,27 +58,144 @@ func resourceInterfacePhysical() *schema.Resource { Optional: true, }, "ae_lacp": { - Type: schema.TypeString, - Optional: true, - Default: "", - ValidateFunc: validation.StringInSlice([]string{"active", "passive"}, false), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"active", "passive"}, false), + ConflictsWith: []string{"parent_ether_opts"}, + Deprecated: "use parent_ether_opts { lacp } instead", }, "ae_link_speed": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{"100m", "1g", "8g", "10g", "40g", "50g", "80g", "100g"}, false), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"100m", "1g", "8g", "10g", "40g", "50g", "80g", "100g"}, false), + ConflictsWith: []string{"parent_ether_opts"}, + Deprecated: "use parent_ether_opts { link_speed } instead", }, "ae_minimum_links": { - Type: schema.TypeInt, - Optional: true, + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"parent_ether_opts"}, + Deprecated: "use parent_ether_opts { minimum_links } instead", }, "description": { Type: schema.TypeString, Optional: true, }, - "ether802_3ad": { - Type: schema.TypeString, + "esi": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"all-active", "single-active"}, false), + }, + "auto_derive_lacp": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"esi.0.identifier"}, + }, + "df_election_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"mod", "preference"}, false), + }, + "identifier": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"esi.0.auto_derive_lacp"}, + ValidateFunc: validation.StringMatch(regexp.MustCompile( + `^([\d\w]{2}:){9}[\d\w]{2}$`), "bad format or length"), + }, + "source_bmac": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsMACAddress, + }, + }, + }, + }, + "ether_opts": { + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{ + "ae_lacp", "ae_link_speed", "ae_minimum_links", + "gigether_opts", "parent_ether_opts", + }, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ae_8023ad": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"ether_opts.0.redundant_parent"}, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !strings.HasPrefix(value, "ae") { + errors = append(errors, fmt.Errorf( + "%q in %q isn't an ae interface", value, k)) + } + + return + }, + }, + "auto_negotiation": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_auto_negotiation"}, + }, + "no_auto_negotiation": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.auto_negotiation"}, + }, + "flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_flow_control"}, + }, + "no_flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.flow_control"}, + }, + "loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_loopback"}, + }, + "no_loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.loopback"}, + }, + "redundant_parent": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"ether_opts.0.ae_8023ad"}, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !strings.HasPrefix(value, "reth") { + errors = append(errors, fmt.Errorf( + "%q in %q isn't an reth interface", value, k)) + } + + return + }, + }, + }, + }, + }, + "ether802_3ad": { + Type: schema.TypeString, + Optional: true, + Deprecated: "use ether_opts { ae_8023ad } or gigether_opts { ae_8023ad } instead", + ConflictsWith: []string{ + "ae_lacp", "ae_link_speed", "ae_minimum_links", + "ether_opts", "gigether_opts", + }, ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) if !strings.HasPrefix(value, "ae") { @@ -85,6 +206,265 @@ func resourceInterfacePhysical() *schema.Resource { return }, }, + "gigether_opts": { + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{ + "ae_lacp", "ae_link_speed", "ae_minimum_links", + "ether_opts", "ether802_3ad", "parent_ether_opts", + }, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ae_8023ad": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.redundant_parent"}, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !strings.HasPrefix(value, "ae") { + errors = append(errors, fmt.Errorf( + "%q in %q isn't an ae interface", value, k)) + } + + return + }, + }, + "auto_negotiation": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_auto_negotiation"}, + }, + "no_auto_negotiation": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.auto_negotiation"}, + }, + "flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_flow_control"}, + }, + "no_flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.flow_control"}, + }, + "loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.no_loopback"}, + }, + "no_loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.loopback"}, + }, + "redundant_parent": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"gigether_opts.0.ae_8023ad"}, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !strings.HasPrefix(value, "reth") { + errors = append(errors, fmt.Errorf( + "%q in %q isn't an reth interface", value, k)) + } + + return + }, + }, + }, + }, + }, + "parent_ether_opts": { + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{ + "ae_lacp", "ae_link_speed", "ae_minimum_links", + "ether_opts", "ether802_3ad", "gigether_opts", + }, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bfd_liveness_detection": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "local_address": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsIPAddress, + }, + "authentication_algorithm": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "keyed-md5", "keyed-sha-1", "meticulous-keyed-md5", "meticulous-keyed-sha-1", "simple-password", + }, false), + }, + "authentication_key_chain": { + Type: schema.TypeString, + Optional: true, + }, + "authentication_loose_check": { + Type: schema.TypeBool, + Optional: true, + }, + "detection_time_threshold": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "holddown_interval": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 255000), + }, + "minimum_interval": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 255000), + }, + "minimum_receive_interval": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 255000), + }, + "multiplier": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 255), + }, + "neighbor": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsIPAddress, + }, + "no_adaptation": { + Type: schema.TypeBool, + Optional: true, + }, + "transmit_interval_minimum_interval": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 255000), + }, + "transmit_interval_threshold": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 4294967295), + }, + "version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"0", "1", "automatic"}, false), + }, + }, + }, + }, + "flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.no_flow_control"}, + }, + "no_flow_control": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.flow_control"}, + }, + "lacp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"active", "passive"}, false), + }, + "admin_key": { + Type: schema.TypeInt, + Optional: true, + Default: -1, + ValidateFunc: validation.IntBetween(0, 65535), + }, + "periodic": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"fast", "slow"}, false), + }, + "sync_reset": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"disable", "enable"}, false), + }, + "system_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsMACAddress, + }, + "system_priority": { + Type: schema.TypeInt, + Optional: true, + Default: -1, + ValidateFunc: validation.IntBetween(0, 65535), + }, + }, + }, + }, + "loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.no_loopback"}, + }, + "no_loopback": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.loopback"}, + }, + "link_speed": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "100m", + "1g", "2.5g", "5g", "8g", + "10g", "25g", "40g", "50g", "80g", + "100g", "400g", "mixed"}, false), + }, + "minimum_bandwidth": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.minimum_links"}, + ValidateFunc: validation.StringMatch(regexp.MustCompile( + `^[0-9]+ (k|g|m)?bps$`), "must be 'N (k|g|m)?bps' format"), + }, + "minimum_links": { + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"parent_ether_opts.0.minimum_bandwidth"}, + ValidateFunc: validation.IntBetween(1, 64), + }, + "redundancy_group": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 128), + }, + "source_address_filter": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "source_filtering": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, "trunk": { Type: schema.TypeBool, Optional: true, @@ -109,6 +489,17 @@ func resourceInterfacePhysical() *schema.Resource { func resourceInterfacePhysicalCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := delInterfaceNC(d, m, nil); err != nil { + return diag.FromErr(err) + } + if err := setInterfacePhysical(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -230,6 +621,11 @@ func resourceInterfacePhysicalUpdate(ctx context.Context, d *schema.ResourceData return diag.FromErr(err) } + if err := unsetInterfacePhysicalAE(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } if err := setInterfacePhysical(d, m, jnprSess); err != nil { sess.configClear(jnprSess) @@ -406,6 +802,47 @@ func checkInterfaceExists(interFace string, m interface{}, jnprSess *NetconfObje return true, nil } +func unsetInterfacePhysicalAE(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + var oldAE string + switch { + case d.HasChange("ether802_3ad"): + oldAEtf, _ := d.GetChange("ether802_3ad") + if oldAEtf.(string) != "" { + oldAE = oldAEtf.(string) + } + case d.HasChange("ether_opts"): + oldEthOpts, _ := d.GetChange("ether_opts") + if len(oldEthOpts.([]interface{})) != 0 { + v := oldEthOpts.([]interface{})[0] + if o := v.(map[string]interface{})["ae_8023ad"].(string); o != "" { + oldAE = o + } + } + case d.HasChange("gigether_opts"): + oldGigethOpts, _ := d.GetChange("gigether_opts") + if len(oldGigethOpts.([]interface{})) != 0 { + v := oldGigethOpts.([]interface{})[0] + if o := v.(map[string]interface{})["ae_8023ad"].(string); o != "" { + oldAE = o + } + } + } + if oldAE != "" { + aggregatedCount, err := interfaceAggregatedCountSearchMax("ae-1", oldAE, d.Get("name").(string), m, jnprSess) + if err != nil { + return err + } + if aggregatedCount == "0" { + return sess.configSet([]string{"delete chassis aggregated-devices ethernet device-count"}, jnprSess) + } + + return sess.configSet([]string{"set chassis aggregated-devices ethernet device-count " + aggregatedCount}, jnprSess) + } + + return nil +} + func setInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0) @@ -435,30 +872,136 @@ func setInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *Netco if d.Get("description").(string) != "" { configSet = append(configSet, setPrefix+"description \""+d.Get("description").(string)+"\"") } - if v := d.Get("name").(string); strings.HasPrefix(v, "ae") { + if err := setInterfacePhysicalEsi(setPrefix, d.Get("esi").([]interface{}), m, jnprSess); err != nil { + return err + } + if v := d.Get("name").(string); strings.HasPrefix(v, "ae") && jnprSess != nil { aggregatedCount, err := interfaceAggregatedCountSearchMax(v, "ae-1", v, m, jnprSess) if err != nil { return err } configSet = append(configSet, "set chassis aggregated-devices ethernet device-count "+aggregatedCount) - } else if d.Get("ether802_3ad").(string) != "" { - configSet = append(configSet, setPrefix+"ether-options 802.3ad "+ - d.Get("ether802_3ad").(string)) - configSet = append(configSet, setPrefix+"gigether-options 802.3ad "+ - d.Get("ether802_3ad").(string)) + } else if d.Get("ether802_3ad").(string) != "" || + len(d.Get("ether_opts").([]interface{})) != 0 || + len(d.Get("gigether_opts").([]interface{})) != 0 { oldAE := "ae-1" - if d.HasChange("ether802_3ad") { + var newAE string + switch { + case d.Get("ether802_3ad").(string) != "": + newAE = d.Get("ether802_3ad").(string) + configSet = append(configSet, setPrefix+"ether-options 802.3ad "+ + d.Get("ether802_3ad").(string)) + configSet = append(configSet, setPrefix+"gigether-options 802.3ad "+ + d.Get("ether802_3ad").(string)) + case len(d.Get("ether_opts").([]interface{})) != 0: + for _, v := range d.Get("ether_opts").([]interface{}) { + if v == nil { + return fmt.Errorf("ether_opts block is empty") + } + m := v.(map[string]interface{}) + if m["ae_8023ad"].(string) != "" { + newAE = m["ae_8023ad"].(string) + configSet = append(configSet, setPrefix+"ether-options 802.3ad "+ + m["ae_8023ad"].(string)) + } + if m["auto_negotiation"].(bool) { + configSet = append(configSet, setPrefix+"ether-options auto-negotiation") + } + if m["no_auto_negotiation"].(bool) { + configSet = append(configSet, setPrefix+"ether-options no-auto-negotiation") + } + if m["flow_control"].(bool) { + configSet = append(configSet, setPrefix+"ether-options flow-control") + } + if m["no_flow_control"].(bool) { + configSet = append(configSet, setPrefix+"ether-options no-flow-control") + } + if m["loopback"].(bool) { + configSet = append(configSet, setPrefix+"ether-options loopback") + } + if m["no_loopback"].(bool) { + configSet = append(configSet, setPrefix+"ether-options no-loopback") + } + if m["redundant_parent"].(string) != "" { + configSet = append(configSet, setPrefix+"ether-options redundant-parent "+ + m["redundant_parent"].(string)) + } + } + case len(d.Get("gigether_opts").([]interface{})) != 0: + for _, v := range d.Get("gigether_opts").([]interface{}) { + if v == nil { + return fmt.Errorf("gigether_opts block is empty") + } + m := v.(map[string]interface{}) + if m["ae_8023ad"].(string) != "" { + newAE = m["ae_8023ad"].(string) + configSet = append(configSet, setPrefix+"gigether-options 802.3ad "+ + m["ae_8023ad"].(string)) + } + if m["auto_negotiation"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options auto-negotiation") + } + if m["no_auto_negotiation"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options no-auto-negotiation") + } + if m["flow_control"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options flow-control") + } + if m["no_flow_control"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options no-flow-control") + } + if m["loopback"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options loopback") + } + if m["no_loopback"].(bool) { + configSet = append(configSet, setPrefix+"gigether-options no-loopback") + } + if m["redundant_parent"].(string) != "" { + configSet = append(configSet, setPrefix+"gigether-options redundant-parent "+ + m["redundant_parent"].(string)) + } + } + } + switch { + case d.HasChange("ether802_3ad"): oldAEtf, _ := d.GetChange("ether802_3ad") if oldAEtf.(string) != "" { oldAE = oldAEtf.(string) } + case d.HasChange("ether_opts"): + oldEthOpts, _ := d.GetChange("ether_opts") + if len(oldEthOpts.([]interface{})) != 0 { + v := oldEthOpts.([]interface{})[0] + if o := v.(map[string]interface{})["ae_8023ad"].(string); o != "" { + oldAE = o + } + } + case d.HasChange("gigether_opts"): + oldGigethOpts, _ := d.GetChange("gigether_opts") + if len(oldGigethOpts.([]interface{})) != 0 { + v := oldGigethOpts.([]interface{})[0] + if o := v.(map[string]interface{})["ae_8023ad"].(string); o != "" { + oldAE = o + } + } } - aggregatedCount, err := interfaceAggregatedCountSearchMax(d.Get("ether802_3ad").(string), oldAE, - d.Get("name").(string), m, jnprSess) - if err != nil { + if newAE != "" && jnprSess != nil { + aggregatedCount, err := interfaceAggregatedCountSearchMax(newAE, oldAE, + d.Get("name").(string), m, jnprSess) + if err != nil { + return err + } + configSet = append(configSet, "set chassis aggregated-devices ethernet device-count "+aggregatedCount) + } + } + for _, v := range d.Get("parent_ether_opts").([]interface{}) { + if v == nil { + return fmt.Errorf("parent_ether_opts block is empty") + } + if err := setInterfacePhysicalParentEtherOpts( + v.(map[string]interface{}), d.Get("name").(string), m, jnprSess); err != nil { return err } - configSet = append(configSet, "set chassis aggregated-devices ethernet device-count "+aggregatedCount) } if d.Get("trunk").(bool) { configSet = append(configSet, setPrefix+"unit 0 family ethernet-switching interface-mode trunk") @@ -474,12 +1017,152 @@ func setInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *Netco configSet = append(configSet, setPrefix+"vlan-tagging") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err + return sess.configSet(configSet, jnprSess) +} + +func setInterfacePhysicalEsi(setPrefix string, esiParams []interface{}, + m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + + for _, v := range esiParams { + m := v.(map[string]interface{}) + if m["mode"].(string) != "" { + configSet = append(configSet, setPrefix+"esi "+m["mode"].(string)) + } + if m["auto_derive_lacp"].(bool) { + configSet = append(configSet, setPrefix+"esi auto-derive lacp") + } + if m["df_election_type"].(string) != "" { + configSet = append(configSet, setPrefix+"esi df-election-type "+m["df_election_type"].(string)) + } + if m["identifier"].(string) != "" { + configSet = append(configSet, setPrefix+"esi "+m["identifier"].(string)) + } + if m["source_bmac"].(string) != "" { + configSet = append(configSet, setPrefix+"esi source-bmac "+m["source_bmac"].(string)) + } } - return nil + return sess.configSet(configSet, jnprSess) +} +func setInterfacePhysicalParentEtherOpts( + ethOpts map[string]interface{}, interfaceName string, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + setPrefix := "set interfaces " + interfaceName + " " + switch { + case strings.HasPrefix(interfaceName, "ae"): + setPrefix += "aggregated-ether-options " + case strings.HasPrefix(interfaceName, "reth"): + setPrefix += "redundant-ether-options " + default: + return fmt.Errorf("parent_ether_opts not compatible with this interface %s "+ + "(need to ae* or reth*)", interfaceName) + } + + for _, v := range ethOpts["bfd_liveness_detection"].([]interface{}) { + bfdLiveDetect := v.(map[string]interface{}) + configSet = append(configSet, setPrefix+ + "bfd-liveness-detection local-address "+bfdLiveDetect["local_address"].(string)) + if v2 := bfdLiveDetect["authentication_algorithm"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"bfd-liveness-detection authentication algorithm "+v2) + } + if v2 := bfdLiveDetect["authentication_key_chain"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"bfd-liveness-detection authentication key-chain "+v2) + } + if bfdLiveDetect["authentication_loose_check"].(bool) { + configSet = append(configSet, setPrefix+"bfd-liveness-detection authentication loose-check") + } + if v2 := bfdLiveDetect["detection_time_threshold"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection detection-time threshold "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["holddown_interval"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection holddown-interval "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["minimum_interval"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection minimum-interval "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["minimum_receive_interval"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection minimum-receive-interval "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["multiplier"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection multiplier "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["neighbor"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"bfd-liveness-detection neighbor "+v2) + } + if bfdLiveDetect["no_adaptation"].(bool) { + configSet = append(configSet, setPrefix+"bfd-liveness-detection no-adaptation") + } + if v2 := bfdLiveDetect["transmit_interval_minimum_interval"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+ + "bfd-liveness-detection transmit-interval minimum-interval "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["transmit_interval_threshold"].(int); v2 != 0 { + configSet = append(configSet, setPrefix+"bfd-liveness-detection transmit-interval threshold "+strconv.Itoa(v2)) + } + if v2 := bfdLiveDetect["version"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"bfd-liveness-detection version "+v2) + } + } + if ethOpts["flow_control"].(bool) { + configSet = append(configSet, setPrefix+flowControlWords) + } + if ethOpts["no_flow_control"].(bool) { + configSet = append(configSet, setPrefix+noFlowControlWords) + } + for _, v := range ethOpts["lacp"].([]interface{}) { + lacp := v.(map[string]interface{}) + configSet = append(configSet, setPrefix+"lacp "+lacp["mode"].(string)) + if v2 := lacp["admin_key"].(int); v2 != -1 { + configSet = append(configSet, setPrefix+"lacp admin-key "+strconv.Itoa(v2)) + } + if v2 := lacp["periodic"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"lacp periodic "+v2) + } + if v2 := lacp["sync_reset"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"lacp sync-reset "+v2) + } + if v2 := lacp["system_id"].(string); v2 != "" { + configSet = append(configSet, setPrefix+"lacp system-id "+v2) + } + if v2 := lacp["system_priority"].(int); v2 != -1 { + configSet = append(configSet, setPrefix+"lacp system-priority "+strconv.Itoa(v2)) + } + } + if ethOpts["loopback"].(bool) { + configSet = append(configSet, setPrefix+loopbackWord) + } + if ethOpts["no_loopback"].(bool) { + configSet = append(configSet, setPrefix+noLoopbackWord) + } + if v := ethOpts["link_speed"].(string); v != "" { + configSet = append(configSet, setPrefix+"link-speed "+v) + } + if v := ethOpts["minimum_bandwidth"].(string); v != "" { + vS := strings.Split(v, " ") + configSet = append(configSet, setPrefix+"minimum-bandwidth bw-value "+vS[0]) + if len(vS) > 1 { + configSet = append(configSet, setPrefix+"minimum-bandwidth bw-unit "+vS[1]) + } + } + if v := ethOpts["minimum_links"].(int); v != 0 { + configSet = append(configSet, setPrefix+"minimum-links "+strconv.Itoa(v)) + } + if v := ethOpts["redundancy_group"].(int); v != 0 { + configSet = append(configSet, setPrefix+"redundancy-group "+strconv.Itoa(v)) + } + for _, v := range ethOpts["source_address_filter"].([]interface{}) { + configSet = append(configSet, setPrefix+"source-address-filter "+v.(string)) + } + if ethOpts["source_filtering"].(bool) { + configSet = append(configSet, setPrefix+"source-filtering") + } + + return sess.configSet(configSet, jnprSess) } + func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObject) (interfacePhysicalOptions, error) { sess := m.(*Session) var confRead interfacePhysicalOptions @@ -503,21 +1186,46 @@ func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObj switch { case strings.HasPrefix(itemTrim, "aggregated-ether-options lacp "): confRead.aeLacp = strings.TrimPrefix(itemTrim, "aggregated-ether-options lacp ") + if err := readInterfacePhysicalParentEtherOpts(&confRead, + strings.TrimPrefix(itemTrim, "aggregated-ether-options ")); err != nil { + return confRead, err + } case strings.HasPrefix(itemTrim, "aggregated-ether-options link-speed "): confRead.aeLinkSpeed = strings.TrimPrefix(itemTrim, "aggregated-ether-options link-speed ") + if err := readInterfacePhysicalParentEtherOpts(&confRead, + strings.TrimPrefix(itemTrim, "aggregated-ether-options ")); err != nil { + return confRead, err + } case strings.HasPrefix(itemTrim, "aggregated-ether-options minimum-links "): confRead.aeMinLink, err = strconv.Atoi(strings.TrimPrefix(itemTrim, "aggregated-ether-options minimum-links ")) if err != nil { return confRead, fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) } + if err := readInterfacePhysicalParentEtherOpts(&confRead, + strings.TrimPrefix(itemTrim, "aggregated-ether-options ")); err != nil { + return confRead, err + } + case strings.HasPrefix(itemTrim, "aggregated-ether-options "): + if err := readInterfacePhysicalParentEtherOpts(&confRead, + strings.TrimPrefix(itemTrim, "aggregated-ether-options ")); err != nil { + return confRead, err + } + case strings.HasPrefix(itemTrim, "redundant-ether-options "): + if err := readInterfacePhysicalParentEtherOpts(&confRead, + strings.TrimPrefix(itemTrim, "redundant-ether-options ")); err != nil { + return confRead, err + } case strings.HasPrefix(itemTrim, "description "): confRead.description = strings.Trim(strings.TrimPrefix(itemTrim, "description "), "\"") - - case strings.HasPrefix(itemTrim, "ether-options 802.3ad "): - confRead.v8023ad = strings.TrimPrefix(itemTrim, "ether-options 802.3ad ") - case strings.HasPrefix(itemTrim, "gigether-options 802.3ad "): - confRead.v8023ad = strings.TrimPrefix(itemTrim, "gigether-options 802.3ad ") + case strings.HasPrefix(itemTrim, "esi "): + if err := readInterfacePhysicalEsi(&confRead, itemTrim); err != nil { + return confRead, err + } + case strings.HasPrefix(itemTrim, "ether-options "): + readInterfacePhysicalEtherOpts(&confRead, strings.TrimPrefix(itemTrim, "ether-options ")) + case strings.HasPrefix(itemTrim, "gigether-options "): + readInterfacePhysicalGigetherOpts(&confRead, strings.TrimPrefix(itemTrim, "gigether-options ")) case strings.HasPrefix(itemTrim, "native-vlan-id"): confRead.vlanNative, err = strconv.Atoi(strings.TrimPrefix(itemTrim, "native-vlan-id ")) if err != nil { @@ -538,6 +1246,296 @@ func readInterfacePhysical(interFace string, m interface{}, jnprSess *NetconfObj return confRead, nil } +func readInterfacePhysicalEsi(confRead *interfacePhysicalOptions, item string) error { + itemTrim := strings.TrimPrefix(item, "esi ") + if len(confRead.esi) == 0 { + confRead.esi = append(confRead.esi, map[string]interface{}{ + "mode": "", + "auto_derive_lacp": false, + "df_election_type": "", + "identifier": "", + "source_bmac": "", + }) + } + var err error + identifier, err := regexp.MatchString(`^([\d\w]{2}:){9}[\d\w]{2}`, itemTrim) + if err != nil { + return fmt.Errorf("esi_identifier regexp error : %w", err) + } + switch { + case identifier: + confRead.esi[0]["identifier"] = itemTrim + case itemTrim == "all-active" || itemTrim == "single-active": + confRead.esi[0]["mode"] = itemTrim + case strings.HasPrefix(itemTrim, "df-election-type "): + confRead.esi[0]["df_election_type"] = strings.TrimPrefix(itemTrim, "df-election-type ") + case strings.HasPrefix(itemTrim, "source-bmac "): + confRead.esi[0]["source_bmac"] = strings.TrimPrefix(itemTrim, "source-bmac ") + case itemTrim == "auto-derive lacp": + confRead.esi[0]["auto_derive_lacp"] = true + } + + return nil +} +func readInterfacePhysicalEtherOpts(confRead *interfacePhysicalOptions, itemTrim string) { + if len(confRead.etherOpts) == 0 { + confRead.etherOpts = append(confRead.etherOpts, map[string]interface{}{ + "ae_8023ad": "", + "auto_negotiation": false, + "no_auto_negotiation": false, + "flow_control": false, + "no_flow_control": false, + "loopback": false, + "no_loopback": false, + "redundant_parent": "", + }) + } + switch { + case strings.HasPrefix(itemTrim, "802.3ad "): + confRead.v8023ad = strings.TrimPrefix(itemTrim, "802.3ad ") + confRead.etherOpts[0]["ae_8023ad"] = strings.TrimPrefix(itemTrim, "802.3ad ") + case itemTrim == "auto-negotiation": + confRead.etherOpts[0]["auto_negotiation"] = true + case itemTrim == "no-auto-negotiation": + confRead.etherOpts[0]["no_auto_negotiation"] = true + case itemTrim == flowControlWords: + confRead.etherOpts[0]["flow_control"] = true + case itemTrim == noFlowControlWords: + confRead.etherOpts[0]["no_flow_control"] = true + case itemTrim == loopbackWord: + confRead.etherOpts[0]["loopback"] = true + case itemTrim == noLoopbackWord: + confRead.etherOpts[0]["no_loopback"] = true + case strings.HasPrefix(itemTrim, "redundant-parent "): + confRead.etherOpts[0]["redundant_parent"] = strings.TrimPrefix(itemTrim, "redundant-parent ") + } +} +func readInterfacePhysicalGigetherOpts(confRead *interfacePhysicalOptions, itemTrim string) { + if len(confRead.gigetherOpts) == 0 { + confRead.gigetherOpts = append(confRead.gigetherOpts, map[string]interface{}{ + "ae_8023ad": "", + "auto_negotiation": false, + "no_auto_negotiation": false, + "flow_control": false, + "no_flow_control": false, + "loopback": false, + "no_loopback": false, + "redundant_parent": "", + }) + } + switch { + case strings.HasPrefix(itemTrim, "802.3ad "): + confRead.v8023ad = strings.TrimPrefix(itemTrim, "802.3ad ") + confRead.gigetherOpts[0]["ae_8023ad"] = strings.TrimPrefix(itemTrim, "802.3ad ") + case itemTrim == "auto-negotiation": + confRead.gigetherOpts[0]["auto_negotiation"] = true + case itemTrim == "no-auto-negotiation": + confRead.gigetherOpts[0]["no_auto_negotiation"] = true + case itemTrim == flowControlWords: + confRead.gigetherOpts[0]["flow_control"] = true + case itemTrim == noFlowControlWords: + confRead.gigetherOpts[0]["no_flow_control"] = true + case itemTrim == loopbackWord: + confRead.gigetherOpts[0]["loopback"] = true + case itemTrim == noLoopbackWord: + confRead.gigetherOpts[0]["no_loopback"] = true + case strings.HasPrefix(itemTrim, "redundant-parent "): + confRead.gigetherOpts[0]["redundant_parent"] = strings.TrimPrefix(itemTrim, "redundant-parent ") + } +} +func readInterfacePhysicalParentEtherOpts(confRead *interfacePhysicalOptions, itemTrim string) error { + if len(confRead.parentEtherOpts) == 0 { + confRead.parentEtherOpts = append(confRead.parentEtherOpts, map[string]interface{}{ + "bfd_liveness_detection": make([]map[string]interface{}, 0), + "flow_control": false, + "no_flow_control": false, + "lacp": make([]map[string]interface{}, 0), + "loopback": false, + "no_loopback": false, + "link_speed": "", + "minimum_bandwidth": "", + "minimum_links": 0, + "redundancy_group": 0, + "source_address_filter": make([]string, 0), + "source_filtering": false, + }) + } + switch { + case strings.HasPrefix(itemTrim, "bfd-liveness-detection "): + if len(confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})) == 0 { + confRead.parentEtherOpts[0]["bfd_liveness_detection"] = append( + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{}), + map[string]interface{}{ + "local_address": "", + "authentication_algorithm": "", + "authentication_key_chain": "", + "authentication_loose_check": false, + "detection_time_threshold": 0, + "holddown_interval": 0, + "minimum_interval": 0, + "minimum_receive_interval": 0, + "multiplier": 0, + "neighbor": "", + "no_adaptation": false, + "transmit_interval_minimum_interval": 0, + "transmit_interval_threshold": 0, + "version": "", + }) + } + itemTrimBfdLiveDet := strings.TrimPrefix(itemTrim, "bfd-liveness-detection ") + switch { + case strings.HasPrefix(itemTrimBfdLiveDet, "local-address "): + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["local_address"] = + strings.TrimPrefix(itemTrimBfdLiveDet, "local-address ") + case strings.HasPrefix(itemTrimBfdLiveDet, "authentication algorithm "): + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["authentication_algorithm"] = + strings.TrimPrefix(itemTrimBfdLiveDet, "authentication algorithm ") + case strings.HasPrefix(itemTrimBfdLiveDet, "authentication key-chain "): + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["authentication_key_chain"] = + strings.TrimPrefix(itemTrimBfdLiveDet, "authentication key-chain ") + case itemTrimBfdLiveDet == "authentication loose-check": + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["authentication_loose_check"] = + true + case strings.HasPrefix(itemTrimBfdLiveDet, "detection-time threshold "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["detection_time_threshold"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "detection-time threshold ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "holddown-interval "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["holddown_interval"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "holddown-interval ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "minimum-interval "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["minimum_interval"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "minimum-interval ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "minimum-receive-interval "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["minimum_receive_interval"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "minimum-receive-interval ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "multiplier "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["multiplier"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "multiplier ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "neighbor "): + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["neighbor"] = + strings.TrimPrefix(itemTrimBfdLiveDet, "neighbor ") + case itemTrimBfdLiveDet == "no-adaptation": + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["no_adaptation"] = + true + case strings.HasPrefix(itemTrimBfdLiveDet, "transmit-interval minimum-interval "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["transmit_interval_minimum_interval"], // nolint: lll + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "transmit-interval minimum-interval ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "transmit-interval threshold "): + var err error + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["transmit_interval_threshold"], + err = strconv.Atoi(strings.TrimPrefix(itemTrimBfdLiveDet, "transmit-interval threshold ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimBfdLiveDet, "version "): + confRead.parentEtherOpts[0]["bfd_liveness_detection"].([]map[string]interface{})[0]["version"] = + strings.TrimPrefix(itemTrimBfdLiveDet, "version ") + } + case itemTrim == flowControlWords: + confRead.parentEtherOpts[0]["flow_control"] = true + case itemTrim == noFlowControlWords: + confRead.parentEtherOpts[0]["no_flow_control"] = true + case strings.HasPrefix(itemTrim, "lacp "): + if len(confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})) == 0 { + confRead.parentEtherOpts[0]["lacp"] = append(confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{}), + map[string]interface{}{ + "mode": "", + "admin_key": -1, + "periodic": "", + "sync_reset": "", + "system_id": "", + "system_priority": -1, + }) + } + itemTrimLacp := strings.TrimPrefix(itemTrim, "lacp ") + switch { + case itemTrimLacp == activeW || itemTrimLacp == "passive": + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["mode"] = itemTrimLacp + case strings.HasPrefix(itemTrimLacp, "admin-key "): + var err error + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["admin_key"], err = + strconv.Atoi(strings.TrimPrefix(itemTrimLacp, "admin-key ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrimLacp, "periodic "): + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["periodic"] = + strings.TrimPrefix(itemTrimLacp, "periodic ") + case strings.HasPrefix(itemTrimLacp, "sync-reset "): + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["sync_reset"] = + strings.TrimPrefix(itemTrimLacp, "sync-reset ") + case strings.HasPrefix(itemTrimLacp, "system-id "): + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["system_id"] = + strings.TrimPrefix(itemTrimLacp, "system-id ") + case strings.HasPrefix(itemTrimLacp, "system-priority "): + var err error + confRead.parentEtherOpts[0]["lacp"].([]map[string]interface{})[0]["system_priority"], err = + strconv.Atoi(strings.TrimPrefix(itemTrimLacp, "system-priority ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + } + case itemTrim == loopbackWord: + confRead.parentEtherOpts[0]["loopback"] = true + case itemTrim == noLoopbackWord: + confRead.parentEtherOpts[0]["no_loopback"] = true + case strings.HasPrefix(itemTrim, "link-speed "): + confRead.parentEtherOpts[0]["link_speed"] = strings.TrimPrefix(itemTrim, "link-speed ") + case strings.HasPrefix(itemTrim, "minimum-bandwidth bw-value "): + confRead.parentEtherOpts[0]["minimum_bandwidth"] = strings.TrimPrefix(itemTrim, "minimum-bandwidth bw-value ") + + confRead.parentEtherOpts[0]["minimum_bandwidth"].(string) + case strings.HasPrefix(itemTrim, "minimum-bandwidth bw-unit "): + confRead.parentEtherOpts[0]["minimum_bandwidth"] = confRead.parentEtherOpts[0]["minimum_bandwidth"].(string) + + " " + strings.TrimPrefix(itemTrim, "minimum-bandwidth bw-unit ") + case strings.HasPrefix(itemTrim, "minimum-links "): + var err error + confRead.parentEtherOpts[0]["minimum_links"], err = + strconv.Atoi(strings.TrimPrefix(itemTrim, "minimum-links ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrim, "redundancy-group "): + var err error + confRead.parentEtherOpts[0]["redundancy_group"], err = + strconv.Atoi(strings.TrimPrefix(itemTrim, "redundancy-group ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrim, err) + } + case strings.HasPrefix(itemTrim, "source-address-filter "): + confRead.parentEtherOpts[0]["source_address_filter"] = append( + confRead.parentEtherOpts[0]["source_address_filter"].([]string), + strings.TrimPrefix(itemTrim, "source-address-filter ")) + case itemTrim == "source-filtering": + confRead.parentEtherOpts[0]["source_filtering"] = true + } + + return nil +} + func delInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) if err := checkInterfacePhysicalContainsUnit(d.Get("name").(string), m, jnprSess); err != nil { @@ -562,26 +1560,41 @@ func delInterfacePhysical(d *schema.ResourceData, m interface{}, jnprSess *Netco return err } } - } else if d.Get("ether802_3ad").(string) != "" { - lastAEchild, err := interfaceAggregatedLastChild(d.Get("ether802_3ad").(string), d.Get("name").(string), m, jnprSess) - if err != nil { - return err + } else if d.Get("ether802_3ad").(string) != "" || + len(d.Get("ether_opts").([]interface{})) != 0 || + len(d.Get("gigether_opts").([]interface{})) != 0 { + var aeDel string + switch { + case d.Get("ether802_3ad").(string) != "": + aeDel = d.Get("ether802_3ad").(string) + case len(d.Get("ether_opts").([]interface{})) != 0 && d.Get("ether_opts").([]interface{})[0] != nil: + v := d.Get("ether_opts").([]interface{})[0].(map[string]interface{}) + aeDel = v["ae_8023ad"].(string) + case len(d.Get("gigether_opts").([]interface{})) != 0 && d.Get("gigether_opts").([]interface{})[0] != nil: + v := d.Get("gigether_opts").([]interface{})[0].(map[string]interface{}) + aeDel = v["ae_8023ad"].(string) } - if lastAEchild { - aggregatedCount, err := interfaceAggregatedCountSearchMax("ae-1", d.Get("ether802_3ad").(string), - d.Get("name").(string), m, jnprSess) + if aeDel != "" { + lastAEchild, err := interfaceAggregatedLastChild(aeDel, d.Get("name").(string), m, jnprSess) if err != nil { return err } - if aggregatedCount == "0" { - err = sess.configSet([]string{"delete chassis aggregated-devices ethernet device-count"}, jnprSess) + if lastAEchild { + aggregatedCount, err := interfaceAggregatedCountSearchMax("ae-1", aeDel, + d.Get("name").(string), m, jnprSess) if err != nil { return err } - } else { - err = sess.configSet([]string{"set chassis aggregated-devices ethernet device-count " + aggregatedCount}, jnprSess) - if err != nil { - return err + if aggregatedCount == "0" { + err = sess.configSet([]string{"delete chassis aggregated-devices ethernet device-count"}, jnprSess) + if err != nil { + return err + } + } else { + err = sess.configSet([]string{"set chassis aggregated-devices ethernet device-count " + aggregatedCount}, jnprSess) + if err != nil { + return err + } } } } @@ -614,6 +1627,7 @@ func checkInterfacePhysicalContainsUnit(interFace string, m interface{}, jnprSes return nil } + func delInterfaceNC(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) @@ -623,47 +1637,71 @@ func delInterfaceNC(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje } configSet = append(configSet, delPrefix+"description") configSet = append(configSet, delPrefix+"disable") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } + func delInterfacePhysicalOpts(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) delPrefix := "delete interfaces " + d.Get("name").(string) + " " configSet = append(configSet, delPrefix+"aggregated-ether-options", - delPrefix+"ether-options 802.3ad", - delPrefix+"gigether-options 802.3ad", + delPrefix+"description", + delPrefix+"esi", + delPrefix+"ether-options", + delPrefix+"gigether-options", delPrefix+"native-vlan-id", + delPrefix+"redundant-ether-options", delPrefix+"unit 0 family ethernet-switching interface-mode", delPrefix+"unit 0 family ethernet-switching vlan members", delPrefix+"vlan-tagging", ) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillInterfacePhysicalData(d *schema.ResourceData, interfaceOpt interfacePhysicalOptions) { - if tfErr := d.Set("ae_lacp", interfaceOpt.aeLacp); tfErr != nil { - panic(tfErr) + _, okAeLacp := d.GetOk("ae_lacp") + if okAeLacp { + if tfErr := d.Set("ae_lacp", interfaceOpt.aeLacp); tfErr != nil { + panic(tfErr) + } } - if tfErr := d.Set("ae_link_speed", interfaceOpt.aeLinkSpeed); tfErr != nil { - panic(tfErr) + _, okAeLinkSpeed := d.GetOk("ae_link_speed") + if okAeLinkSpeed { + if tfErr := d.Set("ae_link_speed", interfaceOpt.aeLinkSpeed); tfErr != nil { + panic(tfErr) + } + } + _, okAeMinLinks := d.GetOk("ae_minimum_links") + if okAeMinLinks { + if tfErr := d.Set("ae_minimum_links", interfaceOpt.aeMinLink); tfErr != nil { + panic(tfErr) + } } - if tfErr := d.Set("ae_minimum_links", interfaceOpt.aeMinLink); tfErr != nil { + if tfErr := d.Set("esi", interfaceOpt.esi); tfErr != nil { panic(tfErr) } if tfErr := d.Set("description", interfaceOpt.description); tfErr != nil { panic(tfErr) } - if tfErr := d.Set("ether802_3ad", interfaceOpt.v8023ad); tfErr != nil { - panic(tfErr) + if _, ok := d.GetOk("ether802_3ad"); ok { + if tfErr := d.Set("ether802_3ad", interfaceOpt.v8023ad); tfErr != nil { + panic(tfErr) + } + } else { + if tfErr := d.Set("ether_opts", interfaceOpt.etherOpts); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("gigether_opts", interfaceOpt.gigetherOpts); tfErr != nil { + panic(tfErr) + } + } + if !okAeLacp && !okAeLinkSpeed && !okAeMinLinks { + if tfErr := d.Set("parent_ether_opts", interfaceOpt.parentEtherOpts); tfErr != nil { + panic(tfErr) + } } if tfErr := d.Set("trunk", interfaceOpt.trunk); tfErr != nil { panic(tfErr) diff --git a/junos/resource_interface_physical_test.go b/junos/resource_interface_physical_test.go index 7ce0335e..2403b453 100644 --- a/junos/resource_interface_physical_test.go +++ b/junos/resource_interface_physical_test.go @@ -1,7 +1,6 @@ package junos_test import ( - "fmt" "os" "testing" @@ -12,6 +11,7 @@ import ( // export TESTACC_INTERFACE_AE=ae for choose interface aggregate test else it's ae0. func TestAccJunosInterfacePhysical_basic(t *testing.T) { var testaccInterface string + var testaccInterface2 string var testaccInterfaceAE string if os.Getenv("TESTACC_INTERFACE") != "" { testaccInterface = os.Getenv("TESTACC_INTERFACE") @@ -23,13 +23,18 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) { } else { testaccInterfaceAE = "ae0" } + if os.Getenv("TESTACC_INTERFACE2") != "" { + testaccInterface2 = os.Getenv("TESTACC_INTERFACE2") + } else { + testaccInterface2 = "ge-0/0/4" + } if os.Getenv("TESTACC_SWITCH") != "" { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccJunosInterfacePhysicalConfigCreate(testaccInterface), + Config: testAccJunosInterfacePhysicalSWConfigCreate(testaccInterface), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", "description", "testacc_interface"), @@ -44,7 +49,7 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) { ), }, { - Config: testAccJunosInterfacePhysicalConfigUpdate(testaccInterface), + Config: testAccJunosInterfacePhysicalSWConfigUpdate(testaccInterface), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", "description", "testacc_interfaceU"), @@ -66,36 +71,102 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) { }, }) } else { + if os.Getenv("TESTACC_ROUTER") != "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosInterfacePhysicalRouterConfigCreate(testaccInterface, testaccInterfaceAE), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.0.source_address_filter.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.0.source_filtering", "true"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.0.identifier", "00:01:11:11:11:11:11:11:11:11"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.0.mode", "all-active"), + ), + }, + { + Config: testAccJunosInterfacePhysicalRouterConfigUpdate(testaccInterface, testaccInterfaceAE), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.0.identifier", "00:11:11:11:11:11:11:11:11:11"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "esi.0.mode", "all-active"), + ), + }, + { + ResourceName: "junos_interface_physical.testacc_interfaceAE", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + } + if os.Getenv("TESTACC_SRX") != "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosInterfacePhysicalSRXConfigCreate(testaccInterface, testaccInterface2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface_reth", + "parent_ether_opts.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface_reth", + "parent_ether_opts.0.redundancy_group", "1"), + ), + }, + }, + }) + } resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccJunosInterfacePhysicalFWConfigCreate(testaccInterface, testaccInterfaceAE), + Config: testAccJunosInterfacePhysicalConfigCreate(testaccInterface, testaccInterfaceAE, testaccInterface2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", "description", "testacc_interface"), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", - "ether802_3ad", testaccInterfaceAE), + "gigether_opts.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", + "gigether_opts.0.ae_8023ad", testaccInterfaceAE), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", "name", testaccInterfaceAE), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", - "ae_lacp", "active"), + "parent_ether_opts.#", "1"), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", - "ae_minimum_links", "1"), + "parent_ether_opts.0.lacp.#", "1"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.0.lacp.0.mode", "active"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.0.minimum_links", "1"), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", "vlan_tagging", "true"), ), }, { - Config: testAccJunosInterfacePhysicalFWConfigUpdate(testaccInterface, testaccInterfaceAE), + Config: testAccJunosInterfacePhysicalConfigUpdate(testaccInterface, testaccInterfaceAE, testaccInterface2), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("junos_interface_physical.testacc_interface", "description", "testacc_interfaceU"), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", - "ae_lacp", ""), + "parent_ether_opts.#", "1"), resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", - "ae_minimum_links", "0"), + "parent_ether_opts.0.lacp.#", "0"), + resource.TestCheckResourceAttr("junos_interface_physical.testacc_interfaceAE", + "parent_ether_opts.0.minimum_bandwidth", "1 gbps"), ), }, { @@ -108,13 +179,16 @@ func TestAccJunosInterfacePhysical_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccJunosInterfacePhysicalConfigUpdate2(testaccInterface, testaccInterfaceAE), + }, }, }) } } -func testAccJunosInterfacePhysicalConfigCreate(interFace string) string { - return fmt.Sprintf(` +func testAccJunosInterfacePhysicalSWConfigCreate(interFace string) string { + return ` resource junos_interface_physical testacc_interface { name = "` + interFace + `" description = "testacc_interface" @@ -122,45 +196,209 @@ resource junos_interface_physical testacc_interface { vlan_native = 100 vlan_members = ["100-110"] } -`) +` } -func testAccJunosInterfacePhysicalConfigUpdate(interFace string) string { - return fmt.Sprintf(` +func testAccJunosInterfacePhysicalSWConfigUpdate(interFace string) string { + return ` resource junos_interface_physical testacc_interface { name = "` + interFace + `" description = "testacc_interfaceU" vlan_members = ["100"] } -`) +` } -func testAccJunosInterfacePhysicalFWConfigCreate(interFace, interfaceAE string) string { - return fmt.Sprintf(` +func testAccJunosInterfacePhysicalConfigCreate(interFace, interfaceAE, interFace2 string) string { + return ` resource junos_interface_physical testacc_interface { - name = "` + interFace + `" - description = "testacc_interface" - ether802_3ad = "` + interfaceAE + `" + name = "` + interFace + `" + description = "testacc_interface" + gigether_opts { + ae_8023ad = "` + interfaceAE + `" + } } -resource junos_interface_physical testacc_interfaceAE { - name = junos_interface_physical.testacc_interface.ether802_3ad - description = "testacc_interfaceAE" - ae_lacp = "active" - ae_minimum_links = 1 - vlan_tagging = true +resource junos_interface_physical testacc_interface2 { + name = "` + interFace2 + `" + description = "testacc_interface2" + gigether_opts { + flow_control = true + loopback = true + auto_negotiation = true + } +} +resource "junos_interface_physical" "testacc_interfaceAE" { + depends_on = [ + junos_interface_physical.testacc_interface, + ] + name = "` + interfaceAE + `" + description = "testacc_interfaceAE" + parent_ether_opts { + flow_control = true + lacp { + mode = "active" + admin_key = 1 + periodic = "slow" + sync_reset = "disable" + system_id = "00:00:01:00:01:00" + system_priority = 250 + } + loopback = true + link_speed = "1g" + minimum_links = 1 + } + vlan_tagging = true } -`) +` } -func testAccJunosInterfacePhysicalFWConfigUpdate(interFace, interfaceAE string) string { - return fmt.Sprintf(` +func testAccJunosInterfacePhysicalConfigUpdate(interFace, interfaceAE, interFace2 string) string { + return ` resource junos_interface_physical testacc_interface { - name = "` + interFace + `" - description = "testacc_interfaceU" - ether802_3ad = "` + interfaceAE + `" + name = "` + interFace + `" + description = "testacc_interfaceU" + gigether_opts { + ae_8023ad = "` + interfaceAE + `" + } +} +resource junos_interface_physical testacc_interface2 { + name = "` + interFace2 + `" + description = "testacc_interface2" + ether_opts { + flow_control = true + loopback = true + auto_negotiation = true + } +} +resource "junos_interface_logical" "testacc_interfaceLO" { + name = "lo0.0" + family_inet { + address { + cidr_ip = "192.0.2.1/32" + } + } } -resource junos_interface_physical testacc_interfaceAE { - name = junos_interface_physical.testacc_interface.ether802_3ad - description = "testacc_interfaceAE" +resource "junos_interface_physical" "testacc_interfaceAE" { + depends_on = [ + junos_interface_physical.testacc_interface, + junos_interface_logical.testacc_interfaceLO, + ] + name = "` + interfaceAE + `" + description = "testacc_interfaceAE" + parent_ether_opts { + bfd_liveness_detection { + local_address = "192.0.2.1" + detection_time_threshold = 30 + holddown_interval = 30 + minimum_interval = 30 + minimum_receive_interval = 10 + multiplier = 1 + neighbor = "192.0.2.2" + no_adaptation = true + transmit_interval_minimum_interval = 10 + transmit_interval_threshold = 30 + version = "automatic" + } + no_flow_control = true + no_loopback = true + link_speed = "1g" + minimum_bandwidth = "1 gbps" + } vlan_tagging = true } -`) +` +} +func testAccJunosInterfacePhysicalConfigUpdate2(interFace, interfaceAE string) string { + return ` +resource junos_interface_physical testacc_interface { + name = "` + interFace + `" + description = "testacc_interfaceU" + ether_opts { + ae_8023ad = "` + interfaceAE + `" + } +} +` +} + +func testAccJunosInterfacePhysicalRouterConfigCreate(interFace, interfaceAE string) string { + return ` +resource "junos_interface_physical" "testacc_interface" { + name = "` + interFace + `" + description = "testacc_interface" + gigether_opts { + ae_8023ad = "` + interfaceAE + `" + } +} +resource "junos_interface_physical" "testacc_interfaceAE" { + name = "` + interfaceAE + `" + description = "testacc_interfaceAE" + esi { + identifier = "00:01:11:11:11:11:11:11:11:11" + mode = "all-active" + } + parent_ether_opts { + source_address_filter = ["00:11:22:33:44:55"] + source_filtering = true + } + vlan_tagging = true +} +` +} +func testAccJunosInterfacePhysicalRouterConfigUpdate(interFace, interfaceAE string) string { + return ` +resource "junos_interface_physical" "testacc_interface" { + name = "` + interFace + `" + description = "testacc_interface" + gigether_opts { + ae_8023ad = "` + interfaceAE + `" + } +} +resource "junos_interface_physical" "testacc_interfaceAE" { + name = "` + interfaceAE + `" + description = "testacc_interfaceAE" + esi { + identifier = "00:11:11:11:11:11:11:11:11:11" + mode = "all-active" + } + vlan_tagging = true +} +` +} + +func testAccJunosInterfacePhysicalSRXConfigCreate(interFace, interFace2 string) string { + return ` +resource "junos_interface_physical" "testacc_interface" { + depends_on = [ + junos_chassis_cluster.testacc_interface + ] + name = "` + interFace + `" + description = "testacc_interface" + gigether_opts { + redundant_parent = "reth0" + } +} +resource "junos_chassis_cluster" "testacc_interface" { + fab0 { + member_interfaces = ["` + interFace2 + `"] + } + redundancy_group { + node0_priority = 100 + node1_priority = 99 + } + redundancy_group { + node0_priority = 100 + node1_priority = 99 + } + reth_count = 1 +} +resource "junos_interface_physical" "testacc_interface_reth" { + depends_on = [ + junos_interface_physical.testacc_interface + ] + name = "reth0" + description = "testacc_interface_reth" + parent_ether_opts { + redundancy_group = 1 + minimum_links = 1 + } +} +` } diff --git a/junos/resource_interface_st0_unit.go b/junos/resource_interface_st0_unit.go index 516575ee..0ac3d1e8 100644 --- a/junos/resource_interface_st0_unit.go +++ b/junos/resource_interface_st0_unit.go @@ -33,7 +33,7 @@ func resourceInterfaceSt0UnitCreate(ctx context.Context, d *schema.ResourceData, if err != nil { sess.configClear(jnprSess) - return diag.FromErr(fmt.Errorf("error for find new st0 unit interface: %w", err)) + return diag.FromErr(fmt.Errorf("error for find new st0 unit interface : %w", err)) } if err := sess.configSet([]string{"set interfaces " + newSt0}, jnprSess); err != nil { sess.configClear(jnprSess) diff --git a/junos/resource_null_commit_file.go b/junos/resource_null_commit_file.go new file mode 100644 index 00000000..2649f996 --- /dev/null +++ b/junos/resource_null_commit_file.go @@ -0,0 +1,122 @@ +package junos + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceNullCommitFile() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceNullCommitFileCreate, + ReadContext: resourceNullCommitFileRead, + DeleteContext: resourceNullCommitFileDelete, + Schema: map[string]*schema.Schema{ + "filename": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "append_lines": { + Type: schema.TypeList, + ForceNew: true, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "clear_file_after_commit": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "triggers": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceNullCommitFileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + fileName := d.Get("filename").(string) + configSet, err := readNullCommitFile(fileName) + if err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + for _, v := range d.Get("append_lines").([]interface{}) { + configSet = append(configSet, v.(string)) + } + if err := sess.configSet(configSet, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("commit a file with resource junos_null_commit_file", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.SetId(fileName) + if d.Get("clear_file_after_commit").(bool) { + if err := cleanNullCommitFile(fileName, sess); err != nil { + return append(diagWarns, diag.FromErr(err)...) + } + } + + return diagWarns +} +func resourceNullCommitFileRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + return nil +} +func resourceNullCommitFileDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + d.SetId("") + + return nil +} + +func readNullCommitFile(filename string) ([]string, error) { + if err := replaceTildeToHomeDir(&filename); err != nil { + return []string{}, err + } + _, err := os.Stat(filename) + if os.IsNotExist(err) { + return []string{}, fmt.Errorf("file `%s` doesn't exist", filename) + } + fileReadByte, err := ioutil.ReadFile(filename) + if err != nil { + return []string{}, fmt.Errorf("could not read file `%s` : %w", filename, err) + } + + return strings.Split(string(fileReadByte), "\n"), nil +} +func cleanNullCommitFile(filename string, sess *Session) error { + if err := replaceTildeToHomeDir(&filename); err != nil { + return err + } + f, err := os.OpenFile(filename, os.O_TRUNC, os.FileMode(sess.junosFilePermission)) + if err != nil { + return fmt.Errorf("could not open file `%s` to truncate after commit : %w", filename, err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("could not close file handler for `%s` after truncation : %w", filename, err) + } + + return nil +} diff --git a/junos/resource_null_commit_file_test.go b/junos/resource_null_commit_file_test.go new file mode 100644 index 00000000..1b4ce909 --- /dev/null +++ b/junos/resource_null_commit_file_test.go @@ -0,0 +1,85 @@ +package junos_test + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testaccNullCommitFile = "/tmp/testacc/terraform-provider-junos/null-commit-file" + +func TestAccJunosNullCommitFile_basic(t *testing.T) { + var testaccInterface string + if os.Getenv("TESTACC_INTERFACE") != "" { + testaccInterface = os.Getenv("TESTACC_INTERFACE") + } else { + testaccInterface = defaultInterfaceTestAcc + } + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "local": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccJunosNullCommitFilePreCreate(testaccInterface), + }, + { + Config: testAccJunosNullCommitFileCreate(testaccInterface), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccJunosNullCommitFileRead(testaccInterface), + PlanOnly: true, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_interface_physical.testacc_nullcommitfile", + "description", "testacc_nullfile"), + resource.TestCheckResourceAttr("data.junos_interface_physical.testacc_nullcommitfile", + "description", "testacc_nullfile"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccJunosNullCommitFilePreCreate(interFace string) string { + return ` +resource junos_interface_physical testacc_nullcommitfile { + name = "` + interFace + `" + description = "testacc_null" + vlan_tagging = true +} +` +} +func testAccJunosNullCommitFileCreate(interFace string) string { + return ` +resource junos_interface_physical testacc_nullcommitfile { + name = "` + interFace + `" + description = "testacc_null" + vlan_tagging = true +} +resource "local_file" "hostname" { + content = "set interfaces ` + interFace + ` description testacc_nullfile" + filename = "` + testaccNullCommitFile + `" +} +resource junos_null_commit_file "testacc_nullcommitfile" { + filename = local_file.hostname.filename + clear_file_after_commit = true +} +` +} +func testAccJunosNullCommitFileRead(interFace string) string { + return ` +resource junos_interface_physical testacc_nullcommitfile { + name = "` + interFace + `" + description = "testacc_null" + vlan_tagging = true +} +data junos_interface_physical testacc_nullcommitfile { + config_interface = "` + interFace + `" +} +` +} diff --git a/junos/resource_ospf_area.go b/junos/resource_ospf_area.go index 6412277c..44771b34 100644 --- a/junos/resource_ospf_area.go +++ b/junos/resource_ospf_area.go @@ -38,7 +38,7 @@ func resourceOspfArea() *schema.Resource { Optional: true, ForceNew: true, Default: defaultWord, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "version": { Type: schema.TypeString, @@ -93,6 +93,15 @@ func resourceOspfArea() *schema.Resource { func resourceOspfAreaCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setOspfArea(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("area_id").(string) + idSeparator + d.Get("version").(string) + + idSeparator + d.Get("routing_instance").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -320,11 +329,8 @@ func setOspfArea(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) strconv.Itoa(ospfInterface["retransmit_interval"].(int))) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readOspfArea(idArea, version, routingInstance string, m interface{}, jnprSess *NetconfObject) (ospfAreaOptions, error) { @@ -426,11 +432,8 @@ func delOspfArea(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) configSet = append(configSet, "delete routing-instances "+d.Get("routing_instance").(string)+ " protocols "+ospfVersion+" area "+d.Get("area_id").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillOspfAreaData(d *schema.ResourceData, ospfAreaOptions ospfAreaOptions) { diff --git a/junos/resource_policyoptions_as_path.go b/junos/resource_policyoptions_as_path.go index b2463ade..8943b5f1 100644 --- a/junos/resource_policyoptions_as_path.go +++ b/junos/resource_policyoptions_as_path.go @@ -29,7 +29,7 @@ func resourcePolicyoptionsAsPath() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "dynamic_db": { Type: schema.TypeBool, @@ -45,6 +45,14 @@ func resourcePolicyoptionsAsPath() *schema.Resource { func resourcePolicyoptionsAsPathCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setPolicyoptionsAsPath(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -221,11 +229,8 @@ func setPolicyoptionsAsPath(d *schema.ResourceData, m interface{}, jnprSess *Net configSet = append(configSet, "set policy-options as-path "+d.Get("name").(string)+ " \""+d.Get("path").(string)+"\"") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readPolicyoptionsAsPath(asPath string, m interface{}, jnprSess *NetconfObject) (asPathOptions, error) { sess := m.(*Session) @@ -262,11 +267,8 @@ func delPolicyoptionsAsPath(asPath string, m interface{}, jnprSess *NetconfObjec sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete policy-options as-path "+asPath) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillPolicyoptionsAsPathData(d *schema.ResourceData, asPathOptions asPathOptions) { if tfErr := d.Set("name", asPathOptions.name); tfErr != nil { diff --git a/junos/resource_policyoptions_as_path_group.go b/junos/resource_policyoptions_as_path_group.go index 26a971d1..c66cd838 100644 --- a/junos/resource_policyoptions_as_path_group.go +++ b/junos/resource_policyoptions_as_path_group.go @@ -29,7 +29,7 @@ func resourcePolicyoptionsAsPathGroup() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "as_path": { Type: schema.TypeList, @@ -39,7 +39,7 @@ func resourcePolicyoptionsAsPathGroup() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "path": { Type: schema.TypeString, @@ -59,6 +59,14 @@ func resourcePolicyoptionsAsPathGroup() *schema.Resource { func resourcePolicyoptionsAsPathGroupCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setPolicyoptionsAsPathGroup(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -240,11 +248,8 @@ func setPolicyoptionsAsPathGroup(d *schema.ResourceData, m interface{}, jnprSess if d.Get("dynamic_db").(bool) { configSet = append(configSet, setPrefix+" dynamic-db") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readPolicyoptionsAsPathGroup(asPathGroup string, m interface{}, jnprSess *NetconfObject) (asPathGroupOptions, error) { @@ -290,11 +295,8 @@ func delPolicyoptionsAsPathGroup(asPathGroup string, m interface{}, jnprSess *Ne sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete policy-options as-path-group "+asPathGroup) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillPolicyoptionsAsPathGroupData(d *schema.ResourceData, asPathGroupOptions asPathGroupOptions) { if tfErr := d.Set("name", asPathGroupOptions.name); tfErr != nil { diff --git a/junos/resource_policyoptions_community.go b/junos/resource_policyoptions_community.go index 1cdb50f9..50ec9876 100644 --- a/junos/resource_policyoptions_community.go +++ b/junos/resource_policyoptions_community.go @@ -29,7 +29,7 @@ func resourcePolicyoptionsCommunity() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "members": { Type: schema.TypeList, @@ -47,6 +47,14 @@ func resourcePolicyoptionsCommunity() *schema.Resource { func resourcePolicyoptionsCommunityCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setPolicyoptionsCommunity(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -222,11 +230,8 @@ func setPolicyoptionsCommunity(d *schema.ResourceData, m interface{}, jnprSess * if d.Get("invert_match").(bool) { configSet = append(configSet, setPrefix+"invert-match") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readPolicyoptionsCommunity(community string, m interface{}, jnprSess *NetconfObject) (communityOptions, error) { sess := m.(*Session) @@ -263,11 +268,8 @@ func delPolicyoptionsCommunity(community string, m interface{}, jnprSess *Netcon sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete policy-options community "+community) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillPolicyoptionsCommunityData(d *schema.ResourceData, communityOptions communityOptions) { if tfErr := d.Set("name", communityOptions.name); tfErr != nil { diff --git a/junos/resource_policyoptions_policy_statement.go b/junos/resource_policyoptions_policy_statement.go index 6c0b73d8..cafc2593 100644 --- a/junos/resource_policyoptions_policy_statement.go +++ b/junos/resource_policyoptions_policy_statement.go @@ -33,7 +33,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "from": { Type: schema.TypeList, @@ -69,7 +69,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "inet", "inet-mdt", "inet-mvpn", "inet-vpn", + "evpn", "inet", "inet-mdt", "inet-mvpn", "inet-vpn", "inet6", "inet6-mvpn", "inet6-vpn", "iso"}, false), }, @@ -296,7 +296,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "inet", "inet-mdt", "inet-mvpn", "inet-vpn", + "evpn", "inet", "inet-mdt", "inet-mvpn", "inet-vpn", "inet6", "inet6-mvpn", "inet6-vpn", "iso"}, false), }, @@ -356,7 +356,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "from": { Type: schema.TypeList, @@ -392,7 +392,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "inet", "inet-mdt", "inet-mvpn", "inet-vpn", + "evpn", "inet", "inet-mdt", "inet-mvpn", "inet-vpn", "inet6", "inet6-mvpn", "inet6-vpn", "iso"}, false), }, @@ -619,7 +619,7 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "inet", "inet-mdt", "inet-mvpn", "inet-vpn", + "evpn", "inet", "inet-mdt", "inet-mvpn", "inet-vpn", "inet6", "inet6-mvpn", "inet6-vpn", "iso"}, false), }, @@ -681,6 +681,14 @@ func resourcePolicyoptionsPolicyStatement() *schema.Resource { func resourcePolicyoptionsPolicyStatementCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setPolicyStatement(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -895,11 +903,7 @@ func setPolicyStatement(d *schema.ResourceData, m interface{}, jnprSess *Netconf } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readPolicyStatement(policyStatement string, m interface{}, jnprSess *NetconfObject) (policyStatementOptions, error) { @@ -979,11 +983,8 @@ func delPolicyStatement(policyStatement string, m interface{}, jnprSess *Netconf sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete policy-options policy-statement "+policyStatement) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillPolicyStatementData(d *schema.ResourceData, policyStatementOptions policyStatementOptions) { if tfErr := d.Set("name", policyStatementOptions.name); tfErr != nil { diff --git a/junos/resource_policyoptions_prefix_list.go b/junos/resource_policyoptions_prefix_list.go index 04e962b5..25359eab 100644 --- a/junos/resource_policyoptions_prefix_list.go +++ b/junos/resource_policyoptions_prefix_list.go @@ -30,7 +30,7 @@ func resourcePolicyoptionsPrefixList() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "apply_path": { Type: schema.TypeString, @@ -41,7 +41,7 @@ func resourcePolicyoptionsPrefixList() *schema.Resource { Optional: true, }, "prefix": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -52,6 +52,14 @@ func resourcePolicyoptionsPrefixList() *schema.Resource { func resourcePolicyoptionsPrefixListCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setPolicyoptionsPrefixList(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -233,7 +241,7 @@ func setPolicyoptionsPrefixList(d *schema.ResourceData, m interface{}, jnprSess if d.Get("dynamic_db").(bool) { configSet = append(configSet, setPrefix+" dynamic-db") } - for _, v := range d.Get("prefix").([]interface{}) { + for _, v := range d.Get("prefix").(*schema.Set).List() { err := validateCIDRNetwork(v.(string)) if err != nil { return err @@ -241,11 +249,7 @@ func setPolicyoptionsPrefixList(d *schema.ResourceData, m interface{}, jnprSess configSet = append(configSet, setPrefix+" "+v.(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readPolicyoptionsPrefixList(prefixList string, m interface{}, jnprSess *NetconfObject) (prefixListOptions, error) { sess := m.(*Session) @@ -286,11 +290,8 @@ func delPolicyoptionsPrefixList(prefixList string, m interface{}, jnprSess *Netc sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete policy-options prefix-list "+prefixList) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillPolicyoptionsPrefixListData(d *schema.ResourceData, prefixListOptions prefixListOptions) { if tfErr := d.Set("name", prefixListOptions.name); tfErr != nil { diff --git a/junos/resource_rib_group.go b/junos/resource_rib_group.go index a22e063b..86283fbd 100644 --- a/junos/resource_rib_group.go +++ b/junos/resource_rib_group.go @@ -30,7 +30,7 @@ func resourceRibGroup() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "import_policy": { Type: schema.TypeList, @@ -55,6 +55,14 @@ func resourceRibGroupCreate(ctx context.Context, d *schema.ResourceData, m inter return diag.FromErr(err) } sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setRibGroup(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -251,11 +259,8 @@ func setRibGroup(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) if d.Get("export_rib").(string) != "" { configSet = append(configSet, setPrefix+"export-rib "+d.Get("export_rib").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readRibGroup(group string, m interface{}, jnprSess *NetconfObject) (ribGroupOptions, error) { sess := m.(*Session) @@ -293,21 +298,15 @@ func delRibGroupElement(element string, group string, m interface{}, jnprSess *N sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete routing-options rib-groups "+group+" "+element) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delRibGroup(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete routing-options rib-groups "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func validateRibGroup(d *schema.ResourceData) error { diff --git a/junos/resource_routing_instance.go b/junos/resource_routing_instance.go index a5458351..085e2b5a 100644 --- a/junos/resource_routing_instance.go +++ b/junos/resource_routing_instance.go @@ -29,7 +29,7 @@ func resourceRoutingInstance() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{"default"}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{"default"}, 64, FormatDefault), }, "type": { Type: schema.TypeString, @@ -46,6 +46,14 @@ func resourceRoutingInstance() *schema.Resource { func resourceRoutingInstanceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setRoutingInstance(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -222,11 +230,8 @@ func setRoutingInstance(d *schema.ResourceData, m interface{}, jnprSess *Netconf configSet = append(configSet, setPrefix+ "routing-options autonomous-system "+d.Get("as").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readRoutingInstance(instance string, m interface{}, jnprSess *NetconfObject) (instanceOptions, error) { sess := m.(*Session) @@ -265,21 +270,15 @@ func delRoutingInstanceOpts(d *schema.ResourceData, m interface{}, jnprSess *Net configSet = append(configSet, setPrefix+"instance-type", setPrefix+"routing-options autonomous-system") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delRoutingInstance(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete routing-instances "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillRoutingInstanceData(d *schema.ResourceData, instanceOptions instanceOptions) { diff --git a/junos/resource_routing_options.go b/junos/resource_routing_options.go index fc5517a6..392f3873 100644 --- a/junos/resource_routing_options.go +++ b/junos/resource_routing_options.go @@ -72,6 +72,14 @@ func resourceRoutingOptions() *schema.Resource { func resourceRoutingOptionsCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setRoutingOptions(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("routing_options") + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -201,11 +209,7 @@ func setRoutingOptions(d *schema.ResourceData, m interface{}, jnprSess *NetconfO } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func delRoutingOptions(m interface{}, jnprSess *NetconfObject) error { @@ -220,11 +224,8 @@ func delRoutingOptions(m interface{}, jnprSess *NetconfObject) error { configSet = append(configSet, delPrefix+line) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readRoutingOptions(m interface{}, jnprSess *NetconfObject) (routingOptionsOptions, error) { sess := m.(*Session) diff --git a/junos/resource_security.go b/junos/resource_security.go index 0544b62a..2ce86a73 100644 --- a/junos/resource_security.go +++ b/junos/resource_security.go @@ -576,6 +576,32 @@ func resourceSecurity() *schema.Resource { "juniper-enhanced", "juniper-local", "web-filtering-none", "websense-redirect", }, false), }, + "feature_profile_web_filtering_juniper_enhanced_server": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host": { + Type: schema.TypeString, + Optional: true, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 65535), + }, + "proxy_profile": { + Type: schema.TypeString, + Optional: true, + }, + "routing_instance": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, }, }, }, @@ -585,6 +611,14 @@ func resourceSecurity() *schema.Resource { func resourceSecurityCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurity(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("security") + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -735,15 +769,33 @@ func setSecurity(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) configSet = append(configSet, setPrefix+"utm feature-profile web-filtering type "+ utm["feature_profile_web_filtering_type"].(string)) } + for _, v2 := range utm["feature_profile_web_filtering_juniper_enhanced_server"].([]interface{}) { + configSet = append(configSet, setPrefix+"utm feature-profile web-filtering juniper-enhanced server") + if v2 != nil { + utmJnpEnhServer := v2.(map[string]interface{}) + if v3 := utmJnpEnhServer["host"].(string); v3 != "" { + configSet = append(configSet, setPrefix+"utm feature-profile web-filtering juniper-enhanced server host "+v3) + } + if v3 := utmJnpEnhServer["port"].(int); v3 != 0 { + configSet = append(configSet, + setPrefix+"utm feature-profile web-filtering juniper-enhanced server port "+strconv.Itoa(v3)) + } + if v3 := utmJnpEnhServer["proxy_profile"].(string); v3 != "" { + configSet = append(configSet, + setPrefix+"utm feature-profile web-filtering juniper-enhanced server proxy-profile \""+v3+"\"") + } + if v3 := utmJnpEnhServer["routing_instance"].(string); v3 != "" { + configSet = append(configSet, + setPrefix+"utm feature-profile web-filtering juniper-enhanced server routing-instance "+v3) + } + } + } } else { return fmt.Errorf("utm block is empty") } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func setSecurityAlg(alg interface{}) ([]string, error) { @@ -1212,6 +1264,7 @@ func listLinesSecurityLog() []string { func listLinesSecurityUtm() []string { return []string{ "utm feature-profile web-filtering type", + "utm feature-profile web-filtering juniper-enhanced server", } } @@ -1231,11 +1284,8 @@ func delSecurity(m interface{}, jnprSess *NetconfObject) error { configSet = append(configSet, delPrefix+line) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurity(m interface{}, jnprSess *NetconfObject) (securityOptions, error) { sess := m.(*Session) @@ -1277,14 +1327,9 @@ func readSecurity(m interface{}, jnprSess *NetconfObject) (securityOptions, erro return confRead, err } case checkStringHasPrefixInList(itemTrim, listLinesSecurityUtm()): - if len(confRead.utm) == 0 { - confRead.utm = append(confRead.utm, map[string]interface{}{ - "feature_profile_web_filtering_type": "", - }) - } - if strings.HasPrefix(itemTrim, "utm feature-profile web-filtering type ") { - confRead.utm[0]["feature_profile_web_filtering_type"] = strings.TrimPrefix(itemTrim, - "utm feature-profile web-filtering type ") + err := readSecurityUtm(&confRead, itemTrim) + if err != nil { + return confRead, err } } } @@ -1809,6 +1854,52 @@ func readSecurityLog(confRead *securityOptions, itemTrimLog string) error { return nil } +func readSecurityUtm(confRead *securityOptions, itemTrimUtm string) error { + if len(confRead.utm) == 0 { + confRead.utm = append(confRead.utm, map[string]interface{}{ + "feature_profile_web_filtering_type": "", + "feature_profile_web_filtering_juniper_enhanced_server": make([]map[string]interface{}, 0), + }) + } + switch { + case strings.HasPrefix(itemTrimUtm, "utm feature-profile web-filtering type "): + confRead.utm[0]["feature_profile_web_filtering_type"] = strings.TrimPrefix(itemTrimUtm, + "utm feature-profile web-filtering type ") + case strings.HasPrefix(itemTrimUtm, "utm feature-profile web-filtering juniper-enhanced server"): + if len(confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{})) == 0 { + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"] = append( + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{}), + map[string]interface{}{ + "host": "", + "port": 0, + "proxy_profile": "", + "routing_instance": "", + }) + } + itemTrimServer := strings.TrimPrefix(itemTrimUtm, "utm feature-profile web-filtering juniper-enhanced server") + switch { + case strings.HasPrefix(itemTrimServer, " host "): + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{})[0]["host"] = + strings.TrimPrefix(itemTrimServer, " host ") + case strings.HasPrefix(itemTrimServer, " port "): + var err error + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{})[0]["port"], err = + strconv.Atoi(strings.TrimPrefix(itemTrimServer, " port ")) + if err != nil { + return fmt.Errorf("failed to convert value from '%s' to integer : %w", itemTrimUtm, err) + } + case strings.HasPrefix(itemTrimServer, " proxy-profile "): + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{})[0]["proxy_profile"] = //nolint: lll + strings.Trim(strings.TrimPrefix(itemTrimServer, " proxy-profile "), "\"") + case strings.HasPrefix(itemTrimServer, " routing-instance "): + confRead.utm[0]["feature_profile_web_filtering_juniper_enhanced_server"].([]map[string]interface{})[0]["routing_instance"] = //nolint: lll + strings.TrimPrefix(itemTrimServer, " routing-instance ") + } + } + + return nil +} + func fillSecurity(d *schema.ResourceData, securityOptions securityOptions) { if tfErr := d.Set("alg", securityOptions.alg); tfErr != nil { panic(tfErr) diff --git a/junos/resource_security_address_book.go b/junos/resource_security_address_book.go new file mode 100644 index 00000000..3b12738e --- /dev/null +++ b/junos/resource_security_address_book.go @@ -0,0 +1,542 @@ +package junos + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +type addressBookOptions struct { + name string + description string + attachZone []string + networkAddress []map[string]interface{} + wildcardAddress []map[string]interface{} + dnsName []map[string]interface{} + rangeAddress []map[string]interface{} + addressSet []map[string]interface{} +} + +func resourceSecurityAddressBook() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceSecurityAddressBookCreate, + ReadContext: resourceSecurityAddressBookRead, + UpdateContext: resourceSecurityAddressBookUpdate, + DeleteContext: resourceSecurityAddressBookDelete, + Importer: &schema.ResourceImporter{ + State: resourceSecurityAddressBookImport, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "global", + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "attach_zone": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "network_address": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsCIDRNetwork(0, 128), + }, + }, + }, + }, + "wildcard_address": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateWildcardFunc(), + }, + }, + }, + }, + "dns_name": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "range_address": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "from": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsIPAddress, + }, + "to": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsIPAddress, + }, + }, + }, + }, + "address_set": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), + }, + "address": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func resourceSecurityAddressBookCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setAddressBook(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + if !checkCompatibilitySecurity(jnprSess) { + return diag.FromErr(fmt.Errorf("security policy not compatible with Junos device %s", + jnprSess.SystemInformation.HardwareModel)) + } + sess.configLock(jnprSess) + addressBookExists, err := checkAddressBookExists(d.Get("name").(string), m, jnprSess) + if err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if addressBookExists { + sess.configClear(jnprSess) + + return diag.FromErr(fmt.Errorf("security address book %v already exists", d.Get("name").(string))) + } + if err := setAddressBook(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("create resource junos_security_address_book", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + addressBookExists, err = checkAddressBookExists(d.Get("name").(string), m, jnprSess) + if err != nil { + return append(diagWarns, diag.FromErr(err)...) + } + if addressBookExists { + d.SetId(d.Get("name").(string)) + } else { + return append(diagWarns, diag.FromErr(fmt.Errorf("security address book %v does not exists after commit "+ + "=> check your config", d.Get("name").(string)))...) + } + + return append(diagWarns, resourceSecurityAddressBookReadWJnprSess(d, m, jnprSess)...) +} + +func resourceSecurityAddressBookRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + + return resourceSecurityAddressBookReadWJnprSess(d, m, jnprSess) +} +func resourceSecurityAddressBookReadWJnprSess(d *schema.ResourceData, m interface{}, + jnprSess *NetconfObject) diag.Diagnostics { + mutex.Lock() + addressOptions, err := readSecurityAddressBook(d.Get("name").(string), m, jnprSess) + mutex.Unlock() + if err != nil { + return diag.FromErr(err) + } + if addressOptions.name == "" { + d.SetId("") + } else { + fillAddressBookData(d, addressOptions) + } + + return nil +} + +func resourceSecurityAddressBookUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + d.Partial(true) + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + + if err := delSecurityAddressBook(d.Get("name").(string), m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + + if err := setAddressBook(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("update resource junos_security_address_book", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.Partial(false) + + return append(diagWarns, resourceSecurityAddressBookReadWJnprSess(d, m, jnprSess)...) +} + +func resourceSecurityAddressBookDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delSecurityAddressBook(d.Get("name").(string), m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("delete resource junos_security_address_book", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + + return diagWarns +} + +func resourceSecurityAddressBookImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return nil, err + } + defer sess.closeSession(jnprSess) + result := make([]*schema.ResourceData, 1) + securityAddressBookExists, err := checkAddressBookExists(d.Id(), m, jnprSess) + if err != nil { + return nil, err + } + if !securityAddressBookExists { + return nil, fmt.Errorf("don't find address book with id '%v' (id must be )", d.Id()) + } + addressOptions, err := readSecurityAddressBook(d.Id(), m, jnprSess) + if err != nil { + return nil, err + } + fillAddressBookData(d, addressOptions) + + result[0] = d + + return result, nil +} + +func checkAddressBookExists(addrBook string, m interface{}, jnprSess *NetconfObject) (bool, error) { + sess := m.(*Session) + + addrBookConfig, err := sess.command("show configuration security address-book "+addrBook+ + " | display set", jnprSess) + if err != nil { + return false, err + } + if addrBookConfig == emptyWord { + return false, nil + } + + return true, nil +} + +func setAddressBook(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + setPrefix := "set security address-book " + d.Get("name").(string) + + if d.Get("description").(string) != "" { + configSet = append(configSet, setPrefix+" description \""+d.Get("description").(string)+"\"") + } + for _, v := range d.Get("attach_zone").([]interface{}) { + if d.Get("name").(string) == "global" { + return fmt.Errorf("cannot attach global address book to a zone") + } + attachZone := v.(string) + configSet = append(configSet, setPrefix+" attach zone "+attachZone) + } + for _, v := range d.Get("network_address").([]interface{}) { + address := v.(map[string]interface{}) + setPrefixAddr := setPrefix + " address " + address["name"].(string) + " " + if address["description"].(string) != "" { + configSet = append(configSet, setPrefixAddr+"description \""+address["description"].(string)+"\"") + } + configSet = append(configSet, setPrefixAddr+address["value"].(string)) + } + for _, v := range d.Get("wildcard_address").([]interface{}) { + address := v.(map[string]interface{}) + setPrefixAddr := setPrefix + " address " + address["name"].(string) + if address["description"].(string) != "" { + configSet = append(configSet, setPrefixAddr+"description \""+address["description"].(string)+"\"") + } + configSet = append(configSet, setPrefixAddr+" wildcard-address "+address["value"].(string)) + } + for _, v := range d.Get("dns_name").([]interface{}) { + address := v.(map[string]interface{}) + setPrefixAddr := setPrefix + " address " + address["name"].(string) + if address["description"].(string) != "" { + configSet = append(configSet, setPrefixAddr+"description \""+address["description"].(string)+"\"") + } + configSet = append(configSet, setPrefixAddr+" dns-name "+address["value"].(string)) + } + for _, v := range d.Get("range_address").([]interface{}) { + address := v.(map[string]interface{}) + setPrefixAddr := setPrefix + " address " + address["name"].(string) + if address["description"].(string) != "" { + configSet = append(configSet, setPrefixAddr+"description \""+address["description"].(string)+"\"") + } + configSet = append(configSet, setPrefixAddr+" range-address "+address["from"].(string)+" to "+address["to"].(string)) + } + for _, v := range d.Get("address_set").([]interface{}) { + addressSet := v.(map[string]interface{}) + setPrefixAddrSet := setPrefix + " address-set " + addressSet["name"].(string) + if addressSet["description"].(string) != "" { + configSet = append(configSet, setPrefixAddrSet+"description \""+addressSet["description"].(string)+"\"") + } + for _, addr := range addressSet["address"].([]interface{}) { + configSet = append(configSet, setPrefixAddrSet+" address "+addr.(string)) + } + } + + return sess.configSet(configSet, jnprSess) +} + +func readSecurityAddressBook(addrBook string, m interface{}, jnprSess *NetconfObject) (addressBookOptions, error) { + sess := m.(*Session) + var confRead addressBookOptions + + securityAddressBookConfig, err := sess.command("show configuration security address-book "+addrBook+ + " | display set relative", jnprSess) + if err != nil { + return confRead, err + } + descMap := make(map[string]string) + if securityAddressBookConfig != emptyWord { + confRead.name = addrBook + for _, item := range strings.Split(securityAddressBookConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + switch { + case strings.HasPrefix(itemTrim, "description "): + confRead.description = strings.Trim(strings.TrimPrefix(itemTrim, "description "), "\"") + case strings.HasPrefix(itemTrim, "address "): + addressSplit := strings.Split(itemTrim, " ") + itemTrimAddress := strings.TrimPrefix(itemTrim, "address "+addressSplit[1]+" ") + switch { + case strings.HasPrefix(itemTrimAddress, "description "): + descMap[addressSplit[1]] = strings.Trim(strings.TrimPrefix(itemTrimAddress, "description "), "\"") + case strings.HasPrefix(itemTrimAddress, "wildcard-address "): + confRead.wildcardAddress = append(confRead.wildcardAddress, map[string]interface{}{ + "name": addressSplit[1], + "description": descMap[addressSplit[1]], + "value": strings.TrimPrefix(itemTrimAddress, "wildcard-address "), + }) + case strings.HasPrefix(itemTrimAddress, "range-address "): + rangeAddr := strings.TrimPrefix(itemTrimAddress, "range-address ") + addresses := strings.Split(rangeAddr, " ") + confRead.rangeAddress = append(confRead.rangeAddress, map[string]interface{}{ + "name": addressSplit[1], + "description": descMap[addressSplit[1]], + "from": addresses[0], + "to": addresses[2], + }) + case strings.HasPrefix(itemTrimAddress, "dns-name "): + confRead.dnsName = append(confRead.dnsName, map[string]interface{}{ + "name": addressSplit[1], + "description": descMap[addressSplit[1]], + "value": strings.TrimPrefix(itemTrimAddress, "dns-name "), + }) + default: + confRead.networkAddress = append(confRead.networkAddress, map[string]interface{}{ + "name": addressSplit[1], + "description": descMap[addressSplit[1]], + "value": itemTrimAddress, + }) + } + case strings.HasPrefix(itemTrim, "address-set "): + addressSetSplit := strings.Split(strings.TrimPrefix(itemTrim, "address-set "), " ") + m := map[string]interface{}{ + "name": addressSetSplit[0], + "address": make([]string, 0), + "description": "", + } + m, confRead.addressSet = copyAndRemoveItemMapList("name", false, m, confRead.addressSet) + if addressSetSplit[1] == "description" { + m["description"] = strings.Trim(strings.TrimPrefix( + itemTrim, "address-set "+addressSetSplit[0]+" description "), "\"") + } else { + m["address"] = append(m["address"].([]string), addressSetSplit[2]) + } + confRead.addressSet = append(confRead.addressSet, m) + case strings.HasPrefix(itemTrim, "attach zone"): + confRead.attachZone = append(confRead.attachZone, strings.TrimPrefix(itemTrim, "attach zone ")) + } + } + } + confRead.networkAddress = copyAddressDescriptions(descMap, confRead.networkAddress) + confRead.dnsName = copyAddressDescriptions(descMap, confRead.dnsName) + confRead.rangeAddress = copyAddressDescriptions(descMap, confRead.rangeAddress) + confRead.wildcardAddress = copyAddressDescriptions(descMap, confRead.wildcardAddress) + + return confRead, nil +} + +func delSecurityAddressBook(addrBook string, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0, 1) + configSet = append(configSet, "delete security address-book "+addrBook) + + return sess.configSet(configSet, jnprSess) +} + +func fillAddressBookData(d *schema.ResourceData, addressOptions addressBookOptions) { + if tfErr := d.Set("name", addressOptions.name); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("description", addressOptions.description); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("attach_zone", addressOptions.attachZone); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("network_address", addressOptions.networkAddress); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("wildcard_address", addressOptions.wildcardAddress); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("dns_name", addressOptions.dnsName); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("range_address", addressOptions.rangeAddress); tfErr != nil { + panic(tfErr) + } + if tfErr := d.Set("address_set", addressOptions.addressSet); tfErr != nil { + panic(tfErr) + } +} + +func copyAddressDescriptions(descMap map[string]string, + addrList []map[string]interface{}) (newList []map[string]interface{}) { + for _, ele := range addrList { + ele["description"] = descMap[ele["name"].(string)] + newList = append(newList, ele) + } + + return newList +} diff --git a/junos/resource_security_address_book_test.go b/junos/resource_security_address_book_test.go new file mode 100644 index 00000000..c592ecbc --- /dev/null +++ b/junos/resource_security_address_book_test.go @@ -0,0 +1,177 @@ +package junos_test + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccJunosSecurityAddressBook_basic(t *testing.T) { + if os.Getenv("TESTACC_SWITCH") == "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosSecurityAddressBookConfigCreate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "name", "global"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "description", "testacc global description"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.#", "2"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.0.name", "testacc_network"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.0.description", "testacc_network description"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.0.value", "10.0.0.0/24"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.1.name", "testacc_network2"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.1.description", "testacc_network description2"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.1.value", "10.1.0.0/24"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "wildcard_address.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "wildcard_address.0.value", "10.0.0.0/255.255.0.255"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "wildcard_address.0.name", "testacc_wildcard"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "range_address.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "range_address.0.name", "testacc_range"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "range_address.0.from", "10.1.1.1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "range_address.0.to", "10.1.1.5"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "dns_name.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "dns_name.0.name", "testacc_dns"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "dns_name.0.value", "google.com"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "address_set.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "address_set.0.address.#", "3"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "name", "testacc_secAddrBook"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "attach_zone.#", "2"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "attach_zone.0", "testacc_secZoneAddr1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "attach_zone.1", "testacc_secZoneAddr2"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "network_address.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "network_address.0.name", "testacc_network"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "network_address.0.value", "10.1.2.3/32"), + ), + }, + { + Config: testAccJunosSecurityAddressBookConfigUpdate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityGlobalAddressBook", + "network_address.0.value", "10.1.0.0/24"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "network_address.#", "1"), + resource.TestCheckResourceAttr("junos_security_address_book.testacc_securityNamedAddressBook", + "network_address.0.value", "10.1.2.4/32"), + ), + }, + { + ResourceName: "junos_security_address_book.testacc_securityGlobalAddressBook", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + } +} + +func testAccJunosSecurityAddressBookConfigCreate() string { + return ` +resource "junos_security_zone" "testacc_secZoneAddr1" { + name = "testacc_secZoneAddr1" +} +resource "junos_security_zone" "testacc_secZoneAddr2" { + name = "testacc_secZoneAddr2" +} + +resource "junos_security_address_book" "testacc_securityGlobalAddressBook" { + description = "testacc global description" + network_address { + name = "testacc_network" + description = "testacc_network description" + value = "10.0.0.0/24" + } + wildcard_address { + name = "testacc_wildcard" + value = "10.0.0.0/255.255.0.255" + } + network_address { + name = "testacc_network2" + description = "testacc_network description2" + value = "10.1.0.0/24" + } + range_address { + name = "testacc_range" + from = "10.1.1.1" + to = "10.1.1.5" + } + dns_name { + name = "testacc_dns" + value = "google.com" + } + address_set { + name = "testacc_addressSet" + address = ["testacc_network", "testacc_wildcard", "testacc_network2"] + } +} + +resource "junos_security_address_book" "testacc_securityNamedAddressBook" { + name = "testacc_secAddrBook" + attach_zone = [junos_security_zone.testacc_secZoneAddr1.name, junos_security_zone.testacc_secZoneAddr2.name] + network_address { + name = "testacc_network" + value = "10.1.2.3/32" + } +} +` +} + +func testAccJunosSecurityAddressBookConfigUpdate() string { + return ` +resource "junos_security_zone" "testacc_secZoneAddr1" { + name = "testacc_secZoneAddr1" +} +resource "junos_security_zone" "testacc_secZoneAddr2" { + name = "testacc_secZoneAddr2" +} + +resource junos_security_address_book "testacc_securityGlobalAddressBook" { + description = "testacc global description" + network_address { + name = "testacc_network" + description = "testacc_network description" + value = "10.1.0.0/24" + } +} + +resource junos_security_address_book "testacc_securityNamedAddressBook" { + name = "testacc_secAddrBook" + network_address { + name = "testacc_network" + value = "10.1.2.4/32" + } +} +` +} diff --git a/junos/resource_security_global_policy.go b/junos/resource_security_global_policy.go new file mode 100644 index 00000000..b1c48fa6 --- /dev/null +++ b/junos/resource_security_global_policy.go @@ -0,0 +1,617 @@ +package junos + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +type globalPolicyOptions struct { + policy []map[string]interface{} +} + +func resourceSecurityGlobalPolicy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceSecurityGlobalPolicyCreate, + ReadContext: resourceSecurityGlobalPolicyRead, + UpdateContext: resourceSecurityGlobalPolicyUpdate, + DeleteContext: resourceSecurityGlobalPolicyDelete, + Importer: &schema.ResourceImporter{ + State: resourceSecurityGlobalPolicyImport, + }, + Schema: map[string]*schema.Schema{ + "policy": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), + }, + "match_source_address": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "match_destination_address": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "match_application": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "match_from_zone": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "match_to_zone": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "then": { + Type: schema.TypeString, + Optional: true, + Default: permitWord, + ValidateFunc: validation.StringInSlice([]string{permitWord, "reject", "deny"}, false), + }, + "count": { + Type: schema.TypeBool, + Optional: true, + }, + "log_init": { + Type: schema.TypeBool, + Optional: true, + }, + "log_close": { + Type: schema.TypeBool, + Optional: true, + }, + "permit_application_services": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "application_firewall_rule_set": { + Type: schema.TypeString, + Optional: true, + }, + "application_traffic_control_rule_set": { + Type: schema.TypeString, + Optional: true, + }, + "gprs_gtp_profile": { + Type: schema.TypeString, + Optional: true, + }, + "gprs_sctp_profile": { + Type: schema.TypeString, + Optional: true, + }, + "idp": { + Type: schema.TypeBool, + Optional: true, + }, + "redirect_wx": { + Type: schema.TypeBool, + Optional: true, + }, + "reverse_redirect_wx": { + Type: schema.TypeBool, + Optional: true, + }, + "security_intelligence_policy": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_proxy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "profile_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "uac_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "captive_portal": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "utm_policy": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourceSecurityGlobalPolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityGlobalPolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("security_global_policy") + + return nil + } + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + if !checkCompatibilitySecurity(jnprSess) { + return diag.FromErr(fmt.Errorf("security policies global not compatible with Junos device %s", + jnprSess.SystemInformation.HardwareModel)) + } + sess.configLock(jnprSess) + glbPolicy, err := readSecurityGlobalPolicy(m, jnprSess) + if err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + if len(glbPolicy.policy) != 0 { + sess.configClear(jnprSess) + + return diag.FromErr(fmt.Errorf("security policies global already set")) + } + + if err := setSecurityGlobalPolicy(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("create resource junos_security_global_policy", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.SetId("security_global_policy") + + return append(diagWarns, resourceSecurityGlobalPolicyReadWJnprSess(d, m, jnprSess)...) +} +func resourceSecurityGlobalPolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + + return resourceSecurityGlobalPolicyReadWJnprSess(d, m, jnprSess) +} +func resourceSecurityGlobalPolicyReadWJnprSess( + d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) diag.Diagnostics { + mutex.Lock() + globalPolicyOptions, err := readSecurityGlobalPolicy(m, jnprSess) + mutex.Unlock() + if err != nil { + return diag.FromErr(err) + } + fillSecurityGlobalPolicyData(d, globalPolicyOptions) + + return nil +} +func resourceSecurityGlobalPolicyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + d.Partial(true) + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + + if err := delSecurityGlobalPolicy(m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + + if err := setSecurityGlobalPolicy(d, m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("update resource junos_security_global_policy", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + d.Partial(false) + + return append(diagWarns, resourceSecurityGlobalPolicyReadWJnprSess(d, m, jnprSess)...) +} +func resourceSecurityGlobalPolicyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return diag.FromErr(err) + } + defer sess.closeSession(jnprSess) + sess.configLock(jnprSess) + if err := delSecurityGlobalPolicy(m, jnprSess); err != nil { + sess.configClear(jnprSess) + + return diag.FromErr(err) + } + var diagWarns diag.Diagnostics + warns, err := sess.commitConf("delete resource junos_security_global_policy", jnprSess) + appendDiagWarns(&diagWarns, warns) + if err != nil { + sess.configClear(jnprSess) + + return append(diagWarns, diag.FromErr(err)...) + } + + return diagWarns +} +func resourceSecurityGlobalPolicyImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + sess := m.(*Session) + jnprSess, err := sess.startNewSession() + if err != nil { + return nil, err + } + defer sess.closeSession(jnprSess) + result := make([]*schema.ResourceData, 1) + globalPolicyOptions, err := readSecurityGlobalPolicy(m, jnprSess) + if err != nil { + return nil, err + } + fillSecurityGlobalPolicyData(d, globalPolicyOptions) + result[0] = d + + return result, nil +} + +func setSecurityGlobalPolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0) + + setPrefix := "set security policies global policy " + for _, v := range d.Get("policy").([]interface{}) { + policy := v.(map[string]interface{}) + setPrefixPolicy := setPrefix + policy["name"].(string) + if len(policy["match_source_address"].([]interface{})) != 0 { + for _, address := range policy["match_source_address"].([]interface{}) { + configSet = append(configSet, setPrefixPolicy+" match source-address "+address.(string)) + } + } else { + configSet = append(configSet, setPrefixPolicy+" match source-address any") + } + if len(policy["match_destination_address"].([]interface{})) != 0 { + for _, address := range policy["match_destination_address"].([]interface{}) { + configSet = append(configSet, setPrefixPolicy+" match destination-address "+address.(string)) + } + } else { + configSet = append(configSet, setPrefixPolicy+" match destination-address any") + } + if len(policy["match_application"].([]interface{})) != 0 { + for _, app := range policy["match_application"].([]interface{}) { + configSet = append(configSet, setPrefixPolicy+" match application "+app.(string)) + } + } else { + configSet = append(configSet, setPrefixPolicy+" match application any") + } + for _, v := range policy["match_from_zone"].([]interface{}) { + configSet = append(configSet, setPrefixPolicy+" match from-zone "+v.(string)) + } + for _, v := range policy["match_to_zone"].([]interface{}) { + configSet = append(configSet, setPrefixPolicy+" match to-zone "+v.(string)) + } + configSet = append(configSet, setPrefixPolicy+" then "+policy["then"].(string)) + if policy["count"].(bool) { + configSet = append(configSet, setPrefixPolicy+" then count") + } + if policy["log_init"].(bool) { + configSet = append(configSet, setPrefixPolicy+" then log session-init") + } + if policy["log_close"].(bool) { + configSet = append(configSet, setPrefixPolicy+" then log session-close") + } + if len(policy["permit_application_services"].([]interface{})) > 0 { + if policy["permit_application_services"].([]interface{})[0] == nil { + return fmt.Errorf("permit_application_services block is empty") + } + if policy["then"].(string) != permitWord { + return fmt.Errorf("conflict policy then %v and policy permit_application_services", + policy["then"].(string)) + } + configSetAppSvc, err := setGlobalPolicyPermitApplicationServices(setPrefixPolicy, + policy["permit_application_services"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + configSet = append(configSet, configSetAppSvc...) + } + } + + return sess.configSet(configSet, jnprSess) +} +func readSecurityGlobalPolicy(m interface{}, jnprSess *NetconfObject) (globalPolicyOptions, error) { + sess := m.(*Session) + var confRead globalPolicyOptions + + policyConfig, err := sess.command("show configuration security policies global | display set relative ", jnprSess) + if err != nil { + return confRead, err + } + policyList := make([]map[string]interface{}, 0) + if policyConfig != emptyWord { + for _, item := range strings.Split(policyConfig, "\n") { + if strings.Contains(item, "") { + continue + } + if strings.Contains(item, "") { + break + } + itemTrim := strings.TrimPrefix(item, setLineStart) + if strings.HasPrefix(itemTrim, "policy ") { + policyLineCut := strings.Split(itemTrim, " ") + m := genMapGlobalPolicyWithName(policyLineCut[1]) + m, policyList = copyAndRemoveItemMapList("name", false, m, policyList) + itemTrimPolicy := strings.TrimPrefix(itemTrim, "policy "+policyLineCut[1]+" ") + switch { + case strings.HasPrefix(itemTrimPolicy, "match source-address "): + m["match_source_address"] = append(m["match_source_address"].([]string), + strings.TrimPrefix(itemTrimPolicy, "match source-address ")) + case strings.HasPrefix(itemTrimPolicy, "match destination-address "): + m["match_destination_address"] = append(m["match_destination_address"].([]string), + strings.TrimPrefix(itemTrimPolicy, "match destination-address ")) + case strings.HasPrefix(itemTrimPolicy, "match application "): + m["match_application"] = append(m["match_application"].([]string), + strings.TrimPrefix(itemTrimPolicy, "match application ")) + case strings.HasPrefix(itemTrimPolicy, "match from-zone "): + m["match_from_zone"] = append(m["match_from_zone"].([]string), + strings.TrimPrefix(itemTrimPolicy, "match from-zone ")) + case strings.HasPrefix(itemTrimPolicy, "match to-zone "): + m["match_to_zone"] = append(m["match_to_zone"].([]string), + strings.TrimPrefix(itemTrimPolicy, "match to-zone ")) + case strings.HasPrefix(itemTrimPolicy, "then "): + switch { + case strings.HasSuffix(itemTrimPolicy, permitWord), + strings.HasSuffix(itemTrimPolicy, "deny"), + strings.HasSuffix(itemTrimPolicy, "reject"): + m["then"] = strings.TrimPrefix(itemTrimPolicy, "then ") + case itemTrimPolicy == "then count": + m["count"] = true + case itemTrimPolicy == "then log session-init": + m["log_init"] = true + case itemTrimPolicy == "then log session-close": + m["log_close"] = true + case strings.HasPrefix(itemTrimPolicy, "then permit application-services"): + m["then"] = permitWord + m["permit_application_services"] = readGlobalPolicyPermitApplicationServices(itemTrimPolicy, + m["permit_application_services"]) + } + } + policyList = append(policyList, m) + } + } + } + confRead.policy = policyList + + return confRead, nil +} +func delSecurityGlobalPolicy(m interface{}, jnprSess *NetconfObject) error { + sess := m.(*Session) + configSet := make([]string, 0, 1) + configSet = append(configSet, "delete security policies global") + + return sess.configSet(configSet, jnprSess) +} + +func fillSecurityGlobalPolicyData(d *schema.ResourceData, globalPolicyOptions globalPolicyOptions) { + if tfErr := d.Set("policy", globalPolicyOptions.policy); tfErr != nil { + panic(tfErr) + } +} + +func genMapGlobalPolicyWithName(name string) map[string]interface{} { + return map[string]interface{}{ + "name": name, + "match_source_address": make([]string, 0), + "match_destination_address": make([]string, 0), + "match_application": make([]string, 0), + "match_from_zone": make([]string, 0), + "match_to_zone": make([]string, 0), + "then": "", + "count": false, + "log_init": false, + "log_close": false, + "permit_application_services": make([]map[string]interface{}, 0), + } +} + +func readGlobalPolicyPermitApplicationServices(itemTrimPolicy string, + permitApplicationServices interface{}) []map[string]interface{} { + applicationServices := map[string]interface{}{ + "application_firewall_rule_set": "", + "application_traffic_control_rule_set": "", + "gprs_gtp_profile": "", + "gprs_sctp_profile": "", + "idp": false, + "redirect_wx": false, + "reverse_redirect_wx": false, + "security_intelligence_policy": "", + "ssl_proxy": make([]map[string]interface{}, 0, 1), + "uac_policy": make([]map[string]interface{}, 0, 1), + "utm_policy": "", + } + if len(permitApplicationServices.([]map[string]interface{})) > 0 { + for k, v := range permitApplicationServices.([]map[string]interface{})[0] { + applicationServices[k] = v + } + } + itemTrimPolicyPermitAppSvc := strings.TrimPrefix(itemTrimPolicy, "then permit application-services ") + switch { + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "application-firewall rule-set "): + applicationServices["application_firewall_rule_set"] = strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, + "application-firewall rule-set "), "\"") + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "application-traffic-control rule-set "): + applicationServices["application_traffic_control_rule_set"] = strings.Trim( + strings.TrimPrefix(itemTrimPolicyPermitAppSvc, "application-traffic-control rule-set "), "\"") + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "gprs-gtp-profile "): + applicationServices["gprs_gtp_profile"] = strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, + "gprs-gtp-profile "), "\"") + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "gprs-sctp-profile "): + applicationServices["gprs_sctp_profile"] = strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, + "gprs-sctp-profile "), "\"") + case itemTrimPolicyPermitAppSvc == "idp": + applicationServices["idp"] = true + case itemTrimPolicyPermitAppSvc == "redirect-wx": + applicationServices["redirect_wx"] = true + case itemTrimPolicyPermitAppSvc == "reverse-redirect-wx": + applicationServices["reverse_redirect_wx"] = true + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "security-intelligence-policy "): + applicationServices["security_intelligence_policy"] = strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, + "security-intelligence-policy "), "\"") + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "ssl-proxy"): + if strings.HasPrefix(itemTrimPolicyPermitAppSvc, "ssl-proxy profile-name ") { + applicationServices["ssl_proxy"] = append(applicationServices["ssl_proxy"].([]map[string]interface{}), + map[string]interface{}{ + "profile_name": strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, "ssl-proxy profile-name "), "\""), + }) + } else { + applicationServices["ssl_proxy"] = append(applicationServices["ssl_proxy"].([]map[string]interface{}), + map[string]interface{}{ + "profile_name": "", + }) + } + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "uac-policy"): + if strings.HasPrefix(itemTrimPolicyPermitAppSvc, "uac-policy captive-portal ") { + applicationServices["uac_policy"] = append(applicationServices["uac_policy"].([]map[string]interface{}), + map[string]interface{}{ + "captive_portal": strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, "uac-policy captive-portal "), "\""), + }) + } else { + applicationServices["uac_policy"] = append(applicationServices["uac_policy"].([]map[string]interface{}), + map[string]interface{}{ + "captive_portal": "", + }) + } + case strings.HasPrefix(itemTrimPolicyPermitAppSvc, "utm-policy "): + applicationServices["utm_policy"] = strings.Trim(strings.TrimPrefix(itemTrimPolicyPermitAppSvc, "utm-policy "), "\"") + } + + // override (maxItem = 1) + return []map[string]interface{}{applicationServices} +} + +func setGlobalPolicyPermitApplicationServices(setPrefixPolicy string, + policyPermitApplicationServices map[string]interface{}) ([]string, error) { + configSet := make([]string, 0) + setPrefixPolicyPermitAppSvc := setPrefixPolicy + " then permit application-services " + if policyPermitApplicationServices["application_firewall_rule_set"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "application-firewall rule-set \""+ + policyPermitApplicationServices["application_firewall_rule_set"].(string)+"\"") + } + if policyPermitApplicationServices["application_traffic_control_rule_set"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "application-traffic-control rule-set \""+ + policyPermitApplicationServices["application_traffic_control_rule_set"].(string)+"\"") + } + if policyPermitApplicationServices["gprs_gtp_profile"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "gprs-gtp-profile \""+policyPermitApplicationServices["gprs_gtp_profile"].(string)+"\"") + } + if policyPermitApplicationServices["gprs_sctp_profile"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "gprs-sctp-profile \""+policyPermitApplicationServices["gprs_sctp_profile"].(string)+"\"") + } + if policyPermitApplicationServices["idp"].(bool) { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "idp") + } + if policyPermitApplicationServices["redirect_wx"].(bool) && + policyPermitApplicationServices["reverse_redirect_wx"].(bool) { + return configSet, fmt.Errorf("conflict redirect_wx and reverse_redirect_wx enabled both") + } + if policyPermitApplicationServices["redirect_wx"].(bool) { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "redirect-wx") + } + if policyPermitApplicationServices["reverse_redirect_wx"].(bool) { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "reverse-redirect-wx") + } + if policyPermitApplicationServices["security_intelligence_policy"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "security-intelligence-policy \""+ + policyPermitApplicationServices["security_intelligence_policy"].(string)+"\"") + } + if len(policyPermitApplicationServices["ssl_proxy"].([]interface{})) > 0 { + if policyPermitApplicationServices["ssl_proxy"].([]interface{})[0] != nil { + policyPermitApplicationServicesSSLProxy := + policyPermitApplicationServices["ssl_proxy"].([]interface{})[0].(map[string]interface{}) + if policyPermitApplicationServicesSSLProxy["profile_name"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "ssl-proxy profile-name \""+ + policyPermitApplicationServicesSSLProxy["profile_name"].(string)+"\"") + } else { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+"ssl-proxy") + } + } else { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+"ssl-proxy") + } + } + if len(policyPermitApplicationServices["uac_policy"].([]interface{})) > 0 { + if policyPermitApplicationServices["uac_policy"].([]interface{})[0] != nil { + policyPermitApplicationServicesUACPolicy := + policyPermitApplicationServices["uac_policy"].([]interface{})[0].(map[string]interface{}) + if policyPermitApplicationServicesUACPolicy["captive_portal"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "uac-policy captive-portal \""+ + policyPermitApplicationServicesUACPolicy["captive_portal"].(string)+"\"") + } else { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+"uac-policy") + } + } else { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+"uac-policy") + } + } + if policyPermitApplicationServices["utm_policy"].(string) != "" { + configSet = append(configSet, setPrefixPolicyPermitAppSvc+ + "utm-policy \""+policyPermitApplicationServices["utm_policy"].(string)+"\"") + } + + return configSet, nil +} diff --git a/junos/resource_security_global_policy_test.go b/junos/resource_security_global_policy_test.go new file mode 100644 index 00000000..e6cf02bf --- /dev/null +++ b/junos/resource_security_global_policy_test.go @@ -0,0 +1,131 @@ +package junos_test + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccJunosSecurityGlobalPolicy_basic(t *testing.T) { + if os.Getenv("TESTACC_SWITCH") == "" { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccJunosSecurityGlobalPolicyConfigCreate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.#", "1"), + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.0.name", "test"), + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.0.then", "permit"), + ), + }, + { + Config: testAccJunosSecurityGlobalPolicyConfigUpdate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.#", "2"), + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.0.permit_application_services.#", "1"), + resource.TestCheckResourceAttr("junos_security_global_policy.testacc_secglobpolicy", + "policy.1.then", "deny"), + ), + }, + { + ResourceName: "junos_security_global_policy.testacc_secglobpolicy", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + } +} + +func testAccJunosSecurityGlobalPolicyConfigCreate() string { + return ` +resource junos_security_zone "testacc_secglobpolicy1" { + name = "testacc_secglobpolicy1" +} +resource junos_security_zone "testacc_secglobpolicy2" { + name = "testacc_secglobpolicy2" +} +resource "junos_security_address_book" "testacc_secglobpolicy" { + network_address { + name = "blue" + value = "192.0.2.1/32" + } + network_address { + name = "green" + value = "192.0.2.2/32" + } +} +resource junos_security_global_policy "testacc_secglobpolicy" { + depends_on = [ + junos_security_address_book.testacc_secglobpolicy + ] + policy { + name = "test" + match_source_address = ["blue"] + match_destination_address = ["green"] + match_application = ["any"] + match_from_zone = [junos_security_zone.testacc_secglobpolicy1.name] + match_to_zone = [junos_security_zone.testacc_secglobpolicy2.name] + } +} +` +} +func testAccJunosSecurityGlobalPolicyConfigUpdate() string { + return ` +resource junos_security_zone "testacc_secglobpolicy1" { + name = "testacc_secglobpolicy1" +} +resource junos_security_zone "testacc_secglobpolicy2" { + name = "testacc_secglobpolicy2" +} +resource "junos_security_address_book" "testacc_secglobpolicy" { + network_address { + name = "blue" + value = "192.0.2.1/32" + } + network_address { + name = "green" + value = "192.0.2.2/32" + } +} +resource junos_security_global_policy "testacc_secglobpolicy" { + depends_on = [ + junos_security_address_book.testacc_secglobpolicy + ] + policy { + name = "test" + match_source_address = ["blue"] + match_destination_address = ["any"] + match_application = ["any"] + match_from_zone = [junos_security_zone.testacc_secglobpolicy1.name] + match_to_zone = [junos_security_zone.testacc_secglobpolicy1.name] + count = true + log_init = true + log_close = true + permit_application_services { + idp = true + redirect_wx = true + ssl_proxy {} + uac_policy {} + } + } + policy { + name = "drop" + match_source_address = ["blue"] + match_destination_address = ["any"] + match_application = ["any"] + match_from_zone = ["any"] + match_to_zone = ["any"] + then = "deny" + } +} +` +} diff --git a/junos/resource_security_ike_gateway.go b/junos/resource_security_ike_gateway.go index 58edf2b4..2cb669f5 100644 --- a/junos/resource_security_ike_gateway.go +++ b/junos/resource_security_ike_gateway.go @@ -42,7 +42,7 @@ func resourceIkeGateway() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "external_interface": { Type: schema.TypeString, @@ -160,7 +160,7 @@ func resourceIkeGateway() *schema.Resource { "access_profile": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), ConflictsWith: []string{ "aaa.0.client_password", "aaa.0.client_username", @@ -272,6 +272,14 @@ func resourceIkeGateway() *schema.Resource { func resourceIkeGatewayCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setIkeGateway(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -561,11 +569,7 @@ func setIkeGateway(d *schema.ResourceData, m interface{}, jnprSess *NetconfObjec configSet = append(configSet, setPrefix+" version "+d.Get("version").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIkeGateway(ikeGateway string, m interface{}, jnprSess *NetconfObject) (ikeGatewayOptions, error) { sess := m.(*Session) @@ -738,11 +742,8 @@ func delIkeGateway(d *schema.ResourceData, m interface{}, jnprSess *NetconfObjec sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ike gateway "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIkeGatewayData(d *schema.ResourceData, ikeGatewayOptions ikeGatewayOptions) { diff --git a/junos/resource_security_ike_policy.go b/junos/resource_security_ike_policy.go index b2441d80..83dc0368 100644 --- a/junos/resource_security_ike_policy.go +++ b/junos/resource_security_ike_policy.go @@ -46,7 +46,7 @@ func resourceIkePolicy() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "proposals": { Type: schema.TypeList, @@ -85,6 +85,14 @@ func resourceIkePolicy() *schema.Resource { func resourceIkePolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setIkePolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -274,11 +282,7 @@ func setIkePolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject configSet = append(configSet, setPrefix+" pre-shared-key hexadecimal "+d.Get("pre_shared_key_hexa").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIkePolicy(ikePolicy string, m interface{}, jnprSess *NetconfObject) (ikePolicyOptions, error) { sess := m.(*Session) @@ -328,11 +332,8 @@ func delIkePolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ike policy "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIkePolicyData(d *schema.ResourceData, ikePolicyOptions ikePolicyOptions) { diff --git a/junos/resource_security_ike_proposal.go b/junos/resource_security_ike_proposal.go index 857c4989..3bc77fac 100644 --- a/junos/resource_security_ike_proposal.go +++ b/junos/resource_security_ike_proposal.go @@ -34,7 +34,7 @@ func resourceIkeProposal() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "authentication_algorithm": { Type: schema.TypeString, @@ -64,6 +64,14 @@ func resourceIkeProposal() *schema.Resource { func resourceIkeProposalCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setIkeProposal(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -250,11 +258,7 @@ func setIkeProposal(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje configSet = append(configSet, setPrefix+" lifetime-seconds "+strconv.Itoa(d.Get("lifetime_seconds").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIkeProposal(ikeProposal string, m interface{}, jnprSess *NetconfObject) (ikeProposalOptions, error) { sess := m.(*Session) @@ -299,11 +303,8 @@ func delIkeProposal(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ike proposal "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIkeProposalData(d *schema.ResourceData, ikeProposalOptions ikeProposalOptions) { diff --git a/junos/resource_security_ipsec_policy.go b/junos/resource_security_ipsec_policy.go index 93643a99..71d93519 100644 --- a/junos/resource_security_ipsec_policy.go +++ b/junos/resource_security_ipsec_policy.go @@ -31,7 +31,7 @@ func resourceIpsecPolicy() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "pfs_keys": { Type: schema.TypeString, @@ -56,6 +56,14 @@ func resourceIpsecPolicy() *schema.Resource { func resourceIpsecPolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setIpsecPolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -236,11 +244,7 @@ func setIpsecPolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje configSet = append(configSet, setPrefix+" proposal-set "+d.Get("proposal_set").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIpsecPolicy(ipsecPolicy string, m interface{}, jnprSess *NetconfObject) (ipsecPolicyOptions, error) { sess := m.(*Session) @@ -278,11 +282,8 @@ func delIpsecPolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ipsec policy "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIpsecPolicyData(d *schema.ResourceData, ipsecPolicyOptions ipsecPolicyOptions) { diff --git a/junos/resource_security_ipsec_proposal.go b/junos/resource_security_ipsec_proposal.go index 3fbb22c2..ef8fe918 100644 --- a/junos/resource_security_ipsec_proposal.go +++ b/junos/resource_security_ipsec_proposal.go @@ -34,7 +34,7 @@ func resourceIpsecProposal() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "authentication_algorithm": { Type: schema.TypeString, @@ -65,6 +65,14 @@ func resourceIpsecProposal() *schema.Resource { func resourceIpsecProposalCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setIpsecProposal(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -252,11 +260,7 @@ func setIpsecProposal(d *schema.ResourceData, m interface{}, jnprSess *NetconfOb configSet = append(configSet, setPrefix+" protocol "+d.Get("protocol").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIpsecProposal(ipsecProposal string, m interface{}, jnprSess *NetconfObject) (ipsecProposalOptions, error) { sess := m.(*Session) @@ -304,11 +308,8 @@ func delIpsecProposal(d *schema.ResourceData, m interface{}, jnprSess *NetconfOb sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ipsec proposal "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIpsecProposalData(d *schema.ResourceData, ipsecProposalOptions ipsecProposalOptions) { diff --git a/junos/resource_security_ipsec_vpn.go b/junos/resource_security_ipsec_vpn.go index 4a6c181c..e1e049c8 100644 --- a/junos/resource_security_ipsec_vpn.go +++ b/junos/resource_security_ipsec_vpn.go @@ -35,7 +35,7 @@ func resourceIpsecVpn() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "bind_interface": { Type: schema.TypeString, @@ -71,7 +71,7 @@ func resourceIpsecVpn() *schema.Resource { "policy": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "identity_local": { Type: schema.TypeString, @@ -86,7 +86,7 @@ func resourceIpsecVpn() *schema.Resource { "identity_service": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, }, @@ -100,7 +100,7 @@ func resourceIpsecVpn() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "local_ip": { Type: schema.TypeString, @@ -148,6 +148,14 @@ func resourceIpsecVpn() *schema.Resource { func resourceIpsecVpnCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" && !d.Get("bind_interface_auto").(bool) { + if err := setIpsecVpn(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -174,7 +182,7 @@ func resourceIpsecVpnCreate(ctx context.Context, d *schema.ResourceData, m inter if err != nil { sess.configClear(jnprSess) - return diag.FromErr(fmt.Errorf("error for find new bind interface: %w", err)) + return diag.FromErr(fmt.Errorf("error for find new bind interface : %w", err)) } tfErr := d.Set("bind_interface", newSt0) if tfErr != nil { @@ -416,11 +424,7 @@ func setIpsecVpn(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readIpsecVpn(ipsecVpn string, m interface{}, jnprSess *NetconfObject) (ipsecVpnOptions, error) { sess := m.(*Session) @@ -524,11 +528,8 @@ func delIpsecVpnConf(d *schema.ResourceData, m interface{}, jnprSess *NetconfObj sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security ipsec vpn "+d.Get("name").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delIpsecVpn(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) @@ -543,11 +544,8 @@ func delIpsecVpn(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) configSet = append(configSet, "delete interfaces "+d.Get("bind_interface").(string)) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillIpsecVpnData(d *schema.ResourceData, ipsecVpnOptions ipsecVpnOptions) { diff --git a/junos/resource_security_log_stream.go b/junos/resource_security_log_stream.go index 07a98046..85fe59af 100644 --- a/junos/resource_security_log_stream.go +++ b/junos/resource_security_log_stream.go @@ -102,7 +102,7 @@ func resourceSecurityLogStream() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{"default"}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{"default"}, 64, FormatDefault), }, }, }, @@ -123,6 +123,14 @@ func resourceSecurityLogStream() *schema.Resource { func resourceSecurityLogStreamCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityLogStream(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -339,11 +347,7 @@ func setSecurityLogStream(d *schema.ResourceData, m interface{}, jnprSess *Netco d.Get("severity").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityLogStream(securityLogStream string, m interface{}, jnprSess *NetconfObject) ( securityLogStreamOptions, error) { @@ -438,11 +442,8 @@ func delLogStream(securityLogStream string, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security log stream \""+securityLogStream+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityLogStreamData(d *schema.ResourceData, securityLogStreamOptions securityLogStreamOptions) { diff --git a/junos/resource_security_nat_destination.go b/junos/resource_security_nat_destination.go index 98814f03..bf1d15b1 100644 --- a/junos/resource_security_nat_destination.go +++ b/junos/resource_security_nat_destination.go @@ -30,7 +30,7 @@ func resourceSecurityNatDestination() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "from": { Type: schema.TypeList, @@ -60,7 +60,7 @@ func resourceSecurityNatDestination() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "destination_address": { Type: schema.TypeString, @@ -81,7 +81,7 @@ func resourceSecurityNatDestination() *schema.Resource { "pool": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, }, }, @@ -95,6 +95,14 @@ func resourceSecurityNatDestination() *schema.Resource { func resourceSecurityNatDestinationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityNatDestination(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -294,11 +302,8 @@ func setSecurityNatDestination(d *schema.ResourceData, m interface{}, jnprSess * } } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityNatDestination(natDestination string, m interface{}, jnprSess *NetconfObject) (natDestinationOptions, error) { @@ -380,11 +385,8 @@ func delSecurityNatDestination(natDestination string, m interface{}, jnprSess *N sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security nat destination rule-set "+natDestination) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityNatDestinationData(d *schema.ResourceData, natDestinationOptions natDestinationOptions) { if tfErr := d.Set("name", natDestinationOptions.name); tfErr != nil { diff --git a/junos/resource_security_nat_destination_pool.go b/junos/resource_security_nat_destination_pool.go index acd0973c..629c39e1 100644 --- a/junos/resource_security_nat_destination_pool.go +++ b/junos/resource_security_nat_destination_pool.go @@ -33,7 +33,7 @@ func resourceSecurityNatDestinationPool() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "address": { Type: schema.TypeString, @@ -55,7 +55,7 @@ func resourceSecurityNatDestinationPool() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, } @@ -64,6 +64,14 @@ func resourceSecurityNatDestinationPool() *schema.Resource { func resourceSecurityNatDestinationPoolCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityNatDestinationPool(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -251,11 +259,8 @@ func setSecurityNatDestinationPool(d *schema.ResourceData, m interface{}, jnprSe if d.Get("routing_instance").(string) != "" { configSet = append(configSet, setPrefix+" routing-instance "+d.Get("routing_instance").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityNatDestinationPool(natDestinationPool string, m interface{}, jnprSess *NetconfObject) (natDestinationPoolOptions, error) { @@ -300,11 +305,8 @@ func delSecurityNatDestinationPool(natDestinationPool string, m interface{}, jnp sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security nat destination pool "+natDestinationPool) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityNatDestinationPoolData(d *schema.ResourceData, natDestinationPoolOptions natDestinationPoolOptions) { if tfErr := d.Set("name", natDestinationPoolOptions.name); tfErr != nil { diff --git a/junos/resource_security_nat_source.go b/junos/resource_security_nat_source.go index 9b6d05b0..069b6d8d 100644 --- a/junos/resource_security_nat_source.go +++ b/junos/resource_security_nat_source.go @@ -31,7 +31,7 @@ func resourceSecurityNatSource() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "from": { Type: schema.TypeList, @@ -81,7 +81,7 @@ func resourceSecurityNatSource() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "match": { Type: schema.TypeList, @@ -121,7 +121,7 @@ func resourceSecurityNatSource() *schema.Resource { "pool": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, }, }, @@ -135,6 +135,14 @@ func resourceSecurityNatSource() *schema.Resource { func resourceSecurityNatSourceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityNatSource(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -361,11 +369,8 @@ func setSecurityNatSource(d *schema.ResourceData, m interface{}, jnprSess *Netco } } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityNatSource(natSource string, m interface{}, jnprSess *NetconfObject) (natSourceOptions, error) { sess := m.(*Session) @@ -483,11 +488,8 @@ func delSecurityNatSource(natSource string, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security nat source rule-set "+natSource) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityNatSourceData(d *schema.ResourceData, natSourceOptions natSourceOptions) { if tfErr := d.Set("name", natSourceOptions.name); tfErr != nil { diff --git a/junos/resource_security_nat_source_pool.go b/junos/resource_security_nat_source_pool.go index 7d97442a..a7aeee91 100644 --- a/junos/resource_security_nat_source_pool.go +++ b/junos/resource_security_nat_source_pool.go @@ -35,7 +35,7 @@ func resourceSecurityNatSourcePool() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "address": { Type: schema.TypeList, @@ -63,7 +63,7 @@ func resourceSecurityNatSourcePool() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, } @@ -71,6 +71,14 @@ func resourceSecurityNatSourcePool() *schema.Resource { func resourceSecurityNatSourcePoolCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityNatSourcePool(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -267,11 +275,8 @@ func setSecurityNatSourcePool(d *schema.ResourceData, m interface{}, jnprSess *N if d.Get("routing_instance").(string) != "" { configSet = append(configSet, setPrefix+" routing-instance "+d.Get("routing_instance").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityNatSourcePool(natSourcePool string, m interface{}, jnprSess *NetconfObject) (natSourcePoolOptions, error) { @@ -323,11 +328,8 @@ func delSecurityNatSourcePool(natSourcePool string, m interface{}, jnprSess *Net sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security nat source pool "+natSourcePool) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityNatSourcePoolData(d *schema.ResourceData, natSourcePoolOptions natSourcePoolOptions) { if tfErr := d.Set("name", natSourcePoolOptions.name); tfErr != nil { diff --git a/junos/resource_security_nat_static.go b/junos/resource_security_nat_static.go index 362eeb33..1641e213 100644 --- a/junos/resource_security_nat_static.go +++ b/junos/resource_security_nat_static.go @@ -30,7 +30,7 @@ func resourceSecurityNatStatic() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "from": { Type: schema.TypeList, @@ -59,7 +59,7 @@ func resourceSecurityNatStatic() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "destination_address": { Type: schema.TypeString, @@ -85,7 +85,7 @@ func resourceSecurityNatStatic() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, }, @@ -99,6 +99,14 @@ func resourceSecurityNatStatic() *schema.Resource { func resourceSecurityNatStaticCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityNatStatic(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -307,11 +315,8 @@ func setSecurityNatStatic(d *schema.ResourceData, m interface{}, jnprSess *Netco } } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityNatStatic(natStatic string, m interface{}, jnprSess *NetconfObject) (natStaticOptions, error) { sess := m.(*Session) @@ -399,11 +404,8 @@ func delSecurityNatStatic(natStatic string, m interface{}, jnprSess *NetconfObje sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security nat static rule-set "+natStatic) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityNatStaticData(d *schema.ResourceData, natStaticOptions natStaticOptions) { if tfErr := d.Set("name", natStaticOptions.name); tfErr != nil { diff --git a/junos/resource_security_policy.go b/junos/resource_security_policy.go index e5e4a846..f8df4a7d 100644 --- a/junos/resource_security_policy.go +++ b/junos/resource_security_policy.go @@ -30,13 +30,13 @@ func resourceSecurityPolicy() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "to_zone": { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "policy": { Type: schema.TypeList, @@ -46,7 +46,7 @@ func resourceSecurityPolicy() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "match_source_address": { Type: schema.TypeList, @@ -165,6 +165,14 @@ func resourceSecurityPolicy() *schema.Resource { func resourceSecurityPolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityPolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("from_zone").(string) + idSeparator + d.Get("to_zone").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -409,11 +417,8 @@ func setSecurityPolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfO configSet = append(configSet, configSetAppSvc...) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityPolicy(idPolicy string, m interface{}, jnprSess *NetconfObject) (policyOptions, error) { zone := strings.Split(idPolicy, idSeparator) @@ -489,11 +494,8 @@ func delSecurityPolicy(fromZone string, toZone string, m interface{}, jnprSess * sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security policies from-zone "+fromZone+" to-zone "+toZone) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityPolicyData(d *schema.ResourceData, policyOptions policyOptions) { diff --git a/junos/resource_security_policy_tunnel_pair_policy.go b/junos/resource_security_policy_tunnel_pair_policy.go index 01aaa506..4a7dfd49 100644 --- a/junos/resource_security_policy_tunnel_pair_policy.go +++ b/junos/resource_security_policy_tunnel_pair_policy.go @@ -29,25 +29,25 @@ func resourceSecurityPolicyTunnelPairPolicy() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "zone_b": { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "policy_a_to_b": { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "policy_b_to_a": { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, }, } @@ -56,6 +56,15 @@ func resourceSecurityPolicyTunnelPairPolicy() *schema.Resource { func resourceSecurityPolicyTunnelPairPolicyCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityPolicyTunnelPairPolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("zone_a").(string) + idSeparator + d.Get("policy_a_to_b").(string) + + idSeparator + d.Get("zone_b").(string) + idSeparator + d.Get("policy_b_to_a").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -256,11 +265,7 @@ func setSecurityPolicyTunnelPairPolicy(d *schema.ResourceData, m interface{}, jn " policy "+d.Get("policy_b_to_a").(string)+ " then permit tunnel pair-policy "+d.Get("policy_a_to_b").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityPolicyTunnelPairPolicy(idRessource string, m interface{}, jnprSess *NetconfObject) (policyPairPolicyOptions, error) { @@ -333,11 +338,8 @@ func delSecurityPolicyTunnelPairPolicy(d *schema.ResourceData, m interface{}, jn " from-zone "+d.Get("zone_b").(string)+" to-zone "+d.Get("zone_a").(string)+ " policy "+d.Get("policy_b_to_a").(string)+ " then permit tunnel pair-policy "+d.Get("policy_a_to_b").(string)) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityPolicyPairData(d *schema.ResourceData, policyPairPolicyOptions policyPairPolicyOptions) { diff --git a/junos/resource_security_screen.go b/junos/resource_security_screen.go index 1dde4af9..84babcc7 100644 --- a/junos/resource_security_screen.go +++ b/junos/resource_security_screen.go @@ -476,7 +476,7 @@ func resourceSecurityScreen() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "destination_address": { Type: schema.TypeList, @@ -581,6 +581,14 @@ func resourceSecurityScreen() *schema.Resource { func resourceSecurityScreenCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityScreen(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -817,11 +825,7 @@ func setSecurityScreen(d *schema.ResourceData, m interface{}, jnprSess *NetconfO configSet = append(configSet, setSecurityScreenUDP(udp, setPrefix)...) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func setSecurityScreenIcmp(icmp map[string]interface{}, setPrefix string) []string { configSet := make([]string, 0) @@ -1804,11 +1808,8 @@ func delSecurityScreen(name string, m interface{}, jnprSess *NetconfObject) erro sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security screen ids-option \""+name+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityScreenData(d *schema.ResourceData, screenOptions screenOptions) { diff --git a/junos/resource_security_screen_whitelist.go b/junos/resource_security_screen_whitelist.go index 8848a767..8e17ad02 100644 --- a/junos/resource_security_screen_whitelist.go +++ b/junos/resource_security_screen_whitelist.go @@ -28,7 +28,7 @@ func resourceSecurityScreenWhiteList() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "address": { Type: schema.TypeList, @@ -42,6 +42,14 @@ func resourceSecurityScreenWhiteList() *schema.Resource { func resourceSecurityScreenWhiteListCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityScreenWhiteList(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -228,11 +236,7 @@ func setSecurityScreenWhiteList(d *schema.ResourceData, m interface{}, jnprSess configSet = append(configSet, setPrefix+"address "+v.(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityScreenWhiteList(name string, m interface{}, jnprSess *NetconfObject) (screenWhiteListOptions, error) { @@ -267,11 +271,8 @@ func delSecurityScreenWhiteList(name string, m interface{}, jnprSess *NetconfObj sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security screen white-list "+name) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityScreenWhiteListData(d *schema.ResourceData, whiteListOptions screenWhiteListOptions) { diff --git a/junos/resource_security_test.go b/junos/resource_security_test.go index ccbbf0fb..ec20ec71 100644 --- a/junos/resource_security_test.go +++ b/junos/resource_security_test.go @@ -374,6 +374,10 @@ resource junos_security "testacc_security" { } utm { feature_profile_web_filtering_type = "juniper-enhanced" + feature_profile_web_filtering_juniper_enhanced_server { + host = "192.0.2.1" + port = 1500 + } } } ` @@ -430,6 +434,17 @@ resource junos_security "testacc_security" { rate_cap = 100 source_address = "192.0.2.1" } + utm { + feature_profile_web_filtering_type = "juniper-enhanced" + feature_profile_web_filtering_juniper_enhanced_server { + host = "192.0.2.1" + port = 1500 + routing_instance = junos_routing_instance.testacc_security.name + } + } +} +resource junos_routing_instance testacc_security { + name = "testacc_security" } ` } diff --git a/junos/resource_security_utm_custom_url_category.go b/junos/resource_security_utm_custom_url_category.go index a39f3a48..39f372c7 100644 --- a/junos/resource_security_utm_custom_url_category.go +++ b/junos/resource_security_utm_custom_url_category.go @@ -28,7 +28,7 @@ func resourceSecurityUtmCustomURLCategory() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "value": { Type: schema.TypeList, @@ -43,6 +43,14 @@ func resourceSecurityUtmCustomURLCategory() *schema.Resource { func resourceSecurityUtmCustomURLCategoryCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmCustomURLCategory(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -225,11 +233,7 @@ func setUtmCustomURLCategory(d *schema.ResourceData, m interface{}, jnprSess *Ne configSet = append(configSet, setPrefix+"value "+v.(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmCustomURLCategory(urlCategory string, m interface{}, jnprSess *NetconfObject) ( utmCustomURLCategoryOptions, error) { @@ -264,11 +268,8 @@ func delUtmCustomURLCategory(urlCategory string, m interface{}, jnprSess *Netcon sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm custom-objects custom-url-category "+urlCategory) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmCustomURLCategoryData(d *schema.ResourceData, utmCustomURLCategoryOptions utmCustomURLCategoryOptions) { diff --git a/junos/resource_security_utm_custom_url_pattern.go b/junos/resource_security_utm_custom_url_pattern.go index d092cbd9..0e6c2769 100644 --- a/junos/resource_security_utm_custom_url_pattern.go +++ b/junos/resource_security_utm_custom_url_pattern.go @@ -28,7 +28,7 @@ func resourceSecurityUtmCustomURLPattern() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "value": { Type: schema.TypeList, @@ -43,6 +43,14 @@ func resourceSecurityUtmCustomURLPattern() *schema.Resource { func resourceSecurityUtmCustomURLPatternCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmCustomURLPattern(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -223,11 +231,7 @@ func setUtmCustomURLPattern(d *schema.ResourceData, m interface{}, jnprSess *Net configSet = append(configSet, setPrefix+"value "+v.(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmCustomURLPattern(urlPattern string, m interface{}, jnprSess *NetconfObject) ( utmCustomURLPatternOptions, error) { @@ -262,11 +266,8 @@ func delUtmCustomURLPattern(urlPattern string, m interface{}, jnprSess *NetconfO sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm custom-objects url-pattern "+urlPattern) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmCustomURLPatternData(d *schema.ResourceData, utmCustomURLPatternOptions utmCustomURLPatternOptions) { diff --git a/junos/resource_security_utm_policy.go b/junos/resource_security_utm_policy.go index 33f14654..31c4d00b 100644 --- a/junos/resource_security_utm_policy.go +++ b/junos/resource_security_utm_policy.go @@ -135,6 +135,14 @@ func resourceSecurityUtmPolicy() *schema.Resource { func resourceSecurityUtmPolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmPolicy(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -395,11 +403,7 @@ func setUtmPolicy(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject d.Get("web_filtering_profile").(string)+"\"") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmPolicy(policy string, m interface{}, jnprSess *NetconfObject) ( utmPolicyOptions, error) { @@ -499,11 +503,8 @@ func delUtmPolicy(policy string, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm utm-policy \""+policy+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmPolicyData(d *schema.ResourceData, utmPolicyOptions utmPolicyOptions) { diff --git a/junos/resource_security_utm_profile_web_filtering_juniper_enhanced.go b/junos/resource_security_utm_profile_web_filtering_juniper_enhanced.go index 6f9c5ce3..6c807bd7 100644 --- a/junos/resource_security_utm_profile_web_filtering_juniper_enhanced.go +++ b/junos/resource_security_utm_profile_web_filtering_juniper_enhanced.go @@ -65,7 +65,7 @@ func resourceSecurityUtmProfileWebFilteringEnhanced() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 128), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 128, FormatDefault), }, "action": { Type: schema.TypeString, @@ -188,6 +188,14 @@ func resourceSecurityUtmProfileWebFilteringEnhanced() *schema.Resource { func resourceSecurityUtmProfileWebFilteringEnhancedCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmProfileWebFEnhanced(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -449,11 +457,7 @@ func setUtmProfileWebFEnhanced(d *schema.ResourceData, m interface{}, jnprSess * configSet = append(configSet, setPrefix+"timeout "+strconv.Itoa(d.Get("timeout").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmProfileWebFEnhanced(profile string, m interface{}, jnprSess *NetconfObject) ( utmProfileWebFilteringEnhancedOptions, error) { @@ -576,11 +580,8 @@ func delUtmProfileWebFEnhanced(profile string, m interface{}, jnprSess *NetconfO configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm feature-profile web-filtering juniper-enhanced "+ "profile \""+profile+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmProfileWebFEnhancedData(d *schema.ResourceData, diff --git a/junos/resource_security_utm_profile_web_filtering_juniper_local.go b/junos/resource_security_utm_profile_web_filtering_juniper_local.go index 3d13160d..2fdbce65 100644 --- a/junos/resource_security_utm_profile_web_filtering_juniper_local.go +++ b/junos/resource_security_utm_profile_web_filtering_juniper_local.go @@ -84,6 +84,14 @@ func resourceSecurityUtmProfileWebFilteringLocal() *schema.Resource { func resourceSecurityUtmProfileWebFilteringLocalCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmProfileWebFLocal(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -297,11 +305,7 @@ func setUtmProfileWebFLocal(d *schema.ResourceData, m interface{}, jnprSess *Net configSet = append(configSet, setPrefix+"timeout "+strconv.Itoa(d.Get("timeout").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmProfileWebFLocal(profile string, m interface{}, jnprSess *NetconfObject) ( utmProfileWebFilteringLocalOptions, error) { @@ -366,11 +370,8 @@ func delUtmProfileWebFLocal(profile string, m interface{}, jnprSess *NetconfObje configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm feature-profile web-filtering juniper-local "+ "profile \""+profile+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmProfileWebFLocalData(d *schema.ResourceData, diff --git a/junos/resource_security_utm_profile_web_filtering_websense_redirect.go b/junos/resource_security_utm_profile_web_filtering_websense_redirect.go index 47e81b4c..8e9db35e 100644 --- a/junos/resource_security_utm_profile_web_filtering_websense_redirect.go +++ b/junos/resource_security_utm_profile_web_filtering_websense_redirect.go @@ -108,6 +108,14 @@ func resourceSecurityUtmProfileWebFilteringWebsense() *schema.Resource { func resourceSecurityUtmProfileWebFilteringWebsenseCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setUtmProfileWebFWebsense(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -338,11 +346,7 @@ func setUtmProfileWebFWebsense(d *schema.ResourceData, m interface{}, jnprSess * configSet = append(configSet, setPrefix+"timeout "+strconv.Itoa(d.Get("timeout").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readUtmProfileWebFWebsense(profile string, m interface{}, jnprSess *NetconfObject) ( utmProfileWebFilteringWebsenseOptions, error) { @@ -430,11 +434,8 @@ func delUtmProfileWebFWebsense(profile string, m interface{}, jnprSess *NetconfO configSet := make([]string, 0, 1) configSet = append(configSet, "delete security utm feature-profile web-filtering websense-redirect "+ "profile \""+profile+"\"") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillUtmProfileWebFWebsenseData(d *schema.ResourceData, diff --git a/junos/resource_security_zone.go b/junos/resource_security_zone.go index 306e1e99..11c63283 100644 --- a/junos/resource_security_zone.go +++ b/junos/resource_security_zone.go @@ -39,7 +39,7 @@ func resourceSecurityZone() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "address_book": { Type: schema.TypeList, @@ -49,7 +49,7 @@ func resourceSecurityZone() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), }, "network": { Type: schema.TypeString, @@ -67,7 +67,7 @@ func resourceSecurityZone() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatAddressName), }, "address": { Type: schema.TypeList, @@ -122,6 +122,14 @@ func resourceSecurityZone() *schema.Resource { func resourceSecurityZoneCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSecurityZone(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -337,11 +345,7 @@ func setSecurityZone(d *schema.ResourceData, m interface{}, jnprSess *NetconfObj configSet = append(configSet, setPrefix+" tcp-rst") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSecurityZone(zone string, m interface{}, jnprSess *NetconfObject) (zoneOptions, error) { sess := m.(*Session) @@ -433,21 +437,15 @@ func delSecurityZoneOpts(zone string, m interface{}, jnprSess *NetconfObject) er for _, line := range listLinesToDelete { configSet = append(configSet, delPrefix+line) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delSecurityZone(zone string, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete security zones security-zone "+zone) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSecurityZoneData(d *schema.ResourceData, zoneOptions zoneOptions) { diff --git a/junos/resource_static_route.go b/junos/resource_static_route.go index 25f2cc69..848bd1de 100644 --- a/junos/resource_static_route.go +++ b/junos/resource_static_route.go @@ -56,7 +56,7 @@ func resourceStaticRoute() *schema.Resource { Optional: true, ForceNew: true, Default: defaultWord, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "active": { Type: schema.TypeBool, @@ -178,6 +178,14 @@ func resourceStaticRoute() *schema.Resource { func resourceStaticRouteCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setStaticRoute(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("destination").(string) + idSeparator + d.Get("routing_instance").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -485,11 +493,8 @@ func setStaticRoute(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje if d.Get("no_retain").(bool) { configSet = append(configSet, setPrefix+" no-retain") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readStaticRoute(destination string, instance string, m interface{}, jnprSess *NetconfObject) (staticRouteOptions, error) { @@ -655,11 +660,8 @@ func delStaticRouteOpts(d *schema.ResourceData, m interface{}, jnprSess *Netconf configSet = append(configSet, delPrefix+"qualified-next-hop "+qualifiedNextHop["next_hop"].(string)) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func delStaticRoute(destination string, instance string, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) @@ -678,11 +680,8 @@ func delStaticRoute(destination string, instance string, m interface{}, jnprSess " routing-options rib "+instance+".inet6.0 static route "+destination) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillStaticRouteData(d *schema.ResourceData, staticRouteOptions staticRouteOptions) { diff --git a/junos/resource_system.go b/junos/resource_system.go index 18d1c5bc..bba97c9f 100644 --- a/junos/resource_system.go +++ b/junos/resource_system.go @@ -591,6 +591,14 @@ func resourceSystem() *schema.Resource { func resourceSystemCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystem(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("system") + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -803,11 +811,7 @@ func setSystem(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) e d.Get("tracing_dest_override_syslog_host").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func setSystemServices(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { @@ -898,11 +902,8 @@ func setSystemServices(d *schema.ResourceData, m interface{}, jnprSess *NetconfO } } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func setSystemInternetOptions(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { @@ -1007,11 +1008,8 @@ func setSystemInternetOptions(d *schema.ResourceData, m interface{}, jnprSess *N configSet = append(configSet, setPrefix+"tcp-mss "+strconv.Itoa(internetOptions["tcp_mss"].(int))) } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func setSystemLogin(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) error { @@ -1116,11 +1114,8 @@ func setSystemLogin(d *schema.ResourceData, m interface{}, jnprSess *NetconfObje } } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func listLinesLogin() []string { @@ -1201,11 +1196,8 @@ func delSystem(m interface{}, jnprSess *NetconfObject) error { configSet = append(configSet, delPrefix+line) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func readSystem(m interface{}, jnprSess *NetconfObject) (systemOptions, error) { sess := m.(*Session) diff --git a/junos/resource_system_login_class.go b/junos/resource_system_login_class.go index 0a2c1441..9111190b 100644 --- a/junos/resource_system_login_class.go +++ b/junos/resource_system_login_class.go @@ -54,12 +54,12 @@ func resourceSystemLoginClass() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "access_end": { Type: schema.TypeString, Optional: true, - RequiredWith: []string{"access_end"}, + RequiredWith: []string{"access_start"}, ValidateFunc: validation.StringMatch(regexp.MustCompile( `^([0-1]\d|2[0-3]):([0-5]\d):([0-5]\d)$`), "must have HH:MM:SS format"), }, @@ -185,6 +185,14 @@ func resourceSystemLoginClass() *schema.Resource { func resourceSystemLoginClassCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemLoginClass(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -427,11 +435,7 @@ func setSystemLoginClass(d *schema.ResourceData, m interface{}, jnprSess *Netcon configSet = append(configSet, setPrefix+"tenant \""+d.Get("tenant").(string)+"\"") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemLoginClass(class string, m interface{}, jnprSess *NetconfObject) (systemLoginClassOptions, error) { sess := m.(*Session) @@ -525,11 +529,8 @@ func delSystemLoginClass(systemLoginClass string, m interface{}, jnprSess *Netco sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system login class "+systemLoginClass) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemLoginClassData(d *schema.ResourceData, systemLoginClassOptions systemLoginClassOptions) { if tfErr := d.Set("name", systemLoginClassOptions.name); tfErr != nil { diff --git a/junos/resource_system_login_user.go b/junos/resource_system_login_user.go index df918323..86728100 100644 --- a/junos/resource_system_login_user.go +++ b/junos/resource_system_login_user.go @@ -35,7 +35,7 @@ func resourceSystemLoginUser() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "class": { Type: schema.TypeString, @@ -88,6 +88,14 @@ func resourceSystemLoginUser() *schema.Resource { func resourceSystemLoginUserCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemLoginUser(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -299,11 +307,7 @@ func setSystemLoginUser(d *schema.ResourceData, m interface{}, jnprSess *Netconf configSet = append(configSet, setPrefix+"full-name \""+d.Get("full_name").(string)+"\"") } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemLoginUser(user string, m interface{}, jnprSess *NetconfObject) (systemLoginUserOptions, error) { sess := m.(*Session) @@ -375,11 +379,8 @@ func delSystemLoginUser(systemLoginUser string, m interface{}, jnprSess *Netconf sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system login user "+systemLoginUser) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemLoginUserData(d *schema.ResourceData, systemLoginUserOptions systemLoginUserOptions) { if tfErr := d.Set("name", systemLoginUserOptions.name); tfErr != nil { diff --git a/junos/resource_system_ntp_server.go b/junos/resource_system_ntp_server.go index 30ce1811..e9993455 100644 --- a/junos/resource_system_ntp_server.go +++ b/junos/resource_system_ntp_server.go @@ -47,7 +47,7 @@ func resourceSystemNtpServer() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "version": { Type: schema.TypeInt, @@ -60,6 +60,14 @@ func resourceSystemNtpServer() *schema.Resource { func resourceSystemNtpServerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemNtpServer(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("address").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -245,11 +253,7 @@ func setSystemNtpServer(d *schema.ResourceData, m interface{}, jnprSess *Netconf configSet = append(configSet, setPrefix+" version "+strconv.Itoa(d.Get("version").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemNtpServer(address string, m interface{}, jnprSess *NetconfObject) (ntpServerOptions, error) { sess := m.(*Session) @@ -298,11 +302,8 @@ func delSystemNtpServer(address string, m interface{}, jnprSess *NetconfObject) sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system ntp server "+address) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemNtpServerData(d *schema.ResourceData, ntpServerOptions ntpServerOptions) { if tfErr := d.Set("address", ntpServerOptions.address); tfErr != nil { diff --git a/junos/resource_system_radius_server.go b/junos/resource_system_radius_server.go index fd54bfef..b1e95614 100644 --- a/junos/resource_system_radius_server.go +++ b/junos/resource_system_radius_server.go @@ -106,7 +106,7 @@ func resourceSystemRadiusServer() *schema.Resource { "routing_instance": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "source_address": { Type: schema.TypeString, @@ -124,6 +124,14 @@ func resourceSystemRadiusServer() *schema.Resource { func resourceSystemRadiusServerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemRadiusServer(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("address").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -344,11 +352,7 @@ func setSystemRadiusServer(d *schema.ResourceData, m interface{}, jnprSess *Netc strconv.Itoa(d.Get("timeout").(int))) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemRadiusServer(address string, m interface{}, jnprSess *NetconfObject) (radiusServerOptions, error) { sess := m.(*Session) @@ -456,11 +460,8 @@ func delSystemRadiusServer(address string, m interface{}, jnprSess *NetconfObjec sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system radius-server "+address) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemRadiusServerData(d *schema.ResourceData, radiusServerOptions radiusServerOptions) { if tfErr := d.Set("address", radiusServerOptions.address); tfErr != nil { diff --git a/junos/resource_system_root_authentication.go b/junos/resource_system_root_authentication.go index 0b830fcf..df88788e 100644 --- a/junos/resource_system_root_authentication.go +++ b/junos/resource_system_root_authentication.go @@ -50,6 +50,14 @@ func resourceSystemRootAuthentication() *schema.Resource { func resourceSystemRootAuthenticationCreate( ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemRootAuthentication(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId("system_root_authentication") + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -178,11 +186,7 @@ func setSystemRootAuthentication(d *schema.ResourceData, m interface{}, jnprSess } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemRootAuthentication(m interface{}, jnprSess *NetconfObject) (systemRootAuthOptions, error) { sess := m.(*Session) @@ -230,11 +234,8 @@ func delSystemRootAuthentication(m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system root-authentication") - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemRootAuthenticationData(d *schema.ResourceData, systemRootAuthOptions systemRootAuthOptions) { if tfErr := d.Set("encrypted_password", systemRootAuthOptions.encryptedPassword); tfErr != nil { diff --git a/junos/resource_system_syslog_file.go b/junos/resource_system_syslog_file.go index 8069f285..c99d6f67 100644 --- a/junos/resource_system_syslog_file.go +++ b/junos/resource_system_syslog_file.go @@ -51,7 +51,7 @@ func resourceSystemSyslogFile() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "allow_duplicates": { Type: schema.TypeBool, @@ -233,6 +233,14 @@ func resourceSystemSyslogFile() *schema.Resource { func resourceSystemSyslogFileCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemSyslogFile(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("filename").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -520,11 +528,7 @@ func setSystemSyslogFile(d *schema.ResourceData, m interface{}, jnprSess *Netcon } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemSyslogFile(filename string, m interface{}, jnprSess *NetconfObject) (syslogFileOptions, error) { @@ -677,11 +681,8 @@ func delSystemSyslogFile(filename string, m interface{}, jnprSess *NetconfObject sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system syslog file "+filename) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemSyslogFileData(d *schema.ResourceData, syslogFileOptions syslogFileOptions) { diff --git a/junos/resource_system_syslog_host.go b/junos/resource_system_syslog_host.go index a919cdec..9a8ba4dd 100644 --- a/junos/resource_system_syslog_host.go +++ b/junos/resource_system_syslog_host.go @@ -76,7 +76,7 @@ func resourceSystemSyslogHost() *schema.Resource { "log_prefix": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 32), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 32, FormatDefault), }, "match": { Type: schema.TypeString, @@ -191,6 +191,14 @@ func resourceSystemSyslogHost() *schema.Resource { func resourceSystemSyslogHostCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setSystemSyslogHost(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("host").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -444,11 +452,7 @@ func setSystemSyslogHost(d *schema.ResourceData, m interface{}, jnprSess *Netcon configSet = append(configSet, setPrefix+" user "+d.Get("user_severity").(string)) } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readSystemSyslogHost(host string, m interface{}, jnprSess *NetconfObject) (syslogHostOptions, error) { sess := m.(*Session) @@ -543,11 +547,8 @@ func delSystemSyslogHost(host string, m interface{}, jnprSess *NetconfObject) er sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete system syslog host "+host) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillSystemSyslogHostData(d *schema.ResourceData, syslogHostOptions syslogHostOptions) { if tfErr := d.Set("host", syslogHostOptions.host); tfErr != nil { diff --git a/junos/resource_vlan.go b/junos/resource_vlan.go index afb3ce69..6ac2c365 100644 --- a/junos/resource_vlan.go +++ b/junos/resource_vlan.go @@ -41,7 +41,7 @@ func resourceVlan() *schema.Resource { Type: schema.TypeString, ForceNew: true, Required: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "community_vlans": { Type: schema.TypeList, @@ -55,17 +55,17 @@ func resourceVlan() *schema.Resource { "forward_filter_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "forward_filter_output": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "forward_flood_input": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: validateNameObjectJunos([]string{}, 64), + ValidateDiagFunc: validateNameObjectJunos([]string{}, 64, FormatDefault), }, "isolated_vlan": { Type: schema.TypeInt, @@ -149,6 +149,14 @@ func resourceVlan() *schema.Resource { func resourceVlanCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { sess := m.(*Session) + if sess.junosFakeCreateSetFile != "" { + if err := setVlan(d, m, nil); err != nil { + return diag.FromErr(err) + } + d.SetId(d.Get("name").(string)) + + return nil + } jnprSess, err := sess.startNewSession() if err != nil { return diag.FromErr(err) @@ -374,11 +382,7 @@ func setVlan(d *schema.ResourceData, m interface{}, jnprSess *NetconfObject) err } } - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - - return nil + return sess.configSet(configSet, jnprSess) } func readVlan(vlan string, m interface{}, jnprSess *NetconfObject) (vlanOptions, error) { sess := m.(*Session) @@ -482,11 +486,8 @@ func delVlan(vlan string, m interface{}, jnprSess *NetconfObject) error { sess := m.(*Session) configSet := make([]string, 0, 1) configSet = append(configSet, "delete vlans "+vlan) - if err := sess.configSet(configSet, jnprSess); err != nil { - return err - } - return nil + return sess.configSet(configSet, jnprSess) } func fillVlanData(d *schema.ResourceData, vlanOptions vlanOptions) { diff --git a/junos/session.go b/junos/session.go index a4261af5..f2728437 100644 --- a/junos/session.go +++ b/junos/session.go @@ -2,26 +2,31 @@ package junos import ( "fmt" + "log" "os" + "path" "strconv" - "strings" "time" ) +const directoryPermission = 0755 + // Session information to connect on Junos Device. type Session struct { - junosPort int - junosSleepLock int - junosSleepShort int - junosSleepSSHClosed int - junosIP string - junosUserName string - junosPassword string - junosSSHKeyPEM string - junosSSHKeyFile string - junosKeyPass string - junosGroupIntDel string - junosLogFile string + junosPort int + junosSleepLock int + junosSleepShort int + junosSleepSSHClosed int + junosFilePermission int64 + junosIP string + junosUserName string + junosPassword string + junosSSHKeyPEM string + junosSSHKeyFile string + junosKeyPass string + junosGroupIntDel string + junosLogFile string + junosFakeCreateSetFile string } func (sess *Session) startNewSession() (*NetconfObject, error) { @@ -35,13 +40,6 @@ func (sess *Session) startNewSession() (*NetconfObject, error) { } if sess.junosSSHKeyFile != "" { auth.PrivateKeyFile = sess.junosSSHKeyFile - if strings.HasPrefix(sess.junosSSHKeyFile, "~") { - homeDir, err := os.UserHomeDir() - if err != nil { - return nil, fmt.Errorf("failed to read user home directory : %w", err) - } - auth.PrivateKeyFile = homeDir + sess.junosSSHKeyFile[1:] - } if sess.junosKeyPass != "" { auth.Passphrase = sess.junosKeyPass } @@ -56,33 +54,25 @@ func (sess *Session) startNewSession() (*NetconfObject, error) { if jnpr.SystemInformation.HardwareModel == "" { return jnpr, fmt.Errorf("can't read model of device with netconf command") } - if sess.junosLogFile != "" { - logFile("[startNewSession] started", sess.junosLogFile) - } + sess.logFile("[startNewSession] started") return jnpr, nil } func (sess *Session) closeSession(jnpr *NetconfObject) { err := jnpr.Close(sess.junosSleepSSHClosed) - if sess.junosLogFile != "" { - if err != nil { - logFile(fmt.Sprintf("[closeSession] err: %q", err), sess.junosLogFile) - } else { - logFile("[closeSession] closed", sess.junosLogFile) - } + if err != nil { + sess.logFile(fmt.Sprintf("[closeSession] err: %q", err)) + } else { + sess.logFile("[closeSession] closed") } } func (sess *Session) command(cmd string, jnpr *NetconfObject) (string, error) { read, err := jnpr.netconfCommand(cmd) - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[command] cmd: %q", cmd), sess.junosLogFile) - logFile(fmt.Sprintf("[command] read: %q", read), sess.junosLogFile) - } + sess.logFile(fmt.Sprintf("[command] cmd: %q", cmd)) + sess.logFile(fmt.Sprintf("[command] read: %q", read)) sleepShort(sess.junosSleepShort) if err != nil && read != emptyWord { - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[command] err: %q", err), sess.junosLogFile) - } + sess.logFile(fmt.Sprintf("[command] err: %q", err)) return "", err } @@ -91,15 +81,11 @@ func (sess *Session) command(cmd string, jnpr *NetconfObject) (string, error) { } func (sess *Session) commandXML(cmd string, jnpr *NetconfObject) (string, error) { read, err := jnpr.netconfCommandXML(cmd) - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[commandXML] cmd: %q", cmd), sess.junosLogFile) - logFile(fmt.Sprintf("[commandXML] read: %q", read), sess.junosLogFile) - } + sess.logFile(fmt.Sprintf("[commandXML] cmd: %q", cmd)) + sess.logFile(fmt.Sprintf("[commandXML] read: %q", read)) sleepShort(sess.junosSleepShort) if err != nil { - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[commandXML] err: %q", err), sess.junosLogFile) - } + sess.logFile(fmt.Sprintf("[commandXML] err: %q", err)) return "", err } @@ -107,45 +93,60 @@ func (sess *Session) commandXML(cmd string, jnpr *NetconfObject) (string, error) return read, nil } func (sess *Session) configSet(cmd []string, jnpr *NetconfObject) error { - message, err := jnpr.netconfConfigSet(cmd) - sleepShort(sess.junosSleepShort) - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[configSet] cmd: %q", cmd), sess.junosLogFile) - logFile(fmt.Sprintf("[configSet] message: %q", message), sess.junosLogFile) + if jnpr != nil { + message, err := jnpr.netconfConfigSet(cmd) + sleepShort(sess.junosSleepShort) + sess.logFile(fmt.Sprintf("[configSet] cmd: %q", cmd)) + sess.logFile(fmt.Sprintf("[configSet] message: %q", message)) + if err != nil { + sess.logFile(fmt.Sprintf("[configSet] err: %q", err)) + + return err + } + + return nil + } else if sess.junosFakeCreateSetFile != "" { + return sess.appendFakeCreateSetFile(cmd) + } + + return fmt.Errorf("internal error: sess.configSet call without connection on device") +} + +func (sess *Session) appendFakeCreateSetFile(lines []string) error { + dirSetFile := path.Dir(sess.junosFakeCreateSetFile) + if _, err := os.Stat(dirSetFile); err != nil { + if err := os.MkdirAll(dirSetFile, os.FileMode(directoryPermission)); err != nil { + return fmt.Errorf("failed to create parent directory of `%s` : %w", sess.junosFakeCreateSetFile, err) + } } + f, err := os.OpenFile(sess.junosFakeCreateSetFile, + os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.FileMode(sess.junosFilePermission)) if err != nil { - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[configSet] err: %q", err), sess.junosLogFile) + return fmt.Errorf("failed to openfile `%s` : %w", sess.junosFakeCreateSetFile, err) + } + defer f.Close() + for _, v := range lines { + if _, err := f.WriteString(v + "\n"); err != nil { + return fmt.Errorf("failed to write in file `%s` : %w", sess.junosFakeCreateSetFile, err) } - - return err } return nil } func (sess *Session) commitConf(logMessage string, jnpr *NetconfObject) (_warnings []error, _err error) { - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[commitConf] commit %q", logMessage), sess.junosLogFile) - } + sess.logFile(fmt.Sprintf("[commitConf] commit %q", logMessage)) warns, err := jnpr.netconfCommit(logMessage) sleepShort(sess.junosSleepShort) - if err != nil { - if sess.junosLogFile != "" { - logFile(fmt.Sprintf("[commitConf] commit error: %q", err), sess.junosLogFile) - if len(warns) > 0 { - for _, w := range warns { - logFile(fmt.Sprintf("[commitConf] commit warning: %q", w), sess.junosLogFile) - } - } + if len(warns) > 0 { + for _, w := range warns { + sess.logFile(fmt.Sprintf("[commitConf] commit warning: %q", w)) } + } + if err != nil { + sess.logFile(fmt.Sprintf("[commitConf] commit error: %q", err)) return warns, err } - if len(warns) > 0 && sess.junosLogFile != "" { - for _, w := range warns { - logFile(fmt.Sprintf("[commitConf] commit warning: %q", w), sess.junosLogFile) - } - } return warns, nil } @@ -155,16 +156,12 @@ func (sess *Session) configLock(jnpr *NetconfObject) { for { lock = jnpr.netconfConfigLock() if lock { - if sess.junosLogFile != "" { - logFile("[configLock] locked", sess.junosLogFile) - } + sess.logFile("[configLock] locked") sleepShort(sess.junosSleepShort) break } else { - if sess.junosLogFile != "" { - logFile("[configLock] sleep for wait lock", sess.junosLogFile) - } + sess.logFile("[configLock] sleep for wait lock") sleep(sess.junosSleepLock) } } @@ -172,30 +169,43 @@ func (sess *Session) configLock(jnpr *NetconfObject) { func (sess *Session) configClear(jnpr *NetconfObject) { err := jnpr.netconfConfigClear() sleepShort(sess.junosSleepShort) - if sess.junosLogFile != "" { - logFile("[configClear] config clear", sess.junosLogFile) - } + sess.logFile("[configClear] config clear") if err != nil { err := jnpr.Close(sess.junosSleepSSHClosed) - if err != nil && sess.junosLogFile != "" { - logFile(fmt.Sprintf("[configClear] close err: %q", err), sess.junosLogFile) + if err != nil { + sess.logFile(fmt.Sprintf("[configClear] close err: %q", err)) } panic(err) } err = jnpr.netconfConfigUnlock() sleepShort(sess.junosSleepShort) - if sess.junosLogFile != "" { - logFile("[configClear] config unlock", sess.junosLogFile) - } + sess.logFile("[configClear] config unlock") if err != nil { err := jnpr.Close(sess.junosSleepSSHClosed) - if err != nil && sess.junosLogFile != "" { - logFile(fmt.Sprintf("[configClear] close err: %q", err), sess.junosLogFile) + if err != nil { + sess.logFile(fmt.Sprintf("[configClear] close err: %q", err)) } panic(err) } } +// log message in junosLogFile. +func (sess *Session) logFile(message string) { + if sess.junosLogFile != "" { + f, err := os.OpenFile(sess.junosLogFile, + os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.FileMode(sess.junosFilePermission)) + if err != nil { + log.Fatal(err) + } + defer f.Close() + + log.SetOutput(f) + log.SetPrefix(time.Now().Format("2006-01-02 15:04:05")) + + log.Printf("%s", message) + } +} + func sleep(timeSleep int) { time.Sleep(time.Duration(timeSleep) * time.Second) } diff --git a/website/docs/d/interface_logical.html.markdown b/website/docs/d/interface_logical.html.markdown index 0929d1fd..54797c2a 100644 --- a/website/docs/d/interface_logical.html.markdown +++ b/website/docs/d/interface_logical.html.markdown @@ -50,6 +50,8 @@ The following arguments are supported: * `mtu` - Maximum transmission unit. * `rpf_check` - Reverse-path-forwarding checks enabled and possible configuration. See the [`rpf_check` attributes](#rpf_check-attributes) block for attributes. * `routing_instance` - Routing_instance where the interface is (if not default instance). +* `security_inbound_protocols` - The inbound protocols allowed. +* `security_inbound_services` - The inbound services allowed. * `security_zone` - Security zone where the interface is. * `vlan_id` - 802.1q VLAN ID for unit interface. diff --git a/website/docs/d/interface_physical.html.markdown b/website/docs/d/interface_physical.html.markdown index b6772c91..4ed6a111 100644 --- a/website/docs/d/interface_physical.html.markdown +++ b/website/docs/d/interface_physical.html.markdown @@ -32,12 +32,78 @@ The following arguments are supported: * `id` - Like resource it's the `name` of interface * `name` - Name of physical interface (without dot). -* `ae_lacp` - LACP option in aggregated-ether-options. -* `ae_link_speed` - Link speed of individual interface that joins the AE. -* `ae_minimum_links` - Minimum number of aggregated links (1..8). +* `ae_lacp` (**DEPRECATED**) - LACP option in aggregated-ether-options. +* `ae_link_speed` (**DEPRECATED**) - Link speed of individual interface that joins the AE. +* `ae_minimum_links` (**DEPRECATED**) - Minimum number of aggregated links. * `description` - Description for interface. -* `ether802_3ad` - Link of 802.3ad interface. +* `esi` - Define ESI Config parameters. See the [`esi` attributes](#esi-attributes) block. +* `ether_opts` - Declare 'ether-options' configuration. + * `ae_8023ad` - Name of an aggregated Ethernet interface to join. + * `auto_negotiation` - Enable auto-negotiation. + * `no_auto_negotiation` - Don't enable auto-negotiation. + * `flow_control` - Enable flow control. + * `no_flow_control` - Don't enable flow control. + * `loopback` - Enable loopback. + * `no_loopback` - Don't enable loopback. + * `redundant_parent` - Name of a redundant ethernet interface to join. +* `ether802_3ad` (**DEPRECATED**) - Link of 802.3ad interface. +* `gigether_opts` - Declare 'gigether-options' configuration. + * `ae_8023ad` - Name of an aggregated Ethernet interface to join. + * `auto_negotiation` - Enable auto-negotiation. + * `no_auto_negotiation` - Don't enable auto-negotiation. + * `flow_control` - Enable flow control. + * `no_flow_control` - Don't enable flow control. + * `loopback` - Enable loopback. + * `no_loopback` - Don't enable loopback. + * `redundant_parent` - Name of a redundant ethernet interface to join. +* `parent_ether_opts` - Declare 'aggregated-ether-options' or 'redundant-ether-options' configuration (it depends on the interface 'name'). See the [`parent_ether_opts` attributes](#parent_ether_opts-attributes) block. * `trunk` - Interface mode is trunk. * `vlan_members` - List of vlan membership for this interface. * `vlan_native` - Vlan for untagged frames. * `vlan_tagging` - 802.1q VLAN tagging support. + +--- +#### esi attributes +* `mode` - ESI Mode +* `identifier` - The ESI value for the interface +* `auto_derive_lacp` - Auto-derive ESI value for the interface +* `df_election_type` - DF Election Type +* `source_bmac` - Unicast Source B-MAC address per ESI for PBB-EVPN + +--- +#### parent_ether_opts attributes +* `bfd_liveness_detection` - Declare 'bfd-liveness-detection' in 'aggregated-ether-options' configuration. See the [`bfd_liveness_detection` attributes in parent_ether_opts](#bfd_liveness_detection-attributes-in-parent_ether_opts) block. +* `flow_control` - Enable flow control. +* `no_flow_control` - Don't enable flow control. +* `lacp` - Declare 'lacp' configuration. + * `mode` - Active or passive. + * `admin_key` - Node's administrative key. + * `periodic` - Timer interval for periodic transmission of LACP packets. + * `sync_reset` - On minimum-link failure notify out of sync to peer. + * `system_id` - Node's System ID, encoded as a MAC address + * `system_priority` - Priority of the system. +* `loopback` - Enable loopback. +* `no_loopback` - Don't enable loopback. +* `link_speed` - Link speed of individual interface that joins the AE. +* `minimum_bandwidth` - Minimum bandwidth configured for aggregated bundle. +* `minimum_links` - Minimum number of aggregated/active links. +* `redundancy_group` - Redundancy group of this interface for reth interface. +* `source_address_filter` - Source address filters. +* `source_filtering` - Enable source address filtering. + +--- +#### bfd_liveness_detection attributes in parent_ether_opts +* `local_address` - BFD local address. +* `authentication_algorithm` - Authentication algorithm name. +* `authentication_key_chain` - Authentication Key chain name. +* `authentication_loose_check` - Verify authentication only if authentication is negotiated. +* `detection_time_threshold` - High detection-time triggering a trap. +* `holddown_interval` - Time to hold the session-UP notification to the client. +* `minimum_interval` - Minimum transmit and receive interval. +* `minimum_receive_interval` - Minimum receive interval. +* `multiplier` - Detection time multiplier. +* `neighbor` - BFD neighbor address. +* `no_adaptation` - Disable adaptation. +* `transmit_interval_minimum_interval` - Minimum transmit interval +* `transmit_interval_threshold` - High transmit interval triggering a trap. +* `version` - BFD protocol version number. \ No newline at end of file diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index bb0cc44b..231f8237 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -124,10 +124,26 @@ The following arguments are supported in the `provider` block: Defaults to `0`. --- -#### Debug options +#### Debug & workaround options +* `file_permission` - (Optional) The permission to set for the created file (debug, setfile). + Defaults to `0644`. + It can also be sourced from the `JUNOS_FILE_PERMISSION` environment variable. + * `debug_netconf_log_path` - (Optional) more detailed log (netconf) in the specified file. It can also be sourced from the `JUNOS_LOG_PATH` environment variable. +* `fake_create_with_setfile` - (Optional, **don't use in normal terraform run**) When this option is set (with a path to a file), the normal process to create resources (netconf connection, precheck, generate/upload set lines in candidate configuration, commit, postcheck) skipped to generate set lines, append them to the specified file, and respond with a `fake` successful creation of resource to Terraform. +Then you can upload/commit the file with the `junos_null_commit_file` resource in the same config or another terraform config or with another way. +If you are using `junos_null_commit_file` in the same terraform config, you must create dependencies between resources so that the creation of the ` junos_null_commit_file` resource is alone and last. +This options is useful to create a workaround for a long terraform run if there are many ressources to be created and Junos device is slow to commit. +As many tests are skipped, this option may generate extra config (not managed by terraform) on Junos device or conficts/errors for resources in tfstate. A `terraform refresh` will be able to detect parts of errors but **be carefully with this option**. +There are exceptions for ressources : + * `junos_null_commit_file` - Of course, the skip doesn’t concern this resource. + * `junos_interface_st0_unit` cannot take into account the option and run still normal process. + * `junos_interface_physical` don’t generate `chassis aggregated-devices ethernet device-count` line when it should be necessary. + + It can also be sourced from the `JUNOS_FAKECREATE_SETFILE` environment variable. + ## Interface specifications When create a resource for a physical interface, the provider considers the interface available if there is 'apply-groups [`group_interface_delete`](#group_interface_delete)' and only this line on interface configuration. diff --git a/website/docs/r/bgp_group.html.markdown b/website/docs/r/bgp_group.html.markdown index 81c98331..e9bcd937 100644 --- a/website/docs/r/bgp_group.html.markdown +++ b/website/docs/r/bgp_group.html.markdown @@ -41,8 +41,16 @@ The following arguments are supported: **WARNING** Clear in tfstate. * `authentication_key_chain` - (Optional)(`String`) Key chain name. Conflict with `authentication_key`. * `bfd_liveness_detection` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Define Bidirectional Forwarding Detection (BFD) options. See the [`bfd_liveness_detection` arguments](#bfd_liveness_detection-arguments) block. Max of 1. +* `bgp_multipath` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to allow load sharing among multiple BGP paths. + * `allow_protection` - (Optional)(`Bool`) Allows the BGP multipath and protection to co-exist. + * `disable` - (Optional)(`Bool`) Disable Multipath. + * `multiple_as` - (Optional)(`Bool`) Use paths received from different ASs. +* `cluster` - (Optional)(`String`) Cluster identifier. Must be a valid IP address. * `damping` - (Optional)(`Bool`) Enable route flap damping. * `export` - (Optional)(`ListOfString`) Export policy list. +* `family_evpn` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for the `signaling` nlri_type. + * `nlri_type` - (Optional)(`String`) NLRI type. Need to be `signaling`. Default to `signaling`. + * other options same as [`family_inet` arguments](#family_inet-arguments). * `family_inet` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each nlri_type. See the [`family_inet` arguments](#family_inet-arguments) block. * `family_inet6` Same options as [`family_inet` arguments](#family_inet-arguments) but for inet6 family. @@ -66,7 +74,8 @@ See the [`family_inet` arguments](#family_inet-arguments) block. * `metric_out_minimum_igp_offset` - (Optional)(`Bool`) Metric offset for MED. Conflict with `metric_out` and `metric_out_(?!minimum)_*`. * `mtu_discovery` - (Optional)(`Bool`) Enable TCP path MTU discovery. * `multihop` - (Optional)(`Bool`) Configure an EBGP multihop session. -* `multipath` - (Optional)(`Bool`) Allow load sharing among multiple BGP paths. +* `multipath` - (Optional,**DEPRECATED**)(`Bool`) Allow load sharing among multiple BGP paths. +Deprecated argument, use the `bgp_multipath` argument instead. * `out_delay` - (Optional)(`Int`) How long before exporting routes from routing table. * `passive` - (Optional)(`Bool`) Do not send open messages to a peer. * `peer_as` - (Optional)(`String`) Autonomous system number. @@ -90,7 +99,7 @@ See the [`family_inet` arguments](#family_inet-arguments) block. --- #### family_inet arguments -Also for `family_inet6` +Also for `family_inet6` and `family_evpn` (except `nlri_type`) * `nlri_type` - (Required)(`String`) NLRI type. Need to be 'any', 'flow', 'labeled-unicast', 'unicast' or 'multicast'. * `accepted_prefix_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for define maximum number of prefixes accepted from a peer and options. diff --git a/website/docs/r/bgp_neighbor.html.markdown b/website/docs/r/bgp_neighbor.html.markdown index f6a3b9fc..591a39db 100644 --- a/website/docs/r/bgp_neighbor.html.markdown +++ b/website/docs/r/bgp_neighbor.html.markdown @@ -42,8 +42,16 @@ The following arguments are supported: **WARNING** Clear in tfstate. * `authentication_key_chain` - (Optional)(`String`) Key chain name. Conflict with `authentication_key`. * `bfd_liveness_detection` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Define Bidirectional Forwarding Detection (BFD) options. See the [`bfd_liveness_detection` arguments](#bfd_liveness_detection-arguments) block. Max of 1. +* `bgp_multipath` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to allow load sharing among multiple BGP paths. + * `allow_protection` - (Optional)(`Bool`) Allows the BGP multipath and protection to co-exist. + * `disable` - (Optional)(`Bool`) Disable Multipath. + * `multiple_as` - (Optional)(`Bool`) Use paths received from different ASs. +* `cluster` - (Optional)(`String`) Cluster identifier. Must be a valid IP address. * `damping` - (Optional)(`Bool`) Enable route flap damping. * `export` - (Optional)(`ListOfString`) Export policy list. +* `family_evpn` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for the `signaling` nlri_type. + * `nlri_type` - (Optional)(`String`) NLRI type. Need to be `signaling`. Default to `signaling`. + * other options same as [`family_inet` arguments](#family_inet-arguments). * `family_inet` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each nlri_type. See the [`family_inet` arguments](#family_inet-arguments) block. * `family_inet6` Same options as [`family_inet` arguments](#family_inet-arguments) but for inet6 family. @@ -67,7 +75,8 @@ See the [`family_inet` arguments](#family_inet-arguments) block. * `metric_out_minimum_igp_offset` - (Optional)(`Bool`) Metric offset for MED. Conflict with `metric_out` and `metric_out_(?!minimum)_*`. * `mtu_discovery` - (Optional)(`Bool`) Enable TCP path MTU discovery. * `multihop` - (Optional)(`Bool`) Configure an EBGP multihop session. -* `multipath` - (Optional)(`Bool`) Allow load sharing among multiple BGP paths. +* `multipath` - (Optional,**DEPRECATED**)(`Bool`) Allow load sharing among multiple BGP paths. +Deprecated argument, use the `bgp_multipath` argument instead. * `out_delay` - (Optional)(`Int`) How long before exporting routes from routing table. * `passive` - (Optional)(`Bool`) Do not send open messages to a peer. * `peer_as` - (Optional)(`String`) Autonomous system number. @@ -91,7 +100,7 @@ See the [`family_inet` arguments](#family_inet-arguments) block. --- #### family_inet arguments -Also for `family_inet6` +Also for `family_inet6` and `family_evpn` (except `nlri_type`) * `nlri_type` - (Required)(`String`) NLRI type. Need to be 'any', 'flow', 'labeled-unicast', 'unicast' or 'multicast'. * `accepted_prefix_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for define maximum number of prefixes accepted from a peer and options. diff --git a/website/docs/r/chassis_cluster.html.markdown b/website/docs/r/chassis_cluster.html.markdown new file mode 100644 index 00000000..681c2455 --- /dev/null +++ b/website/docs/r/chassis_cluster.html.markdown @@ -0,0 +1,77 @@ +--- +layout: "junos" +page_title: "Junos: junos_chassis_cluster" +sidebar_current: "docs-junos-resource-chassis-cluster" +description: |- + Configure chassis cluster configuration (when Junos device supports it) +--- + +# junos_chassis_cluster + +-> **Note:** This resource should only be created **once**. It's used to configure static (not object) options in `chassis cluster` block and `interfaces fab0/1`. + +Configure static configuration in `chassis cluster` block and `interfaces fab0/1`. + +## Example Usage + +```hcl +# Configure chassis cluster +resource "junos_chassis_cluster" "cluster" { + fab0 { + member_interfaces = ["ge-0/0/3"] + } + redundancy_group { # id 0 + node0_priority = 100 + node1_priority = 50 + } + redundancy_group { # id 1 + node0_priority = 100 + node1_priority = 50 + interface_monitor { + name = "ge-0/0/4" + weight = 255 + } + interface_monitor { + name = "ge-0/0/5" + weight = 254 + } + } + reth_count = 2 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `fab0` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'interfaces fab0' configuration. + * `member_interfaces` - (Optional)(`ListOfString`) Member interfaces for the fabric interface. + * `description` - (Optional)(`String`) Text description of interface. +* `fab1` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'interfaces fab1' configuration. + * `member_interfaces` - (Optional)(`ListOfString`) Member interfaces for the fabric interface. + * `description` - (Optional)(`String`) Text description of interface. +* `redundancy_group` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each redundancy-group to declare. First in list have id=0, second id=1, etc. + * `node0_priority` - (Required)(`Int`) Priority of the node in the redundancy-group (1..254). + * `node1_priority` - (Required)(`Int`) Priority of the node in the redundancy-group (1..254). + * `gratuitous_arp_count` - (Optional)(`Int`) Number of gratuitous ARPs to send on an active interface after failover (1..16). + * `hold_down_interval` - (Optional)(`Int`) RG failover interval. RG0(300-1800) RG1+(0-1800) (0..1800 seconds) + * `interface_monitor` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each monitoring interface to declare. See the [`interface_monitor` arguments for redundancy_group] (#interface_monitor-arguments-for-redundancy_group) block. + * `preempt` - (Optional)(`Bool`) Allow preemption of primaryship based on priority. +* `reth_count` - (Required)(`Int`) Number of redundant ethernet interfaces (1..128) +* `config_sync_no_secondary_bootup_auto` - (Optional)(`Bool`) Disable auto configuration synchronize on secondary bootup. +* `control_link_recovery` - (Optional)(`Bool`) Enable automatic control link recovery. +* `heartbeat_interval` - (Optional)(`Int`) Interval between successive heartbeats (1000..2000 milliseconds). +* `heartbeat_threshold` - (Optional)(`Int`) Number of consecutive missed heartbeats to indicate device failure (3..8). + +--- +#### interface_monitor arguments for redundancy_group +* `name` - (Required)(`String`) Name of the interface to monitor. +* `weight` - (Required)(`Int`) Weight assigned to this interface that influences failover (0..255). + +## Import + +Junos chassis cluster can be imported using any id, e.g. + +``` +$ terraform import junos_chassis_cluster.cluster random +``` diff --git a/website/docs/r/group_dual_system.html.markdown b/website/docs/r/group_dual_system.html.markdown new file mode 100644 index 00000000..36181413 --- /dev/null +++ b/website/docs/r/group_dual_system.html.markdown @@ -0,0 +1,78 @@ +--- +layout: "junos" +page_title: "Junos: junos_group_dual_system" +sidebar_current: "docs-junos-group-dual-system" +description: |- + Create a group for member of dual system (node/re) +--- + +# junos_group_dual_system + +Provides a group resource for member of dual system (node/re). + +## Example Usage + +```hcl +# Configure a group for member of dual system. +resource "junos_group_dual_system" "node0" { + name = "node0" + interface_fxp0 { + description = "demo" + family_inet_address { + cidr_ip = "192.0.2.193/26" + } + family_inet_address { + cidr_ip = "192.0.2.194/26" + master_only = true + } + } + routing_options { + static_route { + destination = "192.0.2.0/26" + next_hop = ["192.0.2.254"] + } + } + system { + host_name = "test_node" + backup_router_address = "192.0.2.254" + backup_router_destination = ["192.0.2.0/26"] + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required, Forces new resource)(`String`) Name of group. +* `apply_groups` - (Optional)(`Bool`) Apply the group. Defaults to `true`. +* `interface_fxp0` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for configure `fxp0` interface. See the [`interface_fxp0` arguments] (#interface_fxp0-arguments) block. +* `routing_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for configure `routing-options` block. See the [`routing_options` arguments] (#routing_options-arguments) block. +* `security` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for configure `security` block. + * `log_source_address` - (Required)(`String`) Source ip address used when exporting security logs. +* `system` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) +Can be specified only once for configure `system` block. + * `host_name` - (Optional)(`String`) Hostname. + * `backup_router_address` - (Optional)(`String`) IPv4 address backup router. + * `backup_router_destination` - (Optional)(`ListOfString`) Destinations network reachable through the router. + +--- +#### interface_fxp0 arguments +* `description` - (Optional)(`String`) Description for interface. +* `family_inet_address` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each ip address to declare. + * `cidr_ip` - (Required)(`String`) Address IP/Mask v4. + * `master_only` - (Optional)(`Bool`) Master management IP address. + +--- +#### routing_options arguments +* `static_route` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each destination to declare. + * `destination` - (Required)(`String`) The destination for static route. + * `next_hop` - (Required)(`ListOfString`) List of next-hop. + +## Import + +Junos group can be imported using an id made up of ``, e.g. + +``` +$ terraform import junos_group_dual_system.node0 node0 +``` diff --git a/website/docs/r/interface_logical.html.markdown b/website/docs/r/interface_logical.html.markdown index a2d0b6d2..a2750461 100644 --- a/website/docs/r/interface_logical.html.markdown +++ b/website/docs/r/interface_logical.html.markdown @@ -45,6 +45,8 @@ The following arguments are supported: * `mtu` - (Optional)(`Int`) Maximum transmission unit. * `rpf_check` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for enable reverse-path-forwarding checks on this interface. See the [`rpf_check` arguments](#rpf_check-arguments) block for optional arguments. * `routing_instance` - (Optional)(`String`) Add this interface in routing_instance. Need to be created before. +* `security_inbound_protocols` - (Optional)(`ListOfString`) The inbound protocols allowed. Must be a list of Junos protocols. `security_zone` need to be set. +* `security_inbound_services` - (Optional)(`ListOfString`) The inbound services allowed. Must be a list of Junos services. `security_zone` need to be set. * `security_zone` - (Optional)(`String`) Add this interface in security_zone. Need to be created before. * `vlan_id` - (Optional,Computed)(`Int`) 802.1q VLAN ID for unit interface. If not set, computed with `name` of interface (ge-0/0/0.100 = 100) except if name has '.0' suffix or 'st0.' prefix. diff --git a/website/docs/r/interface_physical.html.markdown b/website/docs/r/interface_physical.html.markdown index 4ac172ff..df91bf91 100644 --- a/website/docs/r/interface_physical.html.markdown +++ b/website/docs/r/interface_physical.html.markdown @@ -30,21 +30,91 @@ resource junos_interface_physical "interface_fw_demo" { ## Argument Reference +~> **NOTE:** This resource computes the maximum number of aggregate interfaces required with the current configuration (searches lines `ether-options 802.3ad` and `ae` interfaces set) then add/remove `chassis aggregated-devices ethernet device-count` line with this maximum. + The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) Name of physical interface (without dot). * `no_disable_on_destroy` - (Optional)(`Bool`) When destroy this resource, delete all configurations => do not add `disable` + `descrition NC` or `apply-groups` with `group_interface_delete` provider argument on interface. -* `ae_lacp` - (Optional)(`String`) Add lacp option in aggregated-ether-options. Need to be 'active' or 'passive' for initiate transmission or respond. -* `ae_link_speed` - (Optional)(`String`) Link speed of individual interface that joins the AE. -* `ae_minimum_links` - (Optional)(`Int`) Minimum number of aggregated links (1..8). +* `ae_lacp` - (Optional,**DEPRECATED**)(`String`) Add lacp option in aggregated-ether-options. Need to be 'active' or 'passive' for initiate transmission or respond. +Deprecated argument, use the `parent_ether_opts` argument instead. +* `ae_link_speed` - (Optional,**DEPRECATED**)(`String`) Link speed of individual interface that joins the AE. +Deprecated argument, use the `parent_ether_opts` argument instead. +* `ae_minimum_links` - (Optional,**DEPRECATED**)(`Int`) Minimum number of aggregated links. +Deprecated argument, use the `parent_ether_opts` argument instead. * `description` - (Optional)(`String`) Description for interface. -* `ether802_3ad` - (Optional)(`String`) Name of aggregated device for add this interface to link of 802.3ad interface. +* `esi` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to define ESI Config parameters. See the [`esi` arguments](#esi-arguments) block. +* `ether_opts` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ether-options' configuration. Conflict with 'gigether_opts'. + * `ae_8023ad` - (Optional)(`String`) Name of an aggregated Ethernet interface to join. + * `auto_negotiation` - (Optional)(`Bool`) Enable auto-negotiation. + * `no_auto_negotiation` - (Optional)(`Bool`) Don't enable auto-negotiation. + * `flow_control` - (Optional)(`Bool`) Enable flow control. + * `no_flow_control` - (Optional)(`Bool`) Don't enable flow control. + * `loopback` - (Optional)(`Bool`) Enable loopback. + * `no_loopback` - (Optional)(`Bool`) Don't enable loopback. + * `redundant_parent` - (Optional)(`String`) Name of a redundant ethernet interface to join. +* `ether802_3ad` - (Optional,**DEPRECATED**)(`String`) Name of aggregated device for add this interface to link of 802.3ad interface. +Deprecated argument, use the `ether_opts` or `gigether_opts` argument instead. +* `gigether_opts` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'gigether-options' configuration. Conflict with 'ether_opts'. + * `ae_8023ad` - (Optional)(`String`) Name of an aggregated Ethernet interface to join. + * `auto_negotiation` - (Optional)(`Bool`) Enable auto-negotiation. + * `no_auto_negotiation` - (Optional)(`Bool`) Don't enable auto-negotiation. + * `flow_control` - (Optional)(`Bool`) Enable flow control. + * `no_flow_control` - (Optional)(`Bool`) Don't enable flow control. + * `loopback` - (Optional)(`Bool`) Enable loopback. + * `no_loopback` - (Optional)(`Bool`) Don't enable loopback. + * `redundant_parent` - (Optional)(`String`) Name of a redundant ethernet interface to join. +* `parent_ether_opts` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'aggregated-ether-options' or 'redundant-ether-options' configuration (it depends on the interface 'name'). See the [`parent_ether_opts` arguments](#parent_ether_opts-arguments) block. * `trunk` - (Optional)(`Bool`) Interface mode is trunk. * `vlan_members` - (Optional)(`ListOfString`) List of vlan for membership for this interface. * `vlan_native` - (Optional)(`Int`) Vlan for untagged frames. * `vlan_tagging` - (Optional)(`Bool`) Add 802.1q VLAN tagging support. -~> **NOTE:** This resource computes the maximum number of aggregate interfaces required with the current configuration (searches lines `ether-options 802.3ad` and `ae` interfaces set) then add/remove `chassis aggregated-devices ethernet device-count` line with this maximum. +--- +#### esi arguments +* `mode` - (Required)(`String`) ESI Mode +* `identifier` - (Optional)(`String`) The ESI value for the interface +* `auto_derive_lacp` - (Optional)(`Bool`) Auto-derive ESI value for the interface +* `df_election_type` - (Optional)(`String`) DF Election Type +* `source_bmac` - (Optional)(`String`) Unicast Source B-MAC address per ESI for PBB-EVPN + +--- +#### parent_ether_opts arguments +* `bfd_liveness_detection` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'bfd-liveness-detection' in 'aggregated-ether-options' configuration. See the [`bfd_liveness_detection` arguments in parent_ether_opts](#bfd_liveness_detection-arguments-in-parent_ether_opts) block. +* `flow_control` - (Optional)(`Bool`) Enable flow control. +* `no_flow_control` - (Optional)(`Bool`) Don't enable flow control. +* `lacp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'lacp' configuration. + * `mode` - (Required)(`String`) Active or passive. + * `admin_key` - (Optional)(`Int`) Node's administrative key. + * `periodic` - (Optional)(`String`) Timer interval for periodic transmission of LACP packets. Need to be 'fast' or 'slow'. + * `sync_reset` - (Optional)(`String`) On minimum-link failure notify out of sync to peer. Need to be 'disable' or 'enable'. + * `system_id` - (Optional)(`String`) Node's System ID, encoded as a MAC address + * `system_priority` - (Optional)(`Int`) Priority of the system (0 ... 65535). +* `loopback` - (Optional)(`Bool`) Enable loopback. +* `no_loopback` - (Optional)(`Bool`) Don't enable loopback. +* `link_speed` - (Optional)(`String`) Link speed of individual interface that joins the AE. +* `minimum_bandwidth` - (Optional)(`String`) Minimum bandwidth configured for aggregated bundle. Need to be 'N (k|g|m)?bps' format. +* `minimum_links` - (Optional)(`Int`) Minimum number of aggregated/active links (1..64). +* `redundancy_group` - (Optional)(`Int`) Redundancy group of this interface (1..128) for reth interface. +* `source_address_filter` - (Optional)(`ListOfString`) Source address filters. +* `source_filtering` - (Optional)(`Bool`) Enable source address filtering. + +--- +#### bfd_liveness_detection arguments in parent_ether_opts +* `local_address` - (Required)(`String`) BFD local address. +* `authentication_algorithm` - (Optional)(`String`) Authentication algorithm name. +* `authentication_key_chain` - (Optional)(`String`) Authentication Key chain name. +* `authentication_loose_check` - (Optional)(`Bool`) Verify authentication only if authentication is negotiated. +* `detection_time_threshold` - (Optional)(`Int`) High detection-time triggering a trap (milliseconds). +* `holddown_interval` - (Optional)(`Int`) Time to hold the session-UP notification to the client (0..255000 milliseconds). +* `minimum_interval` - (Optional)(`Int`) Minimum transmit and receive interval (1..255000 milliseconds). +* `minimum_receive_interval` - (Optional)(`Int`) Minimum receive interval (1..255000 milliseconds). +* `multiplier` - (Optional)(`Int`) Detection time multiplier (1..255). +* `neighbor` - (Optional)(`String`) BFD neighbor address. +* `no_adaptation` - (Optional)(`Bool`) Disable adaptation. +* `transmit_interval_minimum_interval` - (Optional)(`Int`) Minimum transmit interval (1..255000 milliseconds). +* `transmit_interval_threshold` - (Optional)(`Int`) High transmit interval triggering a trap (milliseconds). +* `version` - (Optional)(`String`) BFD protocol version number. ## Import diff --git a/website/docs/r/null_commit_file.html.markdown b/website/docs/r/null_commit_file.html.markdown new file mode 100644 index 00000000..4225ac5a --- /dev/null +++ b/website/docs/r/null_commit_file.html.markdown @@ -0,0 +1,36 @@ +--- +layout: "junos" +page_title: "Junos: junos_null_commit_file" +sidebar_current: "docs-junos-resource-null-commmit-file" +description: |- + Load a file with set/delete lines on device and commit +--- + +# junos_null_commit_file + +Load a file with set/delete lines on device and commit + +~> **NOTE:** Not provide a real resource, just load content of file with set/delete to candidate configuration on device, and commit + +## Example Usage + +```hcl +# Load file and commit +variable "setfile" { default = "~/junos/setfile" } +resource junos_null_commit_file "setfile" { + filename = var.setfile + triggers = { + md5 = filemd5(var.setfile) + } + # clear_file_after_commit = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `filename` - (Required, Forces new resource)(`String`) The path of the file to load +* `append_lines` - (Optional, Forces new resource)(`ListOfString`) List of lines append to lines in the loaded file. +* `clear_file_after_commit` - (Optional, Forces new resource)(`Bool`) Truncate file after successful commit. +* `triggers` - (Optional, Forces new resource)(`Map`) A map of arbitrary strings that, when changed, will force the resource to be replaced. diff --git a/website/docs/r/policyoptions_policy_statement.html.markdown b/website/docs/r/policyoptions_policy_statement.html.markdown index de057ec7..49adb772 100644 --- a/website/docs/r/policyoptions_policy_statement.html.markdown +++ b/website/docs/r/policyoptions_policy_statement.html.markdown @@ -106,16 +106,16 @@ The following arguments are supported: * `value` - (Required)(`String`) Value for action * `default_action` - (Optional)(`String`) Set default policy action. Can be 'accept' or 'reject'. * `load_balance` - (Optional)(`String`) Type of load balancing in forwarding table. Can be 'per-packet' or 'consistent-hash'. -* `local_preference` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare local-preference action. +* `local_preference` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare local-preference action. * `action` - (Required)(`String`) Action on local-preference. Need to be 'add', 'subtract' or 'none'. * `value` - (Required)(`String`) Value for action * `next` - (Optional)(`String`) Skip to next 'policy' or 'term'. * `next_hop` - (Optional)(`String`) Set the address of the next-hop router -* `metric` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare metric action. +* `metric` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare metric action. * `action` - (Required)(`String`) Action on metric. Need to be 'add', 'subtract' or 'none'. * `value` - (Required)(`String`) Value for action * `origin` - (Optional)(`String`) BGP path origin -* `preference` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare preference action. +* `preference` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare preference action. * `action` - (Required)(`String`) Action on preference. Need to be 'add', 'subtract' or 'none'. * `value` - (Required)(`String`) Value for action diff --git a/website/docs/r/routing_options.html.markdown b/website/docs/r/routing_options.html.markdown index f99102d6..f48b8350 100644 --- a/website/docs/r/routing_options.html.markdown +++ b/website/docs/r/routing_options.html.markdown @@ -28,11 +28,11 @@ resource junos_routing_options "routing_options" { The following arguments are supported: -* `autonomous_system` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'autonomous-system' configuration. +* `autonomous_system` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'autonomous-system' configuration. * `number` - (Required)(`String`) Autonomous system number in plain number or 'higher 16bits'.'Lower 16 bits' (asdot notation) format. * `asdot_notation` - (Optional)(`Bool`) Use AS-Dot notation to display true 4 byte AS numbers. * `loops` - (Optional)(`Int`) Maximum number of times this AS can be in an AS path (1..10). -* `graceful_restart` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'graceful-restart' configuration. +* `graceful_restart` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'graceful-restart' configuration. * `disable` - (Optional)(`Bool`) Disable graceful restart. * `restart_duration` - (Optional)(`Int`) Maximum time for which router is in graceful restart (120..10000). diff --git a/website/docs/r/security.html.markdown b/website/docs/r/security.html.markdown index da0f1c37..bc540bf8 100644 --- a/website/docs/r/security.html.markdown +++ b/website/docs/r/security.html.markdown @@ -30,16 +30,17 @@ resource junos_security "security" { The following arguments are supported: -* `alg` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'alg' configuration. See the [`alg` arguments] (#alg-arguments) block. -* `flow` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow' configuration. See the [`flow` arguments] (#flow-arguments) block. -* `forwarding_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'forwarding-options' configuration. See the [`forwarding_options` arguments] (#forwarding_options-arguments) block. -* `ike_traceoptions` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ike traceoptions' configuration. - * `file` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'file' configuration. See the [`file` arguments for ike_traceoptions] (#file-arguments-for-ike_traceoptions) block. +* `alg` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'alg' configuration. See the [`alg` arguments] (#alg-arguments) block. +* `flow` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow' configuration. See the [`flow` arguments] (#flow-arguments) block. +* `forwarding_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'forwarding-options' configuration. See the [`forwarding_options` arguments] (#forwarding_options-arguments) block. +* `ike_traceoptions` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ike traceoptions' configuration. + * `file` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'file' configuration. See the [`file` arguments for ike_traceoptions] (#file-arguments-for-ike_traceoptions) block. * `flag` - (Optional)(`ListOfString`) Tracing parameters for IKE. * `rate_limit` - (Optional)(`Int`) Limit the incoming rate of trace messages (0..4294967295) -* `log` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'log' configuration. See the [`log` arguments] (#log-arguments) block. -* `utm` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'utm' configuration. +* `log` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'log' configuration. See the [`log` arguments] (#log-arguments) block. +* `utm` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'utm' configuration. * `feature_profile_web_filtering_type` - (Optional)(`String`) Configuring feature-profile web-filtering type. Need to be 'juniper-enhanced', 'juniper-local', 'web-filtering-none' or 'websense-redirect'. + * `feature_profile_web_filtering_juniper_enhanced_server` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'server' configuration. See the [`feature_profile_web_filtering_juniper_enhanced_server` arguments for utm] (#feature_profile_web_filtering_juniper_enhanced_server-arguments-for-utm) block. --- #### alg arguments @@ -67,11 +68,11 @@ The following arguments are supported: --- #### flow arguments -* `advanced_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow advanced-options' configuration. +* `advanced_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow advanced-options' configuration. * `drop_matching_reserved_ip_address` - (Optional)(`Bool`) Drop matching reserved source IP address. * `drop_matching_link_local_address` - (Optional)(`Bool`) Drop matching link local address. * `reverse_route_packet_mode_vr` - (Optional)(`Bool`) Allow reverse route lookup with packet mode vr. -* `aging` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow aging' configuration. +* `aging` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow aging' configuration. * `early_ageout` - (Optional)(`Int`) Delay before device declares session invalid (1..65535 seconds). * `high_watermark` - (Optional)(`Bool`) Percentage of session-table capacity at which aggressive aging-out starts (0..100 percent). * `low_watermark` - (Optional)(`Bool`) Percentage of session-table capacity at which aggressive aging-out ends (0..100 percent). @@ -79,7 +80,7 @@ The following arguments are supported: * `allow_embedded_icmp` - (Optional)(`Bool`) Allow embedded ICMP packets not matching a session to pass through. * `allow_reverse_ecmp` - (Optional)(`Bool`) Allow reverse ECMP route lookup. * `enable_reroute_uniform_link_check_nat` - (Optional)(`Bool`) Enable reroute check with uniform link and NAT check. -* `ethernet_switching` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow ethernet-switching' configuration. +* `ethernet_switching` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow ethernet-switching' configuration. * `block_non_ip_all` - (Optional)(`Bool`) Block all non-IP and non-ARP traffic including broadcast/multicast. * `bypass_non_ip_unicast` - (Optional)(`Bool`) Allow all non-IP (including unicast) traffic. * `bpdu_vlan_flooding` - (Optional)(`Bool`) Set 802.1D BPDU flooding based on VLAN. @@ -93,7 +94,7 @@ The following arguments are supported: * `route_change_timeout` - (Optional)(`Int`) Timeout value for route change to nonexistent route (6..1800 seconds). * `syn_flood_protection_mode` - (Optional)(`String`) TCP SYN flood protection mode. Need to be 'syn-cookie' or 'syn-proxy'. * `sync_icmp_session` - (Optional)(`Bool`) Allow icmp sessions to sync to peer node. -* `tcp_mss` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow tcp-mss' configuration. +* `tcp_mss` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow tcp-mss' configuration. * `all_tcp_mss` - (Optional)(`Int`) Enable MSS override for all packets with this value. * `gre_in` - Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for enable MSS override for all GRE packets coming out of an IPSec tunnel. There is one argument : `mss` - (Optional)(`Int`) MSS Value. @@ -101,7 +102,7 @@ The following arguments are supported: There is one argument : `mss` - (Optional)(`Int`) MSS Value. * `ipsec_vpn` - Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for enable MSS override for all packets entering IPSec tunnel. There is one argument : `mss` - (Optional)(`Int`) MSS Value. -* `tcp_session` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'flow tcp-session' configuration. +* `tcp_session` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'flow tcp-session' configuration. * `fin_invalidate_session` - (Optional)(`Bool`) Immediately end session on receipt of fin (FIN) segment. * `maximum_window` - Maximum TCP proxy scaled receive window. Need to be '64K', '128K', '256K', '512K' or '1M'. * `no_sequence_check` - (Optional)(`Bool`) Disable sequence-number checking. @@ -111,7 +112,7 @@ The following arguments are supported: * `rst_sequence_check` - (Optional)(`Bool`) Check sequence number in reset (RST) segment. * `strict_syn_check` - (Optional)(`Bool`) Enable strict syn check. Conflict with `no_sync_check` and `no_syn_check_in_tunnel`. * `tcp_initial_timeout` - (Optional)(`Int`) Timeout for TCP session when initialization fails (4..300 seconds). - * `time_wait_state` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare session timeout value in time-wait state. See the [`time_wait_state` arguments for tcp_session in flow] (#time_wait_state-arguments-for-tcp_session-in-flow) block. + * `time_wait_state` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare session timeout value in time-wait state. See the [`time_wait_state` arguments for tcp_session in flow] (#time_wait_state-arguments-for-tcp_session-in-flow) block. --- #### forwarding_options arguments @@ -148,6 +149,13 @@ The following arguments are supported: * `session_ageout` - (Optional)(`Bool`) Allow session to ageout using service based timeout values. * `session_timeout` - (Optional)(`Int`) Configure session timeout value for time-wait state (2..600 seconds). +--- +#### feature_profile_web_filtering_juniper_enhanced_server arguments for utm +* `host` - (Optional)(`String`) Server host IP address or string host name. +* `port` - (Optional)(`Int`) Server port (1..65535). +* `proxy_profile` - (Optional)(`String`) Proxy profile. +* `routing_instance` - (Optional)(`String`) Routing instance name. + ## Import Junos security can be imported using any id, e.g. diff --git a/website/docs/r/security_address_book.html.markdown b/website/docs/r/security_address_book.html.markdown new file mode 100644 index 00000000..e95121e6 --- /dev/null +++ b/website/docs/r/security_address_book.html.markdown @@ -0,0 +1,85 @@ +--- +layout: "junos" +page_title: "Junos: junos_security_address_book" +sidebar_current: "docs-junos-resource-security-address-book" +description: |- + Create a security address book (when Junos device supports it) +--- + +# junos_security_address_book + +Provides a security address book resource. + +## Example Usage + +```hcl +# Add an address book with entries +resource junos_security_address_book "testAddressBook" { + name = "testAddressBook" + attach_zone = ["SecurityZone"] + network_address { + name = "DemoNetworkAddress" + description = "Test Description" + value = "192.0.0.0/24" + } + network_address { + name = "DemoNetworkAddress2" + description = "Test Description 2" + value = "192.1.0.0/24" + } + dns_name { + name = "DemoDnsName" + value = "juniper.net" + } + range_address { + name = "DemoRangeAddress" + from = "192.0.0.1" + to = "192.0.0.10" + } + wildcard_address { + name = "DemoWildcardAddress" + value = "juniper.net" + } + address_set { + name = "DemoAddressSet" + address = ["DemoDnsName", "DemoWildcardAddress", "DemoRangeAddress"] + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional, Forces new resource)(`String`) The name of address book. Defaults to `global`. +* `description` - (Optional)(`String`) The description of the address book. +* `attach_zone` - (Optional)(`ListOfString`) List of zones to attach address book to. **NOTE:** Cannot be set on global address book. +* `network_address` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each network address. + * `name` - (Required)(`String`) Name of network address. + * `description` - (Optional)(`String`) Description of network address. + * `value` - (Required)(`String`) CIDR value of network address. `192.0.0.0/24` +* `wildcard_address` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each wildcard address. + * `name` - (Required)(`String`) Name of wildcard address. + * `description` - (Optional)(`String`) Description of network address. + * `value` - (Required)(`String`) Nework and Mask of wildcard address. `192.0.0.0/255.255.0.255` +* `dns_name` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each dns name address. + * `name` - (Required)(`String`) Name of dns name address. + * `description` - (Optional)(`String`) Description of dns name address. + * `value` - (Required)(`String`) DNS name string value. `juniper.net` +* `range_address` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each range address. + * `name` - (Required)(`String`) Name of range address. + * `description` - (Optional)(`String`) Description of range address. + * `from` - (Required)(`String`) IP address of start of range. + * `to` - (Required)(`String`) IP address of end of range. +* `address_book_set` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each address-set to declare. + * `name` - (Required)(`String`) Name of address-set. + * `description` - (Optional)(`String`) Description of address-set. + * `address` - (Required)(`ListOfString`) List of address names. + +## Import + +Junos security address book can be imported using an id made up of ``, e.g. + +```sh +$ terraform import junos_security_address_book.global global +``` diff --git a/website/docs/r/security_global_policy.html.markdown b/website/docs/r/security_global_policy.html.markdown new file mode 100644 index 00000000..c1cd8230 --- /dev/null +++ b/website/docs/r/security_global_policy.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "junos" +page_title: "Junos: junos_security_global_policy" +sidebar_current: "docs-junos-resource-security-global-policy" +description: |- + Configure static configuration in security policies global block +--- + +# junos_security_global_policy + +-> **Note:** This resource should only be created **once**. It's used to configure static (not object) options in `security policies global` block. + +Configure static configuration in `security policies global` block + +## Example Usage + +```hcl +# Configure security policies global +resource junos_security_global_policy "global" { + policy { + name = "test" + match_source_address = ["blue"] + match_destination_address = ["green"] + match_application = ["any"] + match_from_zone = ["any"] + match_to_zone = ["any"] + } + policy { + name = "drop" + match_source_address = ["blue"] + match_destination_address = ["any"] + match_application = ["any"] + match_from_zone = ["any"] + match_to_zone = ["any"] + then = "deny" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `policy` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each policy. + * `name` - (Required)(`String`) Security policy name. + * `match_source_address` - (Required)(`ListOfString`) List of source address match. + * `match_destination_address` - (Required)(`ListOfString`) List of destination address match. + * `match_application` - (Required)(`ListOfString`) List of applications match. + * `match_from_zone` - (Required)(`ListOfString`) Match multiple source zone. + * `match_to_zone` - (Required)(`ListOfString`) Match multiple destination zone. + * `then` - (Optional)(`String`) Action of policy. Defaults to `permit`. + * `count` - (Optional)(`Bool`) Enable count. + * `log_init` - (Optional)(`Bool`) Log at session init time. + * `log_close` - (Optional)(`Bool`) Log at session close time. + * `permit_application_services` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'permit application-services' configuration. See the [`permit_application_services` arguments] (#permit_application_services-arguments) block. + +--- +#### permit_application_services arguments +* `application_firewall_rule_set` - (Optional)(`String`) Servie rule-set Name for Application firewall. +* `application_traffic_control_rule_set` - (Optional)(`String`) Service rule-set name Application traffic control. +* `gprs_gtp_profile` - (Optional)(`String`) Specify GPRS Tunneling Protocol profile name. +* `gprs_sctp_profile` - (Optional)(`String`) Specify GPRS stream control protocol profile name. +* `idp` - (Optional)(`Bool`) Enable Intrusion detection and prevention. +* `redirect_wx` - (Optional)(`Bool`) Set WX redirection. +* `reverse_redirect_wx` - (Optional)(`Bool`) Set WX reverse redirection. +* `security_intelligence_policy` - (Optional)(`String`) Specify security-intelligence policy name. +* `ssl_proxy` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to enable SSL Proxy. + * `profile_name` - (Optional)(`String`) Specify SSL proxy service profile name. +* `uac_policy` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to enable unified access control enforcement. + * `captive_portal` - (Optional)(`String`) Specify captive portal. +* `utm_policy` - (Optional)(`String`) Specify utm policy name. + +## Import + +Junos security global policies can be imported using any id, e.g. + +``` +$ terraform import junos_security_global_policy.global random +``` diff --git a/website/docs/r/security_ike_gateway.html.markdown b/website/docs/r/security_ike_gateway.html.markdown index 3562a937..1d4f506c 100644 --- a/website/docs/r/security_ike_gateway.html.markdown +++ b/website/docs/r/security_ike_gateway.html.markdown @@ -31,19 +31,19 @@ The following arguments are supported: * `external_interface` - (Required)(`String`) Interface for ike negotiations. * `policy` - (Required)(`String`) Ike policy. * `address` - (Optional)(`ListOfString`) List of Peer IP. Need to set one of `address` or `dynamic_remote`. -* `dynamic_remote` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare dynamic configuration. See the [`dynamic_remote` arguments] (#dynamic_remote-arguments) block. Need to set one of `address` or `dynamic_remote`. -* `aaa` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'aaa' configuration. +* `dynamic_remote` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare dynamic configuration. See the [`dynamic_remote` arguments] (#dynamic_remote-arguments) block. Need to set one of `address` or `dynamic_remote`. +* `aaa` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'aaa' configuration. * `access_profile` - (Optional)(`String`) Access profile that contains authentication information. Conflict with `aaa.client_*`. * `client_password` - (Optional)(`String`) AAA client password with 1 to 128 characters. Conflict with `aaa.access_profile`. * `client_username` - (Optional)(`String`) AAA client username with 1 to 128 characters. Conflict with `aaa.access_profile`. -* `dead_peer_detection` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare RFC-3706 DPD configuration. See the [`dead_peer_detection` arguments] (#dead_peer_detection-arguments) block. +* `dead_peer_detection` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare RFC-3706 DPD configuration. See the [`dead_peer_detection` arguments] (#dead_peer_detection-arguments) block. * `general_ike_id` - (Optional)(`Bool`) Accept peer IKE-ID in general. * `local_address` - (Optional)(`String`) Local IP for ike negotiations. -* `local_identity` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare local IKE identity configuration. +* `local_identity` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare local IKE identity configuration. * `type` - (Required)(`String`) Type of IKE identity. * `value` - (Optional)(`String`) Value for IKE identity. * `no_nat_traversal` - (Optional)(`Bool`) Disable IPSec NAT traversal. -* `remote_identity` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare remote IKE identity configuration. +* `remote_identity` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare remote IKE identity configuration. * `type` - (Required)(`String`) Type of IKE identity. * `value` - (Optional)(`String`) Value for IKE identity. * `version` - (Optional)(`String`) Negotiate using either IKE v1 or IKE v2 protocol. Need to be 'v1-only' or 'v2-only'. @@ -52,7 +52,7 @@ The following arguments are supported: #### dynamic_remote arguments -> **Note:** You can only choose one argument between `distinguished_name`, `hostname`, `inet`, `inet6` and `user_at_hostname`. * `connections_limit` - (Optional)(`Int`) Maximum number of users connected to gateway. -* `distinguished_name` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare distinguished-name configuration. +* `distinguished_name` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare distinguished-name configuration. * `container` - (Optional)(`String`) Container string for a distinguished name. * `wildcard` - (Optional)(`String`) Wildcard string for a distinguished name. * `hostname` - (Optional)(`String`) Use a fully-qualified domain name. diff --git a/website/docs/r/security_ipsec_vpn.html.markdown b/website/docs/r/security_ipsec_vpn.html.markdown index 9602f5a4..653d3a67 100644 --- a/website/docs/r/security_ipsec_vpn.html.markdown +++ b/website/docs/r/security_ipsec_vpn.html.markdown @@ -36,7 +36,7 @@ The following arguments are supported: Deprecated argument, use the `junos_interface_st0_unit` resource to find st0 unit available instead. * `df_bit` - (Optional)(`String`) Specifies how to handle the Don't Fragment bit. Need to be 'clear', 'copy' or 'set'. * `establish_tunnels` - (Optional)(`String`) When the VPN comes up. Need to be 'immediately' or 'on-traffic'. -* `ike` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare ike configuration. +* `ike` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare ike configuration. * `gateway` - (Required)(`String`) The name of security ike gateway (phase-1). * `policy` - (Required)(`String`) The name of ipsec policy. * `identity_local` - (Optional)(`String`) IPSec proxy-id local parameter. @@ -46,7 +46,7 @@ Deprecated argument, use the `junos_interface_st0_unit` resource to find st0 uni * `name` - (Required)(`String`) Name of traffic-selector. * `local_ip` - (Required)(`String`) CIDR for IP addresses of local traffic-selector. * `remote_ip` - (Required)(`String`) CIDR for IP addresses of remote traffic-selector. -* `vpn_monitor` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare VPN monitor liveness configuration. +* `vpn_monitor` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare VPN monitor liveness configuration. * `destination_ip` - (Optional)(`String`) IP destination for monitor message. * `optimized` - (Optional)(`Bool`) Optimize for scalability. * `source_interface` - (Optional)(`String`) Set source interface for monitor message. Compute when `source_interface_auto` = true. diff --git a/website/docs/r/security_nat_destination.html.markdown b/website/docs/r/security_nat_destination.html.markdown index 81e364a7..2229008d 100644 --- a/website/docs/r/security_nat_destination.html.markdown +++ b/website/docs/r/security_nat_destination.html.markdown @@ -36,7 +36,7 @@ resource junos_security_nat_destination "demo_dnat" { The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) The name of destination nat. -* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'from' configuration. +* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'from' configuration. * `type` - (Required)(`String`) Type of from options. Need to be 'interface', 'routing-instance' or 'zone' * `value` - (Required)(`String`) Name of interface, routing-instance or zone for from options * `rule` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each rule to declare. See the [`rule` arguments](#rule-arguments) block. @@ -45,7 +45,7 @@ The following arguments are supported: #### rule arguments * `name` - (Required)(`String`) Name of rule * `destination_address` - (Required)(`String`) CIDR for match destination address -* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'then' action. +* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'then' action. * `type` - (Required)(`String`) Type of destination nat. Need to be 'pool' or 'off' * `pool` - (Optional)(`String`) Name of nat destination pool when type pool diff --git a/website/docs/r/security_nat_source.html.markdown b/website/docs/r/security_nat_source.html.markdown index eac3bc65..3b76a0ee 100644 --- a/website/docs/r/security_nat_source.html.markdown +++ b/website/docs/r/security_nat_source.html.markdown @@ -42,10 +42,10 @@ resource junos_security_nat_source "demo_snat" { The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) The name of source nat. -* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'from' configuration. +* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'from' configuration. * `type` - (Required)(`String`) Type of from options. Need to be 'interface', 'routing-instance' or 'zone'. * `value` - (Required)(`String`) Name of interface, routing-instance or zone for from options. -* `to` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'to' configuration. +* `to` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'to' configuration. * `type` - (Required)(`String`) Type of to options. Need to be 'interface', 'routing-instance' or 'zone'. * `value` - (Required)(`String`) Name of interface, routing-instance or zone for to options. * `rule` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each rule to declare. See the [`rule` arguments](#rule-arguments) block. @@ -53,11 +53,11 @@ The following arguments are supported: --- #### rule arguments * `name` - (Required)(`String`) Name of rule. -* `match` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'match' configuration. +* `match` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'match' configuration. * `destination_address` - (Optional)(`ListOfString`) CIDR list to match destination address. * `protocol` - (Optional)(`ListOfString`) Protocol list to match. * `source_address` - (Optional)(`ListOfString`) CIDR list to match source address. -* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'then' configuration. +* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'then' configuration. * `type` - (Required)(`String`) Type of source nat. Need to be 'interface', 'pool' or 'off'. * `pool` - (Optional)(`String`) Name of nat source pool when type pool. diff --git a/website/docs/r/security_nat_static.html.markdown b/website/docs/r/security_nat_static.html.markdown index 24e7ba5d..cb9af19d 100644 --- a/website/docs/r/security_nat_static.html.markdown +++ b/website/docs/r/security_nat_static.html.markdown @@ -36,7 +36,7 @@ resource junos_security_nat_static "demo_nat" { The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) The name of static nat. -* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'from' configuration. +* `from` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'from' configuration. * `type` - (Required)(`String`) Type of from options. Need to be 'interface', 'routing-instance' or 'zone'. * `value` - (Required)(`String`) Name of interface, routing-instance or zone for from options. * `rule` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified multiple times for each rule to declare. See the [`rule` arguments](#rule-arguments) block. @@ -45,7 +45,7 @@ The following arguments are supported: #### rule arguments * `name` - (Required)(`String`) Name of rule. * `destination_address` - (Required)(`String`) CIDR of destination address for rule. -* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'then' configuration. +* `then` - (Required)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'then' configuration. * `type` - (Required)(`String`) Type of static nat. Need to be 'inet' or 'prefix'. * `prefix` - (Optional)(`String`) CIDR for prefix static nat. * `routing_instance` - (Optional)(`String`) Change routing_instance with nat. diff --git a/website/docs/r/security_policy.html.markdown b/website/docs/r/security_policy.html.markdown index 3b7aa846..e420e913 100644 --- a/website/docs/r/security_policy.html.markdown +++ b/website/docs/r/security_policy.html.markdown @@ -37,7 +37,7 @@ The following arguments are supported: * `match_source_address` - (Required)(`ListOfString`) List of source address match. * `match_destination_address` - (Required)(`ListOfString`) List of destination address match. * `match_application` - (Required)(`ListOfString`) List of applications match. - * `then` - (Optional)(`String`) action of policy. Defaults to `permit`. + * `then` - (Optional)(`String`) Action of policy. Defaults to `permit`. * `count` - (Optional)(`Bool`) Enable count. * `log_init` - (Optional)(`Bool`) Log at session init time. * `log_close` - (Optional)(`Bool`) Log at session close time. @@ -55,7 +55,7 @@ The following arguments are supported: * `reverse_redirect_wx` - (Optional)(`Bool`) Set WX reverse redirection. * `security_intelligence_policy` - (Optional)(`String`) Specify security-intelligence policy name. * `ssl_proxy` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html) Enable SSL Proxy. Max of 1. - * `profile_name` - (Optional)(`String`) Specify SSL proxy service profile name. + * `profile_name` - (Optional)(`String`) Specify SSL proxy service profile name. * `uac_policy` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html) Enable unified access control enforcement. Max of 1. * `captive_portal` - (Optional)(`String`) Specify captive portal. * `utm_policy` - (Optional)(`String`) Specify utm policy name. diff --git a/website/docs/r/security_screen.html.markdown b/website/docs/r/security_screen.html.markdown index ea5ba2fc..53c1c825 100644 --- a/website/docs/r/security_screen.html.markdown +++ b/website/docs/r/security_screen.html.markdown @@ -45,13 +45,13 @@ The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) The name of screen. * `alarm_without_drop` - (Optional)(`Bool`) Do not drop packet, only generate alarm. * `description` - (Optional)(`String`) Text description of screen. -* `icmp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'icmp' configuration. See the [`icmp` arguments] (#icmp-arguments) block. -* `ip` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ip' configuration. See the [`ip` arguments] (#ip-arguments) block. -* `limit_session` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'limit-session' configuration. +* `icmp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'icmp' configuration. See the [`icmp` arguments] (#icmp-arguments) block. +* `ip` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ip' configuration. See the [`ip` arguments] (#ip-arguments) block. +* `limit_session` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'limit-session' configuration. * `destination_ip_based` - (Optional)(`ListOfString`) Limit sessions to the same destination IP (1..2000000). * `source_ip_based` - (Optional)(`ListOfString`) Limit sessions from the same source IP (1..2000000). -* `tcp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'tcp' configuration. See the [`tcp` arguments] (#tcp-arguments) block. -* `udp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'udp' configuration. See the [`udp` arguments] (#udp-arguments) block. +* `tcp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'tcp' configuration. See the [`tcp` arguments] (#tcp-arguments) block. +* `udp` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'udp' configuration. See the [`udp` arguments] (#udp-arguments) block. --- #### icmp arguments @@ -68,7 +68,7 @@ The following arguments are supported: #### ip arguments * `bad_option` - (Optional)(`Bool`) Enable ip with bad option ids option. * `block_frag` - (Optional)(`Bool`) Enable ip fragment blocking ids option. -* `ipv6_extension_header` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ip ipv6-extension-header' configuration. See the [`ipv6_extension_header` arguments for ip] (#ipv6_extension_header-arguments-for-ip) block. +* `ipv6_extension_header` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ip ipv6-extension-header' configuration. See the [`ipv6_extension_header` arguments for ip] (#ipv6_extension_header-arguments-for-ip) block. * `ipv6_extension_header_limit` - (Optional)(`Int`) Enable ipv6 extension header limit ids option (0..32). * `ipv6_malformed_header` - (Optional)(`Bool`) Enable ipv6 malformed header ids option. * `loose_source_route_option` - (Optional)(`Bool`) Enable ip with loose source route ids option. @@ -80,7 +80,7 @@ The following arguments are supported: * `strict_source_route_option` - (Optional)(`Bool`) Enable ip with strict source route ids option. * `tear_drop` - (Optional)(`Bool`) Enable tear drop ids option. * `timestamp_option` - (Optional)(`Bool`) Enable ip with timestamp option ids option. -* `tunnel` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ip tunnel' configuration. See the [`tunnel` arguments for ip] (#tunnel-arguments-for-ip) block. +* `tunnel` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ip tunnel' configuration. See the [`tunnel` arguments for ip] (#tunnel-arguments-for-ip) block. * `unknown_protocol` - (Optional)(`Bool`) Enable ip unknown protocol ids option. --- @@ -138,13 +138,13 @@ The following arguments are supported: --- #### tunnel arguments for ip * `bad_inner_header` - (Optional)(`Bool`) Enable IP tunnel bad inner header ids option. -* `gre` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ip tunnel gre' configuration. +* `gre` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ip tunnel gre' configuration. * `gre_4in4` - (Optional)(`Bool`) Enable IP tunnel GRE 4in4 ids option. * `gre_4in6` - (Optional)(`Bool`) Enable IP tunnel GRE 4in6 ids option. * `gre_6in4` - (Optional)(`Bool`) Enable IP tunnel GRE 6in4 ids option. * `gre_6in6` - (Optional)(`Bool`) Enable IP tunnel GRE 6in6 ids option. * `ip_in_udp_teredo` - (Optional)(`Bool`) Enable IP tunnel IPinUDP Teredo ids option. -* `ipip` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ip tunnel ipip' configuration. +* `ipip` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ip tunnel ipip' configuration. * `ipip_4in4` - (Optional)(`Bool`) Enable IP tunnel IPIP 4in4 ids option. * `ipip_4in6` - (Optional)(`Bool`) Enable IP tunnel IPIP 4in6 ids option. * `ipip_6in4` - (Optional)(`Bool`) Enable IP tunnel IPIP 6in4 ids option. diff --git a/website/docs/r/system.html.markdown b/website/docs/r/system.html.markdown index 1cdb6238..309b03eb 100644 --- a/website/docs/r/system.html.markdown +++ b/website/docs/r/system.html.markdown @@ -43,11 +43,11 @@ The following arguments are supported: * `default_address_selection` - (Optional)(`Bool`) Use loopback interface as source address for locally generated packets. * `domain_name` - (Optional)(`String`) Domain name. * `host_name` - (Optional)(`String`) Hostname. -* `inet6_backup_router` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'inet6-backup-router' configuration. +* `inet6_backup_router` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'inet6-backup-router' configuration. * `address` - (Optional)(`String`) Address of router to use while booting. * `destination` - (Optional)(`ListOfString`) Destination networks reachable through the router. -* `internet_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'internet-options' configuration. See the [`internet_options` arguments] (#internet_options-arguments) block. -* `login` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'login' configuration. See the [`login` arguments] (#login-arguments) block. +* `internet_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'internet-options' configuration. See the [`internet_options` arguments] (#internet_options-arguments) block. +* `login` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'login' configuration. See the [`login` arguments] (#login-arguments) block. * `max_configuration_rollbacks` - (Optional)(`Int`) Maximum rollback configuration (0..49). * `max_configurations_on_flash` - (Optional)(`Int`) Number of configuration files stored on flash (0..49). * `name_server` - (Optional)(`ListOfString`) DNS name servers. @@ -56,10 +56,10 @@ The following arguments are supported: * `no_ping_time_stamp` - (Optional)(`Bool`) Do not insert time stamp in ping replies. * `no_redirects` - (Optional)(`Bool`) Disable ICMP redirects. * `no_redirects_ipv6` - (Optional)(`Bool`) Disable IPV6 ICMP redirects. -* `services` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'services' configuration. - * `ssh` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'ssh' configuration. See the [`ssh` arguments for services] (#ssh-arguments-for-services) block. -* `syslog` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'syslog' configuration. - * `archive` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'archive' configuration. See the [`archive` arguments for syslog] (#archive-arguments-for-syslog) block. +* `services` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'services' configuration. + * `ssh` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'ssh' configuration. See the [`ssh` arguments for services] (#ssh-arguments-for-services) block. +* `syslog` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'syslog' configuration. + * `archive` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'archive' configuration. See the [`archive` arguments for syslog] (#archive-arguments-for-syslog) block. * `log_rotate_frequency` - (Optional)(`Int`) Rotate log frequency (1..59 minutes). * `source_address` - (Optional)(`String`) Use specified address as source address. * `time_zone` - (Optional)(`String`) Time zone name or POSIX-compliant time zone string (/ or ). @@ -68,10 +68,10 @@ The following arguments are supported: --- #### internet_options arguments * `gre_path_mtu_discovery` - (Optional)(`Bool`) Enable path MTU discovery for GRE tunnels. Conflict with `no_gre_path_mtu_discovery`. -* `icmpv4_rate_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'icmpv4-rate-limit' configuration. +* `icmpv4_rate_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'icmpv4-rate-limit' configuration. * `bucket_size` - (Optional)(`Int`) ICMP rate-limiting maximum bucket size (seconds). * `packet-rate` - (Optional)(`Int`) ICMP rate-limiting packets earned per second. -* `icmpv6_rate_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'icmpv6-rate-limit' configuration. +* `icmpv6_rate_limit` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'icmpv6-rate-limit' configuration. * `bucket_size` - (Optional)(`Int`) ICMPv6 rate-limiting maximum bucket size (seconds). * `packet-rate` - (Optional)(`Int`) ICMPv6 rate-limiting packets earned per second. * `ipip_path_mtu_discovery` - (Optional)(`Bool`) Enable path MTU discovery for IP-IP tunnels. Conflict with `no_ipip_path_mtu_discovery`. @@ -100,7 +100,7 @@ The following arguments are supported: * `deny_sources_address` - (Optional)(`ListOfString`) Sources from which logins are denied. * `idle_timeout` - (Optional)(`Int`) Maximum idle time before logout (1..60 minutes). * `message` - (Optional)(`String`) System login message. -* `password` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'password' configuration. +* `password` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'password' configuration. * `change_type` - (Optional)(`String`) Password change type. * `format` - (Optional)(`String`) Encryption method to use for password. * `maximum_length` - (Optional)(`Int`) Maximum password length for all users (20..128). @@ -112,7 +112,7 @@ The following arguments are supported: * `minimum_punctuations` - (Optional)(`Int`) Minimum number of punctuation class characters in password (1..128). * `minimum_reuse` - (Optional)(`Int`) Minimum number of old passwords which should not be same as the new password (1..20). * `minimum_upper_cases` - (Optional)(`Int`) Minimum number of upper-case class characters in password (1..128). -* `retry_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'retry-options' configuration. +* `retry_options` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'retry-options' configuration. * `backoff_factor` - (Optional)(`Int`) Delay factor after 'backoff-threshold' password failures (5..10). * `backoff_threshold` - (Optional)(`Int`) Number of password failures before delay is introduced (1..3). * `lockout_period` - (Optional)(`Int`) Amount of time user account is locked after 'tries-before-disconnect' failures (1..43200 minutes). diff --git a/website/docs/r/system_login_user.html.markdown b/website/docs/r/system_login_user.html.markdown index d0ca7ca0..83ee11bd 100644 --- a/website/docs/r/system_login_user.html.markdown +++ b/website/docs/r/system_login_user.html.markdown @@ -30,7 +30,7 @@ The following arguments are supported: * `name` - (Required, Forces new resource)(`String`) The name of system login user. * `class` - (Required)(`String`) Login class. * `uid` - (Optional, Computed, Forces new resource)(`Int`) User identifier (uid) (100..64000). -* `authentication` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare 'authentication' configuration. +* `authentication` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare 'authentication' configuration. * `encrypted_password` - (Optional)(`String`) Encrypted password string. * `no_public_keys` - (Optional)(`Bool`) Disables ssh public key based authentication. * `ssh_public_keys` - (Optional)(`ListOfString`) Secure shell (ssh) public key string. diff --git a/website/docs/r/vlan.html.markdown b/website/docs/r/vlan.html.markdown index 9704ac9f..e1f1f527 100644 --- a/website/docs/r/vlan.html.markdown +++ b/website/docs/r/vlan.html.markdown @@ -37,7 +37,7 @@ The following arguments are supported: * `service_id` - (Optional)(`Int`) Service id (when Junos device supports it). * `vlan_id` - (Optional)(`Int`) 802.1q VLAN identifier. Conflict with `vlan_id_list`. * `vlan_id_list` - (Optional)(`ListOfString`) List of vlan ID. Can be a ID or range (exemple: 10-20). Conflict with `vlan_id`. -* `vxlan` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once for declare vxlan configuration (when Junos device supports it). +* `vxlan` - (Optional)([attribute-as-blocks mode](https://www.terraform.io/docs/configuration/attr-as-blocks.html)) Can be specified only once to declare vxlan configuration (when Junos device supports it). * `vni` - (Required)(`Int`) VXLAN identifier. * `encapsulate_inner_vlan` - (Optional)(`Bool`) Retain inner VLAN in the packet. * `ingress_node_replication` - (Optional)(`Bool`) Enable ingress node replication. diff --git a/website/junos.erb b/website/junos.erb index 3948cc88..abe519f0 100644 --- a/website/junos.erb +++ b/website/junos.erb @@ -33,12 +33,18 @@ > junos_bgp_neighbor + > + junos_chassis_cluster + > junos_firewall_filter > junos_firewall_policer + > + junos_group_dual_system + > junos_interface @@ -51,6 +57,9 @@ > junos_interface_st0_unit + > + junos_null_commit_file + > junos_ospf_area @@ -81,6 +90,12 @@ > junos_security + > + junos_security_address_book + + > + junos_security_global_policy + > junos_security_ike_gateway @@ -123,6 +138,12 @@ > junos_security_policy_tunnel_pair_policy + > + junos_security_screen + + > + junos_security_screen_whitelist + > junos_security_utm_custom_url_category