├── .drone.yml ├── .errcheck_ignore.txt ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md └── SUPPORT.md ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── .prettierignore ├── CHANGELOG.md ├── GNUmakefile ├── README.md ├── go.mod ├── go.sum ├── main.go ├── opnsense ├── data_firewall_alias.go ├── helpers.go ├── provider.go ├── provider_test.go ├── resource_firewall_alias.go ├── resource_firewall_alias_util.go ├── resource_firewall_filter_rule.go ├── resource_firewire_filter_rule_test.go ├── resource_firmware.go ├── resource_firmware_test.go ├── resource_wireguard_client.go ├── resource_wireguard_client_test.go ├── resource_wireguard_server.go └── resource_wireguard_server_test.go ├── renovate.json └── scripts ├── changelog-links.sh ├── errcheck.sh ├── gofmtcheck.sh └── gogetcookie.sh /.drone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "kind": "pipeline", 4 | "name": "Kubernetes", 5 | "node_selector": { "drone": true }, 6 | "platform": { "arch": "amd64", "os": "linux" }, 7 | "steps": 8 | [ 9 | { 10 | "commands": 11 | [ 12 | "npm install prettier", 13 | "echo .pre-commit-config.yaml >> .prettierignore", 14 | 'npx prettier --check "**/*.{ts,js,md,yaml,yml,sass,css,scss,html,htm}"', 15 | ], 16 | "image": "node:lts-buster", 17 | "name": "Prettier lint", 18 | "pull": "always", 19 | }, 20 | { 21 | "commands": 22 | [ 23 | "curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin", 24 | "golangci-lint run -v --timeout 10m", 25 | ], 26 | "image": "golang:1.16-buster", 27 | "name": "Go lint", 28 | "pull": "always", 29 | }, 30 | { 31 | "commands": ["go test ./..."], 32 | "image": "golang:1.16-buster", 33 | "name": "Go test", 34 | "pull": "always", 35 | }, 36 | { 37 | "commands": 38 | [ 39 | "go get github.com/mitchellh/gox", 40 | 'gox -osarch "!darwin/386" -output="dist/{{.Dir}}_{{.OS}}_{{.Arch}}"', 41 | ], 42 | "image": "golang:1.16-buster", 43 | "name": "Go build", 44 | "pull": "always", 45 | }, 46 | { 47 | "environment": { "SSH_KEY": { "from_secret": "ssh_key" } }, 48 | "image": "appleboy/drone-scp", 49 | "name": "Deploy with scp", 50 | "pull": "always", 51 | "settings": 52 | { 53 | "host": "core.terra.fap.no", 54 | "rm": true, 55 | "source": ["dist/*"], 56 | "strip_components": 1, 57 | "target": "/fastest/serve/builds/terraform-provider-opnsense", 58 | "username": "deploy", 59 | }, 60 | "when": { "branch": ["master", "main"], "event": ["push"] }, 61 | }, 62 | ], 63 | "type": "kubernetes", 64 | } 65 | -------------------------------------------------------------------------------- /.errcheck_ignore.txt: -------------------------------------------------------------------------------- 1 | (*schema.ResourceData).Set 2 | (*github.com/hashicorp/terraform/helper/schema.ResourceData).Set 3 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | HashiCorp Community Guidelines apply to you when interacting with the community here on GitHub and contributing code. 4 | 5 | Please read the full text at https://www.hashicorp.com/community-guidelines 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hi there, 2 | 3 | Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see: https://www.terraform.io/community.html. 4 | 5 | ### Terraform Version 6 | 7 | Run `terraform -v` to show the version. If you are not running the latest version of Terraform, please upgrade because your issue may have already been fixed. 8 | 9 | ### Affected Resource(s) 10 | 11 | Please list the resources as a list, for example: 12 | 13 | - opc_instance 14 | - opc_storage_volume 15 | 16 | If this issue appears to affect multiple resources, it may be an issue with Terraform's core, so please mention this. 17 | 18 | ### Terraform Configuration Files 19 | 20 | ```hcl 21 | # Copy-paste your Terraform configurations here - for large Terraform configs, 22 | # please use a service like Dropbox and share a link to the ZIP file. For 23 | # security, you can also encrypt the files using our GPG public key. 24 | ``` 25 | 26 | ### Debug Output 27 | 28 | Please provider a link to a GitHub Gist containing the complete debug output: https://www.terraform.io/docs/internals/debugging.html. Please do NOT paste the debug output in the issue; just paste a link to the Gist. 29 | 30 | ### Panic Output 31 | 32 | If Terraform produced a panic, please provide a link to a GitHub Gist containing the output of the `crash.log`. 33 | 34 | ### Expected Behavior 35 | 36 | What should have happened? 37 | 38 | ### Actual Behavior 39 | 40 | What actually happened? 41 | 42 | ### Steps to Reproduce 43 | 44 | Please list the steps required to reproduce the issue, for example: 45 | 46 | 1. `terraform apply` 47 | 48 | ### Important Factoids 49 | 50 | Are there anything atypical about your accounts that we should know? For example: Running in EC2 Classic? Custom version of OpenStack? Tight ACLs? 51 | 52 | ### References 53 | 54 | Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example: 55 | 56 | - GH-1234 57 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | Terraform is a mature project with a growing community. There are active, dedicated people willing to help you through various mediums. 4 | 5 | Take a look at those mediums listed at https://www.terraform.io/community.html 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | dist/ 3 | website/ 4 | example/ 5 | *.dll 6 | *.exe 7 | .DS_Store 8 | example.tf 9 | terraform.tfplan 10 | terraform.tfstate 11 | bin/ 12 | modules-dev/ 13 | /pkg/ 14 | website/.vagrant 15 | website/.bundle 16 | website/build 17 | website/node_modules 18 | .vagrant/ 19 | *.backup 20 | ./*.tfstate 21 | .terraform/ 22 | *.log 23 | *.bak 24 | *~ 25 | .*.swp 26 | .idea 27 | *.iml 28 | *.test 29 | *.iml 30 | 31 | website/vendor 32 | 33 | # Test exclusions 34 | !command/test-fixtures/**/*.tfstate 35 | !command/test-fixtures/**/.terraform/ 36 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters-settings: 2 | errcheck: 3 | exclude: .errcheck_ignore.txt 4 | 5 | linters: 6 | fast: false 7 | presets: 8 | - style 9 | - bugs 10 | - unused 11 | - format 12 | disable: 13 | - interfacer 14 | - gomnd 15 | - godox 16 | - funlen 17 | - exhaustivestruct 18 | 19 | run: 20 | deadline: 10m 21 | tests: false 22 | # Autogenerated files take too much time and memory to load, 23 | # even if we skip them with skip-dirs. 24 | # So we define this tag and use it in the autogenerated files. 25 | build-tags: 26 | - codeanalysis 27 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | before: 4 | hooks: 5 | # this is just an example and not a requirement for provider building/publishing 6 | - go mod tidy 7 | builds: 8 | - env: 9 | # goreleaser does not work with CGO, it could also complicate 10 | # usage by users in CI/CD systems like Terraform Cloud where 11 | # they are unable to install libraries. 12 | - CGO_ENABLED=0 13 | mod_timestamp: "{{ .CommitTimestamp }}" 14 | flags: 15 | - -trimpath 16 | ldflags: 17 | - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}" 18 | goos: 19 | - freebsd 20 | - windows 21 | - linux 22 | - darwin 23 | goarch: 24 | - amd64 25 | - "386" 26 | - arm 27 | - arm64 28 | ignore: 29 | - goos: darwin 30 | goarch: "386" 31 | binary: "{{ .ProjectName }}_v{{ .Version }}" 32 | archives: 33 | - format: zip 34 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" 35 | checksum: 36 | name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS" 37 | algorithm: sha256 38 | signs: 39 | - artifacts: checksum 40 | args: 41 | # if you are using this is a GitHub action or some other automated pipeline, you 42 | # need to pass the batch flag to indicate its not interactive. 43 | - "--batch" 44 | - "--local-user" 45 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 46 | - "--output" 47 | - "${signature}" 48 | - "--detach-sign" 49 | - "${artifact}" 50 | release: 51 | # Visit your project's GitHub Releases page to publish this release. 52 | draft: true 53 | changelog: 54 | skip: true 55 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .build/ 2 | .drone.yml 3 | .pre-commit-config.yaml 4 | dist/ 5 | helm/ 6 | templates/ 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kradalby/terraform-provider-opnsense/326a7337a1ee9c4b2fe9cc66aebbee5046f32fca/CHANGELOG.md -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./... |grep -v 'vendor') 2 | GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) 3 | WEBSITE_REPO=github.com/hashicorp/terraform-website 4 | PKG_NAME=opnsense 5 | 6 | default: build 7 | 8 | build: fmtcheck 9 | go install 10 | 11 | test: fmtcheck 12 | go test -i $(TEST) || exit 1 13 | echo $(TEST) | \ 14 | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 15 | 16 | testacc: fmtcheck 17 | TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m 18 | 19 | vet: 20 | @echo "go vet ." 21 | @go vet $$(go list ./... | grep -v vendor/) ; if [ $$? -eq 1 ]; then \ 22 | echo ""; \ 23 | echo "Vet found suspicious constructs. Please check the reported constructs"; \ 24 | echo "and fix them if necessary before submitting the code for review."; \ 25 | exit 1; \ 26 | fi 27 | 28 | fmt: 29 | prettier --write "**/*.{ts,js,md,yaml,yml,sass,css,scss}" 30 | golangci-lint run --fix 31 | 32 | fmtcheck: 33 | @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" 34 | 35 | errcheck: 36 | @sh -c "'$(CURDIR)/scripts/errcheck.sh'" 37 | 38 | test-compile: 39 | @if [ "$(TEST)" = "./..." ]; then \ 40 | echo "ERROR: Set TEST to a specific package. For example,"; \ 41 | echo " make test-compile TEST=./$(PKG_NAME)"; \ 42 | exit 1; \ 43 | fi 44 | go test -c $(TEST) $(TESTARGS) 45 | 46 | website: 47 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 48 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 49 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 50 | endif 51 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 52 | 53 | website-test: 54 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 55 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 56 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 57 | endif 58 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider-test PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 59 | 60 | .PHONY: build test testacc vet fmt fmtcheck errcheck test-compile website website-test 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Provider 2 | 3 | --- 4 | 5 | This project is currently unmaintained, I do not have any time for it at the moment. 6 | There is a lot of potential, but it would require a code generator to make code based 7 | on the API docs. 8 | 9 | If you would be interested in sponsoring the continuation of this project, please 10 | reach out to me. 11 | 12 | --- 13 | 14 | - Website: https://www.terraform.io 15 | - [![Gitter chat](https://badges.gitter.im/hashicorp-terraform/Lobby.png)](https://gitter.im/hashicorp-terraform/Lobby) 16 | - Mailing list: [Google Groups](http://groups.google.com/group/terraform-tool) 17 | 18 | 19 | 20 | ## Maintainers 21 | 22 | This provider plugin is maintained by the Terraform team at [HashiCorp](https://www.hashicorp.com/). 23 | 24 | ## Requirements 25 | 26 | - [Terraform](https://www.terraform.io/downloads.html) 0.10.x 27 | - [Go](https://golang.org/doc/install) 1.11 (to build the provider plugin) 28 | 29 | ## Usage 30 | 31 | ``` 32 | # For example, restrict template version in 0.1.x 33 | provider "template" { 34 | version = "~> 0.1" 35 | } 36 | ``` 37 | 38 | ## Building The Provider 39 | 40 | Clone repository to: `$GOPATH/src/github.com/terraform-providers/terraform-provider-template` 41 | 42 | ```sh 43 | $ mkdir -p $GOPATH/src/github.com/terraform-providers; cd $GOPATH/src/github.com/terraform-providers 44 | $ git clone git@github.com:terraform-providers/terraform-provider-template 45 | ``` 46 | 47 | Enter the provider directory and build the provider 48 | 49 | ```sh 50 | $ cd $GOPATH/src/github.com/terraform-providers/terraform-provider-template 51 | $ make build 52 | ``` 53 | 54 | ## Using the provider 55 | 56 | ## Fill in for each provider 57 | 58 | ## Developing the Provider 59 | 60 | If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.11+ is _required_). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`. 61 | 62 | To compile the provider, run `make build`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. 63 | 64 | ```sh 65 | $ make build 66 | ... 67 | $ $GOPATH/bin/terraform-provider-template 68 | ... 69 | ``` 70 | 71 | In order to test the provider, you can simply run `make test`. 72 | 73 | ```sh 74 | $ make test 75 | ``` 76 | 77 | In order to run the full suite of Acceptance tests, run `make testacc`. 78 | 79 | _Note:_ Acceptance tests create real resources, and often cost money to run. 80 | 81 | ```sh 82 | $ make testacc 83 | ``` 84 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kradalby/terraform-provider-opnsense 2 | 3 | go 1.15 4 | 5 | // replace github.com/kradalby/opnsense-go => ../opnsense-go 6 | 7 | require ( 8 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.8.0 9 | github.com/kradalby/opnsense-go v0.0.0-20210802162605-47fb9b5e0bbb 10 | github.com/mitchellh/mapstructure v1.4.2 11 | github.com/rogpeppe/go-internal v1.6.2 // indirect 12 | github.com/satori/go.uuid v1.2.0 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.61.0 h1:NLQf5e1OMspfNT1RAHOB3ublr1TW3YTXO8OiWwVjK2U= 15 | cloud.google.com/go v0.61.0/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= 16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 22 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 23 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 24 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 25 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 26 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 27 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 28 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 29 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 30 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 31 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 32 | cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= 33 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 34 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 35 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 36 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 37 | github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 38 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= 39 | github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= 40 | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 41 | github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= 42 | github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= 43 | github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= 44 | github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 45 | github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= 46 | github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 47 | github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= 48 | github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 49 | github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= 50 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 51 | github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= 52 | github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= 53 | github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 54 | github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 55 | github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= 56 | github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= 57 | github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= 58 | github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= 59 | github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= 60 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 61 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 62 | github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= 63 | github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ= 64 | github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 65 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= 66 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 67 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 68 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 69 | github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 70 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 71 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 72 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 73 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 74 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 75 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 76 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 77 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 78 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 79 | github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= 80 | github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= 81 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 82 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 83 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 84 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 85 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= 86 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 87 | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 88 | github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= 89 | github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= 90 | github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= 91 | github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= 92 | github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 93 | github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 94 | github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 95 | github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 96 | github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= 97 | github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= 98 | github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= 99 | github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= 100 | github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= 101 | github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= 102 | github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= 103 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 104 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 105 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 106 | github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 107 | github.com/gobuffalo/envy v1.9.0 h1:eZR0DuEgVLfeIb1zIKt3bT4YovIMf9O9LXQeCZLXpqE= 108 | github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= 109 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 110 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 111 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 112 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= 113 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 114 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 115 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 116 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 117 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 118 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 119 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 120 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 121 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 122 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 123 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 124 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 125 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 126 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 127 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 128 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 129 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 130 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 131 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 132 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 133 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 134 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 135 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 136 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 137 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 138 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 139 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 140 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 141 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 142 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 143 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 144 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 145 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 146 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 147 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 148 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 149 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 150 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 151 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 152 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 153 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 154 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 155 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 156 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 157 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 158 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 159 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 160 | github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= 161 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 162 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 163 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 164 | github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= 165 | github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= 166 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 167 | github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= 168 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 169 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 170 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 171 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= 172 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= 173 | github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= 174 | github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8= 175 | github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= 176 | github.com/hashicorp/go-getter v1.5.0 h1:ciWJaeZWSMbc5OiLMpKp40MKFPqO44i0h3uyfXPBkkk= 177 | github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= 178 | github.com/hashicorp/go-getter v1.5.3 h1:NF5+zOlQegim+w/EUhSLh6QhXHmZMEeHLQzllkQ3ROU= 179 | github.com/hashicorp/go-getter v1.5.3/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= 180 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 181 | github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= 182 | github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 183 | github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 184 | github.com/hashicorp/go-hclog v0.15.0 h1:qMuK0wxsoW4D0ddCCYwPSTm4KQv1X1ke3WmPWZ0Mvsk= 185 | github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 186 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 187 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 188 | github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= 189 | github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= 190 | github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= 191 | github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= 192 | github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= 193 | github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= 194 | github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= 195 | github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= 196 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 197 | github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= 198 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 199 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 200 | github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= 201 | github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 202 | github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= 203 | github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 204 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 205 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 206 | github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= 207 | github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= 208 | github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= 209 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 210 | github.com/hashicorp/terraform-exec v0.10.0 h1:3nh/1e3u9gYRUQGOKWp/8wPR7ABlL2F14sZMZBrp+dM= 211 | github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= 212 | github.com/hashicorp/terraform-exec v0.12.0 h1:Tb1VC2gqArl9EJziJjoazep2MyxMk00tnNKV/rgMba0= 213 | github.com/hashicorp/terraform-exec v0.12.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= 214 | github.com/hashicorp/terraform-exec v0.13.0 h1:1Pth+pdWJAufJuWWjaVOVNEkoRTOjGn3hQpAqj4aPdg= 215 | github.com/hashicorp/terraform-exec v0.13.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= 216 | github.com/hashicorp/terraform-exec v0.13.3 h1:R6L2mNpDGSEqtLrSONN8Xth0xYwNrnEVzDz6LF/oJPk= 217 | github.com/hashicorp/terraform-exec v0.13.3/go.mod h1:SSg6lbUsVB3DmFyCPjBPklqf6EYGX0TlQ6QTxOlikDU= 218 | github.com/hashicorp/terraform-exec v0.14.0 h1:UQoUcxKTZZXhyyK68Cwn4mApT4mnFPmEXPiqaHL9r+w= 219 | github.com/hashicorp/terraform-exec v0.14.0/go.mod h1:qrAASDq28KZiMPDnQ02sFS9udcqEkRly002EA2izXTA= 220 | github.com/hashicorp/terraform-json v0.5.0 h1:7TV3/F3y7QVSuN4r9BEXqnWqrAyeOtON8f0wvREtyzs= 221 | github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= 222 | github.com/hashicorp/terraform-json v0.8.0 h1:XObQ3PgqU52YLQKEaJ08QtUshAfN3yu4u8ebSW0vztc= 223 | github.com/hashicorp/terraform-json v0.8.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= 224 | github.com/hashicorp/terraform-json v0.10.0 h1:9syPD/Y5t+3uFjG8AiWVPu1bklJD8QB8iTCaJASc8oQ= 225 | github.com/hashicorp/terraform-json v0.10.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= 226 | github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQAwYYLETaTvw= 227 | github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= 228 | github.com/hashicorp/terraform-plugin-go v0.1.0 h1:kyXZ0nkHxiRev/q18N40IbRRk4AV0zE/MDJkDM3u8dY= 229 | github.com/hashicorp/terraform-plugin-go v0.1.0/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= 230 | github.com/hashicorp/terraform-plugin-go v0.2.1 h1:EW/R8bB2Zbkjmugzsy1d27yS8/0454b3MtYHkzOknqA= 231 | github.com/hashicorp/terraform-plugin-go v0.2.1/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= 232 | github.com/hashicorp/terraform-plugin-go v0.3.0 h1:AJqYzP52JFYl9NABRI7smXI1pNjgR5Q/y2WyVJ/BOZA= 233 | github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= 234 | github.com/hashicorp/terraform-plugin-go v0.4.0 h1:LFbXNeLDo0J/wR0kUzSPq0RpdmFh2gNedzU0n/gzPAo= 235 | github.com/hashicorp/terraform-plugin-go v0.4.0/go.mod h1:7u/6nt6vaiwcWE2GuJKbJwNlDFnf5n95xKw4hqIVr58= 236 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.3 h1:X7VmKpcIxq+rIbuqe5TPN27KLzbO9aXQcjG4c5iC3tk= 237 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.3/go.mod h1:oz4kkpfTJ/hA2VMD0WpITTd3yPDGpT4uN7CiKdre/YI= 238 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4 h1:GYkUL3zjrZgig9Gm+/61+YglzESJxXRDMp7qhJsh4j0= 239 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4/go.mod h1:GP0lmw4Y+XV1OfTmi/hK75t5KWGGzoOzEgUBPGZ6Wq4= 240 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0 h1:2m4uKA97R8ijHGLwhHdpSJyI8Op1FpS/ozpoF21jK7s= 241 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0/go.mod h1:+12dJQebYjuU/yiq94iZUPuC66abfRBrXdpVJia3ojk= 242 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0 h1:Egv+R1tOOjPNz643KBTx3tLT6RdFGGYJcZlyLvrPcEU= 243 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0/go.mod h1:+12dJQebYjuU/yiq94iZUPuC66abfRBrXdpVJia3ojk= 244 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0 h1:2c+vG46celrDCsfYEIzaXxvBaAXCqlVG77LwtFz8cfs= 245 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0/go.mod h1:JBItawj+j8Ssla5Ib6BC/W9VQkOucBfnX7VRtyx1vw8= 246 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.1 h1:k2rpom9wG2cdi5iLRH80EdQB7UX/E6UzYzUfzgsNLuU= 247 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.1/go.mod h1:jgCWyjKf1BRqzuA3IPJb6PJ2YY86ePJurX9xfJtuYNU= 248 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.2 h1:8oo4eMtv3nEZGqe8W0UzMxKnKWuwS/Tb2YyIFJkL59g= 249 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.2/go.mod h1:jgCWyjKf1BRqzuA3IPJb6PJ2YY86ePJurX9xfJtuYNU= 250 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.3 h1:DGnxpIYRHXQZb2TOlQ1OCEYxoRQrAcbLIcYm8kvbFuU= 251 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.3/go.mod h1:5wrrTcxbSaQXamCDbHZTHk6yTF9OEZaOvQ9fvLXBE3o= 252 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.4 h1:6k0WcxFgVqF/GUFHPvAH8FIrCkoA1RInXzSxhkKamPg= 253 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.4/go.mod h1:z+cMZ0iswzZOahBJ3XmNWgWkVnAd2bl8g+FhyyuPDH4= 254 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0 h1:4EHNOAjwiYCeBxY16rt2KwyRNNVsCaVO3kWBbiXfYM0= 255 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0/go.mod h1:z+cMZ0iswzZOahBJ3XmNWgWkVnAd2bl8g+FhyyuPDH4= 256 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.0 h1:mPZW0DDXlD70/Y+jenKz8fmkyxdmuE9T8mrftycxuZ0= 257 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.0/go.mod h1:r2d5s4frIMvyjEuv4a47xI4f7mkaQlRu7bLgw2/LAaY= 258 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 h1:OZ+Q7irJBDhb71XzMSPGJvTIW101sOmbDg5i5qV1odY= 259 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1/go.mod h1:72j8cKfs9IirGhPMXJJWLTvRUK4zATtrCOvs2avDlo8= 260 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 h1:SuI59MqNjYDrL7EfqHX9V6P/24isgqYx/FdglwVs9bg= 261 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= 262 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.1 h1:vpzKKP2dIFb9n89AG8Wxl758/5JSZWZH0OuKdlq0M38= 263 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.1/go.mod h1:o3pdss6ynDZW9FfiZ+rETUH5LEVufrXdhwLU+5OiRo0= 264 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.8.0 h1:GSumgrL6GGcRYU37YuF1CC59hRPR7Yzy6tpoFlo8wr4= 265 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.8.0/go.mod h1:6KbP09YzlB++S6XSUKYl83WyoHVN4MgeoCbPRsdfCtA= 266 | github.com/hashicorp/terraform-plugin-test/v2 v2.1.2 h1:p96IIn+XpvVjw7AtN8y9MKxn0x69S7wtbGf7JgDJoIk= 267 | github.com/hashicorp/terraform-plugin-test/v2 v2.1.2/go.mod h1:jerO5mrd+jVNALy8aiq+VZOg/CR8T2T1QR3jd6JKGOI= 268 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 269 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= 270 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 271 | github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 272 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 273 | github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= 274 | github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 275 | github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= 276 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= 277 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 278 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 279 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 280 | github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= 281 | github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= 282 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 283 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= 284 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 285 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 286 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 287 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 288 | github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= 289 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 290 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= 291 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 292 | github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 293 | github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= 294 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 295 | github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= 296 | github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 297 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 298 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 299 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 300 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 301 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 302 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 303 | github.com/kradalby/opnsense-go v0.0.0-20200916123608-6df8ebb1a878 h1:CmoW7oCkAGGshBLfLtbzrDqghh96c9AKzp0DmdIPQHc= 304 | github.com/kradalby/opnsense-go v0.0.0-20200916123608-6df8ebb1a878/go.mod h1:V1rKHz6Faa/T7TV6mXSpixcKJJNJWYGo3jG2DvmNezM= 305 | github.com/kradalby/opnsense-go v0.0.0-20200916130135-67bf4464de4c h1:gp/TOt53FKlwhsQ6Avy5HqYZ0h+iItdkPeR4/tWNWIQ= 306 | github.com/kradalby/opnsense-go v0.0.0-20200916130135-67bf4464de4c/go.mod h1:nOA+QAdEKT3cCfVFonP7GRqY4+rH/CReEObl3rilQmk= 307 | github.com/kradalby/opnsense-go v0.0.0-20210123082920-7015c8e12160 h1:fqQ/XR09STCUnU1vxFEI09+79jfcagYURE6m9A8ChHU= 308 | github.com/kradalby/opnsense-go v0.0.0-20210123082920-7015c8e12160/go.mod h1:neCt2sy0utNxKFEATECUk1g8cA9pl2p2ObxTIXzsfJY= 309 | github.com/kradalby/opnsense-go v0.0.0-20210528195939-75c226e47325 h1:8xkTh89Kj0ihGIeSL2LkYdps7swtdat/N9bA8R3e6mg= 310 | github.com/kradalby/opnsense-go v0.0.0-20210528195939-75c226e47325/go.mod h1:neCt2sy0utNxKFEATECUk1g8cA9pl2p2ObxTIXzsfJY= 311 | github.com/kradalby/opnsense-go v0.0.0-20210802162605-47fb9b5e0bbb h1:zG77k0oETIiJnB+of9IKQJRfv6g7ediEM+YRigLbHV4= 312 | github.com/kradalby/opnsense-go v0.0.0-20210802162605-47fb9b5e0bbb/go.mod h1:neCt2sy0utNxKFEATECUk1g8cA9pl2p2ObxTIXzsfJY= 313 | github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= 314 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 315 | github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= 316 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 317 | github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= 318 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 319 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 320 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 321 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 322 | github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= 323 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 324 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 325 | github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 326 | github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= 327 | github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= 328 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 329 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 330 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 331 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 332 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 333 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 334 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 335 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 336 | github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= 337 | github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 338 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 339 | github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= 340 | github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 341 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 342 | github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= 343 | github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 344 | github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 345 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 346 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 347 | github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= 348 | github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 349 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 350 | github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= 351 | github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 352 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 353 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 354 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 355 | github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= 356 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= 357 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 358 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 359 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 360 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 361 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 362 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 363 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 364 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 365 | github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 366 | github.com/rogpeppe/go-internal v1.5.1 h1:asQ0uD7BN9RU5Im41SEEZTwCi/zAXdMOLS3npYaos2g= 367 | github.com/rogpeppe/go-internal v1.5.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 368 | github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0= 369 | github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 370 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 371 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 372 | github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= 373 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 374 | github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= 375 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 376 | github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 377 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 378 | github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 379 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 380 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 381 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 382 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 383 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 384 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 385 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 386 | github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 387 | github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4= 388 | github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 389 | github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= 390 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 391 | github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 392 | github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= 393 | github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 394 | github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= 395 | github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 396 | github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= 397 | github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= 398 | github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= 399 | github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= 400 | github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= 401 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 402 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 403 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 404 | github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 405 | github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= 406 | github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 407 | github.com/zclconf/go-cty v1.8.2 h1:u+xZfBKgpycDnTNjPhGiTEYZS5qS/Sb5MqSfm7vzcjg= 408 | github.com/zclconf/go-cty v1.8.2/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= 409 | github.com/zclconf/go-cty v1.8.4 h1:pwhhz5P+Fjxse7S7UriBrMu6AUJSZM5pKqGem1PjGAs= 410 | github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= 411 | github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= 412 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 413 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 414 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 415 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 416 | go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= 417 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 418 | golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 419 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 420 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 421 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 422 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 423 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 424 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 425 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 426 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 427 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 428 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= 429 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 430 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= 431 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 432 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 433 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 434 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 435 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 436 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 437 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 438 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 439 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 440 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 441 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 442 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 443 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 444 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 445 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 446 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 447 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 448 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 449 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 450 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 451 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 452 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 453 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= 454 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 455 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 456 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 457 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 458 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 459 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 460 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 461 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 462 | golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= 463 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 464 | golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 465 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 466 | golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 467 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 468 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 469 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 470 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 471 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 472 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 473 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 474 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 475 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 476 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 477 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 478 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 479 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 480 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 481 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 482 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 483 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 484 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 485 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 486 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 487 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 488 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 489 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 490 | golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= 491 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 492 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 493 | golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= 494 | golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= 495 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 496 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 497 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 498 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 499 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= 500 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 501 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 502 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 503 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 504 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 505 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 506 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 507 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 508 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 509 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 510 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 511 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 512 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 513 | golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 514 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 515 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 516 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 517 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 518 | golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 519 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 520 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 521 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 522 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 523 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 524 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 525 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 526 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 527 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 528 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 529 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 530 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 531 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 532 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 533 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 534 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 535 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 536 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 537 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 538 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 539 | golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= 540 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 541 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 542 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 543 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= 544 | golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 545 | golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= 546 | golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 547 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 548 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 549 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 550 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 551 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 552 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 553 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 554 | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= 555 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 556 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 557 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 558 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 559 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 560 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 561 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 562 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 563 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 564 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 565 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 566 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 567 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 568 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 569 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 570 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 571 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 572 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 573 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 574 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 575 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 576 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 577 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 578 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 579 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 580 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 581 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 582 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 583 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 584 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 585 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 586 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 587 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 588 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 589 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 590 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 591 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 592 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 593 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 594 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 595 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 596 | golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed h1:+qzWo37K31KxduIYaBeMqJ8MUOyTayOQKpH9aDPLMSY= 597 | golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 598 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 599 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 600 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 601 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 602 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 603 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 604 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 605 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 606 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 607 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 608 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 609 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 610 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 611 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 612 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 613 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 614 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 615 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 616 | google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk= 617 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 618 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 619 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 620 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 621 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 622 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 623 | google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= 624 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 625 | google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 626 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 627 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 628 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 629 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 630 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 631 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 632 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 633 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 634 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 635 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 636 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 637 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 638 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 639 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 640 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 641 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 642 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 643 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 644 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 645 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 646 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 647 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 648 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 649 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 650 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 651 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 652 | google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxtiIncJxFXeCyq84ixuKWVCaCAi9Oc= 653 | google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 654 | google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 655 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 656 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 657 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 658 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 659 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 660 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 661 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 662 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 663 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 664 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 665 | google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= 666 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 667 | google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= 668 | google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 669 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 670 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 671 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 672 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 673 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 674 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 675 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 676 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 677 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 678 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 679 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 680 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 681 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 682 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 683 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 684 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 685 | gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 686 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 687 | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 688 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 689 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 690 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 691 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 692 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 693 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 694 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 695 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 696 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 697 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 698 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 699 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 700 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 701 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 702 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 703 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 6 | "github.com/kradalby/terraform-provider-opnsense/opnsense" 7 | ) 8 | 9 | func main() { 10 | plugin.Serve(&plugin.ServeOpts{ 11 | ProviderFunc: providerFunc, 12 | }) 13 | } 14 | 15 | func providerFunc() *schema.Provider { 16 | return opnsense.Provider() 17 | } 18 | -------------------------------------------------------------------------------- /opnsense/data_firewall_alias.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/kradalby/opnsense-go/opnsense" 8 | uuid "github.com/satori/go.uuid" 9 | ) 10 | 11 | func dataFirewallAlias() *schema.Resource { 12 | return &schema.Resource{ 13 | Read: dataFirewallAliasRead, 14 | Schema: map[string]*schema.Schema{ 15 | "name": { 16 | Type: schema.TypeString, 17 | ForceNew: true, 18 | Required: true, 19 | }, 20 | "enabled": { 21 | Type: schema.TypeBool, 22 | Computed: true, 23 | }, 24 | "type": { 25 | Type: schema.TypeString, 26 | Computed: true, 27 | }, 28 | "description": { 29 | Type: schema.TypeString, 30 | Computed: true, 31 | }, 32 | "content": { 33 | Type: schema.TypeSet, 34 | Elem: &schema.Schema{ 35 | Type: schema.TypeString, 36 | }, 37 | Computed: true, 38 | }, 39 | // TODO add other fields 40 | }, 41 | } 42 | } 43 | 44 | // Read will fetch the data of a resource. 45 | func dataFirewallAliasRead(d *schema.ResourceData, meta interface{}) error { 46 | log.Printf("[TRACE] Getting OPNsense client from meta") 47 | 48 | c := meta.(*opnsense.Client) 49 | 50 | wantedName := d.Get("name") 51 | 52 | // list all alias 53 | aliasList, err := c.AliasGetList() 54 | if err != nil { 55 | // temporary fix for the internal error API when we try to get an unreferenced UIID 56 | if err.Error() == apiInternalErrorMsg { 57 | d.SetId("") 58 | 59 | return nil 60 | } 61 | 62 | log.Printf("ERROR: \n%#v", err) 63 | 64 | return err 65 | } 66 | 67 | for _, alias := range aliasList.Rows { 68 | if alias.Name == wantedName { 69 | wantedUUID, err := uuid.FromString(alias.UUID) 70 | if err != nil { 71 | log.Printf("[ERROR] dataFirewallAliasRead - Failed to parse ID") 72 | 73 | return err 74 | } 75 | 76 | wantedAlias, err := c.AliasGet(wantedUUID) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | d.SetId(wantedAlias.UUID.String()) 82 | 83 | err = d.Set("Name", wantedAlias.Name) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | err = d.Set("Enabled", wantedAlias.Enabled) 89 | if err != nil { 90 | return err 91 | } 92 | 93 | err = d.Set("Description", wantedAlias.Description) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | err = d.Set("Type", wantedAlias.Type) 99 | if err != nil { 100 | return err 101 | } 102 | 103 | err = d.Set("Content", wantedAlias.Content) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | break 109 | } 110 | } 111 | 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /opnsense/helpers.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | ErrExpectedString = errors.New("expected string") 9 | ErrInvalidUUID = errors.New("invalid UUID") 10 | ErrMoreThanOneUUIDReturned = errors.New("more than one uuid returned") 11 | ErrStatusNotOk = errors.New("api status message not ok") 12 | ) 13 | 14 | const apiInternalErrorMsg = "Internal Error status code received" 15 | -------------------------------------------------------------------------------- /opnsense/provider.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 11 | "github.com/kradalby/opnsense-go/opnsense" 12 | ) 13 | 14 | func Provider() *schema.Provider { 15 | return &schema.Provider{ 16 | Schema: map[string]*schema.Schema{ 17 | "url": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | DefaultFunc: schema.EnvDefaultFunc("OPNSENSE_URL", nil), 21 | Description: "The OPNsense url to connect to", 22 | }, 23 | "key": { 24 | Type: schema.TypeString, 25 | Required: true, 26 | DefaultFunc: schema.EnvDefaultFunc("OPNSENSE_KEY", nil), 27 | Description: "The OPNsense API key", 28 | }, 29 | "secret": { 30 | Type: schema.TypeString, 31 | Required: true, 32 | DefaultFunc: schema.EnvDefaultFunc("OPNSENSE_SECRET", nil), 33 | Description: "The OPNsense API secret", 34 | }, 35 | "allow_unverified_tls": { 36 | Type: schema.TypeBool, 37 | Optional: true, 38 | DefaultFunc: schema.EnvDefaultFunc("OPNSENSE_ALLOW_UNVERIFIED_TLS", false), 39 | Description: "Allow connection to a OPNsense server without verified TLS", 40 | }, 41 | }, 42 | 43 | ResourcesMap: map[string]*schema.Resource{ 44 | "opnsense_wireguard_client": resourceWireGuardClient(), 45 | "opnsense_wireguard_server": resourceWireGuardServer(), 46 | "opnsense_firewall_filter_rule": resourceFirewallFilterRule(), 47 | "opnsense_firewall_alias": resourceFirewallAlias(), 48 | "opnsense_firewall_alias_util": resourceFirewallAliasUtil(), 49 | "opnsense_firmware": resourceFirmware(), 50 | }, 51 | 52 | DataSourcesMap: map[string]*schema.Resource{ 53 | "opnsense_firewall_alias": dataFirewallAlias(), 54 | }, 55 | 56 | ConfigureContextFunc: providerConfigure, 57 | } 58 | } 59 | 60 | func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { 61 | // Warning or errors can be collected in a slice type 62 | var diags diag.Diagnostics 63 | 64 | url := d.Get("url").(string) 65 | key := d.Get("key").(string) 66 | secret := d.Get("secret").(string) 67 | skipTLS := d.Get("allow_unverified_tls").(bool) 68 | 69 | log.Printf("[TRACE] Creating OPNsense client\n") 70 | 71 | c, err := opnsense.NewClient(url, key, secret, skipTLS) 72 | if err != nil { 73 | log.Printf("[ERROR] Could not create OPNsense client: %#v\n", err) 74 | 75 | return nil, diag.FromErr(err) 76 | } 77 | 78 | _, err = c.FirmwareConfigGet() 79 | if err != nil { 80 | if errors.Is(err, opnsense.ErrOpnsense401) { 81 | diags = append(diags, diag.Diagnostic{ 82 | Severity: diag.Error, 83 | Summary: "Authentication with OPNsense failed", 84 | Detail: fmt.Sprintf( 85 | "When attempting to authenticate with OPNsense server %s, a 401 Authentication error was returned", 86 | url, 87 | ), 88 | }) 89 | 90 | return nil, diags 91 | } 92 | 93 | return nil, diag.FromErr(err) 94 | } 95 | 96 | return c, diags 97 | } 98 | -------------------------------------------------------------------------------- /opnsense/provider_test.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | ) 9 | 10 | var ( 11 | testAccProviders map[string]*schema.Provider 12 | testAccProvider *schema.Provider 13 | ) 14 | 15 | func init() { 16 | testAccProvider = Provider() 17 | testAccProviders = map[string]*schema.Provider{ 18 | "opnsense": testAccProvider, 19 | } 20 | } 21 | 22 | func testAccPreCheck(t *testing.T) { 23 | if v := os.Getenv("OPNSENSE_ADDRESS"); v == "" { 24 | t.Fatal("OPNSENSE_ADDRESS must be set for acceptance tests") 25 | } 26 | 27 | if v := os.Getenv("OPNSENSE_KEY"); v == "" { 28 | t.Fatal("OPNSENSE_KEY must be set for acceptance tests") 29 | } 30 | 31 | if v := os.Getenv("OPNSENSE_SECRET"); v == "" { 32 | t.Fatal("OPNSENSE_SECRET must be set for acceptance tests") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /opnsense/resource_firewall_alias.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "strings" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 10 | "github.com/kradalby/opnsense-go/opnsense" 11 | uuid "github.com/satori/go.uuid" 12 | ) 13 | 14 | func resourceFirewallAlias() *schema.Resource { 15 | return &schema.Resource{ 16 | Create: resourceFirewallAliasCreate, 17 | Read: resourceFirewallAliasRead, 18 | Update: resourceFirewallAliasUpdate, 19 | Delete: resourceFirewallAliasDelete, 20 | 21 | Importer: &schema.ResourceImporter{ 22 | StateContext: schema.ImportStatePassthroughContext, 23 | }, 24 | 25 | Schema: map[string]*schema.Schema{ 26 | "parent": { 27 | Type: schema.TypeSet, 28 | Elem: &schema.Schema{ 29 | Type: schema.TypeString, 30 | }, 31 | Description: "UIID of other alias who will contain this alias (nested)", 32 | Optional: true, 33 | }, 34 | "enabled": { 35 | Type: schema.TypeBool, 36 | Description: "State of the alias", 37 | Optional: true, 38 | Default: true, 39 | }, 40 | "name": { 41 | Type: schema.TypeString, 42 | Description: "Name of the alias", 43 | Required: true, 44 | }, 45 | "type": { 46 | Type: schema.TypeString, 47 | Description: "Type of the alias", 48 | Required: true, 49 | ValidateFunc: validation.StringInSlice([]string{"host", "network", "port", "url"}, false), 50 | }, 51 | "description": { 52 | Type: schema.TypeString, 53 | Description: "Description of the alias", 54 | Optional: true, 55 | Default: "", 56 | }, 57 | "content": { 58 | Type: schema.TypeSet, 59 | Elem: &schema.Schema{ 60 | Type: schema.TypeString, 61 | }, 62 | Description: "The content of this alias (IP, Cidr, url, ...)", 63 | 64 | Optional: true, 65 | }, 66 | // TODO add other fields (like proto) 67 | }, 68 | } 69 | } 70 | 71 | func resourceFirewallAliasRead(d *schema.ResourceData, meta interface{}) error { 72 | log.Printf("[TRACE] Getting OPNsense client from meta") 73 | 74 | c := meta.(*opnsense.Client) 75 | 76 | log.Printf("[TRACE] Converting ID to UUID") 77 | 78 | uuid, err := uuid.FromString(d.Id()) 79 | if err != nil { 80 | log.Printf("[ERROR]resourceFirewallAliasRead - Failed to parse ID") 81 | 82 | return err 83 | } 84 | 85 | log.Printf("[TRACE] Fetching alias configuration from OPNsense") 86 | 87 | alias, err := c.AliasGet(uuid) 88 | if err != nil { 89 | // temporary fix for the internal error API when we try to get an unreferenced UIID 90 | if err.Error() == apiInternalErrorMsg { 91 | d.SetId("") 92 | 93 | return nil 94 | } 95 | 96 | log.Printf("[ERROR] Failed to fetch uuid: %s", uuid) 97 | 98 | return err 99 | } 100 | 101 | log.Printf("[DEBUG] Configuration from OPNsense: \n") 102 | log.Printf("[DEBUG] %#v \n", alias) 103 | 104 | d.SetId(alias.UUID.String()) 105 | 106 | err = d.Set("enabled", alias.Enabled) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | err = d.Set("name", alias.Name) 112 | if err != nil { 113 | return err 114 | } 115 | 116 | err = d.Set("type", alias.Type) 117 | if err != nil { 118 | return err 119 | } 120 | 121 | err = d.Set("description", alias.Description) 122 | if err != nil { 123 | return err 124 | } 125 | 126 | err = d.Set("content", alias.Content) 127 | if err != nil { 128 | return err 129 | } 130 | 131 | parents := []string{} 132 | 133 | // check if this alias is a member of another alias (nested) 134 | aliasList, err := c.AliasGetList() 135 | if err != nil { 136 | log.Printf("[ERROR]: %v", err) 137 | 138 | return err 139 | } 140 | 141 | for _, nestedAlias := range aliasList.Rows { 142 | if strings.Contains(nestedAlias.Content, alias.Name) { 143 | parents = append(parents, nestedAlias.UUID) 144 | } 145 | } 146 | 147 | err = d.Set("parent", parents) 148 | if err != nil { 149 | return err 150 | } 151 | 152 | return nil 153 | } 154 | 155 | func resourceFirewallAliasCreate(d *schema.ResourceData, meta interface{}) error { 156 | c := meta.(*opnsense.Client) 157 | alias := opnsense.AliasFormat{} 158 | 159 | err := prepareFirewallAliasConfiguration(d, &alias) 160 | if err != nil { 161 | return err 162 | } 163 | 164 | // create the alias 165 | createdUUID, err := c.AliasAdd(alias) 166 | if err != nil { 167 | return err 168 | } 169 | 170 | // add the alias to his parent if necessary 171 | parent := d.Get("parent") 172 | if parent != nil { 173 | parentList := parent.(*schema.Set).List() 174 | if len(parentList) > 0 { 175 | err = addNestedAlias(c, parentList, alias.Name) 176 | if err != nil { 177 | return err 178 | } 179 | } 180 | } 181 | 182 | // apply configuration change 183 | _, err = c.AliasReconfigure() 184 | if err != nil { 185 | return err 186 | } 187 | 188 | d.SetId(createdUUID.String()) 189 | err = resourceFirewallAliasRead(d, meta) 190 | 191 | return err 192 | } 193 | 194 | func resourceFirewallAliasUpdate(d *schema.ResourceData, meta interface{}) error { 195 | // TODO don"t update the alias if only the parent field is modified 196 | c := meta.(*opnsense.Client) 197 | 198 | elmUUID, err := uuid.FromString(d.Id()) 199 | if err != nil { 200 | return err 201 | } 202 | 203 | alias := opnsense.AliasFormat{} 204 | 205 | err = prepareFirewallAliasConfiguration(d, &alias) 206 | if err != nil { 207 | return err 208 | } 209 | 210 | _, err = c.AliasUpdate(elmUUID, alias) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | if d.HasChange("parent") { 216 | oldParent, newParent := d.GetChange("parent") 217 | log.Println("[TRACE] OLD Parent : ", oldParent) 218 | log.Println("[TRACE] NEW Parent : ", newParent) 219 | 220 | oldParentSet := oldParent.(*schema.Set) 221 | newParentSet := newParent.(*schema.Set) 222 | 223 | listToDel := oldParentSet.Difference(newParentSet).List() 224 | listToAdd := newParentSet.Difference(oldParentSet).List() 225 | 226 | // remove this alias from the previous nested alias 227 | if len(listToDel) > 0 { 228 | err = removeNestedAlias(c, listToDel, alias.Name) 229 | if err != nil { 230 | return err 231 | } 232 | } 233 | 234 | if len(listToAdd) > 0 { 235 | err = addNestedAlias(c, listToAdd, alias.Name) 236 | if err != nil { 237 | return err 238 | } 239 | } 240 | } 241 | 242 | // apply configuration change 243 | _, err = c.AliasReconfigure() 244 | if err != nil { 245 | return err 246 | } 247 | 248 | d.SetId(elmUUID.String()) 249 | 250 | err = resourceFirewallAliasRead(d, meta) 251 | 252 | return err 253 | } 254 | 255 | func resourceFirewallAliasDelete(d *schema.ResourceData, meta interface{}) error { 256 | c := meta.(*opnsense.Client) 257 | 258 | uuid, err := uuid.FromString(d.Id()) 259 | if err != nil { 260 | return err 261 | } 262 | 263 | // if this alias is nested, we need to delete this ressource in the parent before deleting this alias 264 | parent := d.Get("parent") 265 | if parent != nil { 266 | parentList := parent.(*schema.Set).List() 267 | if len(parentList) > 0 { 268 | err = removeNestedAlias(c, parentList, d.Get("name").(string)) 269 | if err != nil { 270 | return err 271 | } 272 | } 273 | } 274 | 275 | _, err = c.AliasDelete(uuid) 276 | if err != nil { 277 | return err 278 | } 279 | 280 | // apply configuration change 281 | _, err = c.AliasReconfigure() 282 | if err != nil { 283 | return err 284 | } 285 | 286 | d.SetId("") 287 | 288 | return err 289 | } 290 | 291 | func prepareFirewallAliasConfiguration(d *schema.ResourceData, conf *opnsense.AliasFormat) error { 292 | conf.Enabled = d.Get("enabled").(bool) 293 | conf.Name = d.Get("name").(string) 294 | conf.Description = d.Get("description").(string) 295 | conf.Type = d.Get("type").(string) 296 | 297 | contentList := d.Get("content").(*schema.Set).List() 298 | contentListStr := make([]string, len(contentList)) 299 | 300 | for i := range contentList { 301 | contentListStr[i] = contentList[i].(string) 302 | } 303 | 304 | conf.Content = contentListStr 305 | 306 | return nil 307 | } 308 | 309 | func removeInList(slice []string, elm string) ([]string, bool) { 310 | for k, v := range slice { 311 | if v == elm { 312 | return append(slice[:k], slice[k+1:]...), true 313 | } 314 | } 315 | 316 | return slice, false 317 | } 318 | 319 | func removeNestedAlias(c *opnsense.Client, parentUUIDList []interface{}, name string) error { 320 | for _, parentUUIDStr := range parentUUIDList { 321 | parentUUID, err := uuid.FromString(parentUUIDStr.(string)) 322 | if err != nil { 323 | return fmt.Errorf("[ERROR] Failed to parse ID: %w", err) 324 | } 325 | 326 | parentAlias, err := c.AliasGet(parentUUID) 327 | if err != nil { 328 | return fmt.Errorf("[ERROR] Something went wrong while retrieving parent alias for: %w", err) 329 | } 330 | 331 | parentAlias.Content, _ = removeInList(parentAlias.Content, name) 332 | 333 | _, err = c.AliasUpdate(parentUUID, *parentAlias) 334 | if err != nil { 335 | return err 336 | } 337 | } 338 | 339 | return nil 340 | } 341 | 342 | func addNestedAlias(c *opnsense.Client, parentUUIDList []interface{}, name string) error { 343 | for _, parentUUIDStr := range parentUUIDList { 344 | parentUUID, err := uuid.FromString(parentUUIDStr.(string)) 345 | if err != nil { 346 | return fmt.Errorf("[ERROR] Failed to parse ID: %w", err) 347 | } 348 | 349 | parentAlias, err := c.AliasGet(parentUUID) 350 | if err != nil { 351 | return fmt.Errorf("[ERROR] Something went wrong while retrieving parent alias for: %w", err) 352 | } 353 | 354 | parentAlias.Content = append(parentAlias.Content, name) 355 | _, err = c.AliasUpdate(parentUUID, *parentAlias) 356 | 357 | if err != nil { 358 | return err 359 | } 360 | } 361 | 362 | return nil 363 | } 364 | -------------------------------------------------------------------------------- /opnsense/resource_firewall_alias_util.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/kradalby/opnsense-go/opnsense" 8 | ) 9 | 10 | func resourceFirewallAliasUtil() *schema.Resource { 11 | return &schema.Resource{ 12 | Create: resourceFirewallAliasUtilCreate, 13 | Read: resourceFirewallAliasUtilRead, 14 | Update: resourceFirewallAliasUtilUpdate, 15 | Delete: resourceFirewallAliasUtilDelete, 16 | Importer: &schema.ResourceImporter{ 17 | StateContext: schema.ImportStatePassthroughContext, 18 | }, 19 | 20 | Schema: map[string]*schema.Schema{ 21 | "name": { 22 | Type: schema.TypeString, 23 | Description: "Name of the alias", 24 | Required: true, 25 | }, 26 | "address": { 27 | Type: schema.TypeString, 28 | Description: "IP or CIDR address to add in the alias", 29 | Required: true, 30 | }, 31 | }, 32 | } 33 | } 34 | 35 | func resourceFirewallAliasUtilRead(d *schema.ResourceData, meta interface{}) error { 36 | c := meta.(*opnsense.Client) 37 | 38 | name := d.Get("name").(string) 39 | 40 | alias, err := c.AliasUtilsGet(name) 41 | if err != nil { 42 | d.SetId("") 43 | // fix for the internal error API received when we try to get an unreferenced alias 44 | if err.Error() == apiInternalErrorMsg { 45 | return nil 46 | } 47 | 48 | return fmt.Errorf("list of address used in the alias '%s' could not be retreived : %w", name, err) 49 | } 50 | 51 | // We don't want to retrieved all addresse present in the alias because this resource will manage only one address 52 | // instead we just check if the address is present or not in the alias 53 | addressInState := d.Get("address").(string) 54 | addressFound := false 55 | 56 | if alias.Rows != nil { 57 | for _, v := range alias.Rows { 58 | if v.Address == addressInState { 59 | addressFound = true 60 | 61 | break 62 | } 63 | } 64 | } 65 | 66 | if addressFound { 67 | err = d.Set("address", addressInState) 68 | if err != nil { 69 | return err 70 | } 71 | } else { 72 | // address no found in the alias, we tell Terraform that the resource no longer exists 73 | d.SetId("") 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func resourceFirewallAliasUtilCreate(d *schema.ResourceData, meta interface{}) error { 80 | c := meta.(*opnsense.Client) 81 | 82 | name := d.Get("name").(string) 83 | address := d.Get("address").(string) 84 | conf := opnsense.AliasUtilsSet{ 85 | Address: address, 86 | } 87 | 88 | _, err := c.AliasUtilsAdd(name, conf) 89 | if err != nil { 90 | return fmt.Errorf("failed to add '%s' from alias '%s' : %w", conf.Address, name, err) 91 | } 92 | 93 | d.SetId(address) 94 | 95 | return resourceFirewallAliasUtilRead(d, meta) 96 | } 97 | 98 | func resourceFirewallAliasUtilUpdate(d *schema.ResourceData, meta interface{}) error { 99 | c := meta.(*opnsense.Client) 100 | conf := opnsense.AliasUtilsSet{} 101 | 102 | oldAddress := d.Get("address") 103 | newAddress := d.Get("address") 104 | oldName := d.Get("name") 105 | newName := d.Get("name") 106 | 107 | if d.HasChange("name") { 108 | oldName, newName = d.GetChange("name") 109 | } 110 | 111 | if d.HasChange("address") { 112 | oldAddress, newAddress = d.GetChange("address") 113 | } 114 | 115 | // We always try to add the new address before removing the previous one because this 116 | // could result in an unsafe state where we have deleted the address without added the new one 117 | conf.Address = newAddress.(string) 118 | 119 | _, err := c.AliasUtilsAdd(newName.(string), conf) 120 | if err != nil { 121 | return fmt.Errorf("failed to add '%s' in alias '%s' : %w", conf.Address, newName.(string), err) 122 | } 123 | 124 | conf.Address = oldAddress.(string) 125 | _, err = c.AliasUtilsDel(oldName.(string), conf) 126 | 127 | if err != nil { 128 | return fmt.Errorf("failed to remove '%s' in alias '%s' : %w", conf.Address, oldName.(string), err) 129 | } 130 | 131 | d.SetId(newAddress.(string)) 132 | 133 | return resourceFirewallAliasUtilRead(d, meta) 134 | } 135 | 136 | func resourceFirewallAliasUtilDelete(d *schema.ResourceData, meta interface{}) error { 137 | c := meta.(*opnsense.Client) 138 | 139 | name := d.Get("name").(string) 140 | conf := opnsense.AliasUtilsSet{ 141 | Address: d.Get("address").(string), 142 | } 143 | 144 | _, err := c.AliasUtilsDel(name, conf) 145 | if err != nil { 146 | // normally we should handle here the case when the API return an error and check if the 147 | // resource might already be destroyed (manually for example) but the API doesn't return 148 | // an error when we try to delete a non existing address in the alias so we can skip 149 | // this logic and always return the error send by opnsense 150 | return fmt.Errorf("failed to remove '%s' from alias '%s' : %w", conf.Address, name, err) 151 | } 152 | 153 | return nil 154 | } 155 | -------------------------------------------------------------------------------- /opnsense/resource_firewall_filter_rule.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 12 | "github.com/kradalby/opnsense-go/opnsense" 13 | "github.com/mitchellh/mapstructure" 14 | uuid "github.com/satori/go.uuid" 15 | ) 16 | 17 | func resourceFirewallFilterRule() *schema.Resource { 18 | return &schema.Resource{ 19 | CreateContext: resourceFirewallFilterRuleCreate, 20 | ReadContext: resourceFirewallFilterRuleRead, 21 | UpdateContext: resourceFirewallFilterRuleUpdate, 22 | DeleteContext: resourceFirewallFilterRuleDelete, 23 | 24 | Importer: &schema.ResourceImporter{ 25 | StateContext: schema.ImportStatePassthroughContext, 26 | }, 27 | 28 | Timeouts: &schema.ResourceTimeout{ 29 | Create: schema.DefaultTimeout(45 * time.Minute), 30 | }, 31 | 32 | Schema: map[string]*schema.Schema{ 33 | "uuid": { 34 | Type: schema.TypeString, 35 | Optional: true, 36 | Computed: true, 37 | Description: "Unique ID", 38 | }, 39 | "enabled": { 40 | Type: schema.TypeBool, 41 | Required: true, 42 | }, 43 | "sequence": { 44 | Type: schema.TypeInt, 45 | Optional: true, 46 | }, 47 | "action": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | Default: "pass", 51 | ValidateFunc: validation.StringInSlice([]string{"pass", "block", "reject"}, false), 52 | }, 53 | "quick": { 54 | Type: schema.TypeBool, 55 | Optional: true, 56 | Default: true, 57 | }, 58 | "interface": { 59 | Type: schema.TypeString, 60 | Required: true, 61 | }, 62 | "direction": { 63 | Type: schema.TypeString, 64 | Optional: true, 65 | Default: "in", 66 | ValidateFunc: validation.StringInSlice([]string{"in", "out"}, false), 67 | }, 68 | "ipprotocol": { 69 | Type: schema.TypeString, 70 | Optional: true, 71 | Default: "ipv4", 72 | ValidateFunc: validation.StringInSlice([]string{"ipv4", "ipv6"}, false), 73 | }, 74 | "protocol": { 75 | Type: schema.TypeString, 76 | Optional: true, 77 | Default: "any", 78 | }, 79 | "source_net": { 80 | Type: schema.TypeString, 81 | Required: true, 82 | }, 83 | "source_not": { 84 | Type: schema.TypeBool, 85 | Optional: true, 86 | Default: false, 87 | }, 88 | "source_port": { 89 | Type: schema.TypeString, 90 | Required: true, 91 | }, 92 | "destination_net": { 93 | Type: schema.TypeString, 94 | Required: true, 95 | }, 96 | "destination_not": { 97 | Type: schema.TypeBool, 98 | Optional: true, 99 | Default: false, 100 | }, 101 | "destination_port": { 102 | Type: schema.TypeString, 103 | Required: true, 104 | }, 105 | "gateway": { 106 | Type: schema.TypeString, 107 | Optional: true, 108 | }, 109 | "log": { 110 | Type: schema.TypeBool, 111 | Optional: true, 112 | Default: false, 113 | }, 114 | "description": { 115 | Type: schema.TypeString, 116 | Optional: true, 117 | }, 118 | }, 119 | } 120 | } 121 | 122 | func resourceFirewallFilterRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 123 | log.Printf("[TRACE] Getting OPNsense client from meta") 124 | 125 | var diags diag.Diagnostics 126 | 127 | c := meta.(*opnsense.Client) 128 | 129 | log.Printf("[TRACE] Converting ID to UUID") 130 | 131 | uuid, err := uuid.FromString(d.Id()) 132 | if err != nil { 133 | log.Printf("[ERROR] Failed to parse ID") 134 | 135 | return diag.FromErr(err) 136 | } 137 | 138 | rule, err := c.FirewallFilterRuleGet(uuid) 139 | if err != nil { 140 | diags = append(diags, diag.Diagnostic{ 141 | Severity: diag.Error, 142 | Summary: "Failed to get rule from OPNsense", 143 | Detail: fmt.Sprintf( 144 | "When attempting to fetch the rule %s, the API returned %s", 145 | uuid, err, 146 | ), 147 | }) 148 | 149 | return diags 150 | } 151 | 152 | ruleMap := opnsense.StructToMap(rule) 153 | 154 | for k, v := range ruleMap { 155 | if err := d.Set(k, v); err != nil { 156 | return diag.FromErr(err) 157 | } 158 | } 159 | 160 | d.SetId(uuid.String()) 161 | 162 | return diags 163 | } 164 | 165 | func resourceFirewallFilterRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 166 | c := meta.(*opnsense.Client) 167 | 168 | rule := opnsense.FilterRule{} 169 | ruleMap := make(map[string]interface{}) 170 | 171 | for _, field := range opnsense.JSONFields(rule) { 172 | ruleMap[field] = d.Get(field) 173 | } 174 | 175 | err := mapstructure.Decode(ruleMap, &rule) 176 | if err != nil { 177 | return diag.FromErr(err) 178 | } 179 | 180 | err = c.FirewallFilterRuleAdd(&rule) 181 | if err != nil { 182 | return diag.FromErr(err) 183 | } 184 | 185 | return resourceFirewallFilterRuleRead(ctx, d, meta) 186 | } 187 | 188 | func resourceFirewallFilterRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 189 | c := meta.(*opnsense.Client) 190 | 191 | rule := opnsense.FilterRule{} 192 | ruleMap := make(map[string]interface{}) 193 | 194 | for _, field := range opnsense.JSONFields(rule) { 195 | ruleMap[field] = d.Get(field) 196 | } 197 | 198 | err := mapstructure.Decode(ruleMap, &rule) 199 | if err != nil { 200 | return diag.FromErr(err) 201 | } 202 | 203 | err = c.FirewallFilterRuleSet(&rule) 204 | if err != nil { 205 | return diag.FromErr(err) 206 | } 207 | 208 | return resourceFirewallFilterRuleRead(ctx, d, meta) 209 | } 210 | 211 | func resourceFirewallFilterRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 212 | c := meta.(*opnsense.Client) 213 | 214 | var diags diag.Diagnostics 215 | 216 | uuid, err := uuid.FromString(d.Id()) 217 | if err != nil { 218 | log.Printf("[ERROR] Failed to parse ID") 219 | 220 | return diag.FromErr(err) 221 | } 222 | 223 | err = c.FirewallFilterRuleDelete(uuid) 224 | if err != nil { 225 | return diag.FromErr(err) 226 | } 227 | 228 | d.SetId("") 229 | 230 | return diags 231 | } 232 | 233 | // func statusStateConf(d *schema.ResourceData, client *opnsense.Client) *resource.StateChangeConf { 234 | // createStateConf := &resource.StateChangeConf{ 235 | // Pending: []string{ 236 | // opnsense.StatusRunning, 237 | // }, 238 | // Target: []string{ 239 | // opnsense.StatusDone, 240 | // }, 241 | // Refresh: func() (interface{}, string, error) { 242 | // resp, err := client.FirmwareUpgradeStatus() 243 | // if err != nil { 244 | // return 0, "", err 245 | // } 246 | 247 | // return resp, resp.Status, nil 248 | // }, 249 | // Timeout: d.Timeout(schema.TimeoutCreate), 250 | 251 | // Delay: 10 * time.Second, 252 | // MinTimeout: 5 * time.Second, 253 | // ContinuousTargetOccurence: 2, 254 | // } 255 | 256 | // return createStateConf 257 | // } 258 | -------------------------------------------------------------------------------- /opnsense/resource_firewire_filter_rule_test.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 10 | "github.com/kradalby/opnsense-go/opnsense" 11 | ) 12 | 13 | func testFirewallFilterRuleResource(name string) string { 14 | return fmt.Sprintf(` 15 | resource "opnsense_firmware" "%s" { 16 | plugin { 17 | name = "os-firewall" 18 | installed = true 19 | } 20 | } 21 | 22 | resource "opnsense_firewall_filter_rule" "%s" { 23 | enabled = true 24 | action = "pass" 25 | quick = true 26 | interface = "wan" 27 | source_net = "192.168.0.0/24" 28 | source_port = 8000 29 | destination_net = "192.168.0.0/24" 30 | destination_port = 8000 31 | } 32 | `, name, name) 33 | } 34 | 35 | func testAccFirewallFilterRuleResourceDestroy(s *terraform.State) error { 36 | c := testAccProvider.Meta().(*opnsense.Client) 37 | 38 | rules, err := c.FirewallFilterRuleSearch() 39 | if err != nil { 40 | return err 41 | } 42 | 43 | if len(rules) != 0 { 44 | return fmt.Errorf("All plugins are not uninstalled, %d", len(rules)) 45 | } 46 | 47 | return nil 48 | } 49 | 50 | func TestFirewallFilterRule_basic(t *testing.T) { 51 | rName := fmt.Sprintf("a%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) 52 | 53 | resource.Test(t, resource.TestCase{ 54 | PreCheck: func() { testAccPreCheck(t) }, 55 | Providers: testAccProviders, 56 | CheckDestroy: testAccFirewallFilterRuleResourceDestroy, 57 | Steps: []resource.TestStep{ 58 | { 59 | Config: testFirewallFilterRuleResource(rName), 60 | Check: resource.ComposeTestCheckFunc( 61 | resource.TestCheckResourceAttr( 62 | fmt.Sprintf("opnsense_firmware.%s", rName), 63 | "plugin.#", 64 | "1", 65 | ), 66 | resource.TestCheckResourceAttr( 67 | fmt.Sprintf("opnsense_firewall_filter_rule.%s", rName), 68 | "action", 69 | "pass", 70 | ), 71 | ), 72 | }, 73 | }, 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /opnsense/resource_firmware.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 11 | "github.com/kradalby/opnsense-go/opnsense" 12 | ) 13 | 14 | func resourceFirmware() *schema.Resource { 15 | return &schema.Resource{ 16 | CreateContext: resourceFirmwareCreate, 17 | ReadContext: resourceFirmwareRead, 18 | UpdateContext: resourceFirmwareUpdate, 19 | DeleteContext: resourceFirmwareDelete, 20 | 21 | Importer: &schema.ResourceImporter{ 22 | StateContext: schema.ImportStatePassthroughContext, 23 | }, 24 | 25 | Timeouts: &schema.ResourceTimeout{ 26 | Create: schema.DefaultTimeout(45 * time.Minute), 27 | }, 28 | 29 | Schema: map[string]*schema.Schema{ 30 | "plugin": { 31 | Type: schema.TypeSet, 32 | Optional: true, 33 | Computed: true, 34 | Description: "A plugin installed to OPNsense", 35 | Elem: &schema.Resource{ 36 | Schema: map[string]*schema.Schema{ 37 | "name": { 38 | Type: schema.TypeString, 39 | Required: true, 40 | }, 41 | "installed": { 42 | Type: schema.TypeBool, 43 | Required: true, 44 | }, 45 | "version": { 46 | Type: schema.TypeString, 47 | Computed: true, 48 | }, 49 | "comment": { 50 | Type: schema.TypeString, 51 | Computed: true, 52 | }, 53 | "flatsize": { 54 | Type: schema.TypeString, 55 | Computed: true, 56 | }, 57 | "locked": { 58 | Type: schema.TypeString, 59 | Computed: true, 60 | }, 61 | "license": { 62 | Type: schema.TypeString, 63 | Computed: true, 64 | }, 65 | "repository": { 66 | Type: schema.TypeString, 67 | Computed: true, 68 | }, 69 | "origin": { 70 | Type: schema.TypeString, 71 | Computed: true, 72 | }, 73 | "provided": { 74 | Type: schema.TypeBool, 75 | Computed: true, 76 | }, 77 | "path": { 78 | Type: schema.TypeString, 79 | Computed: true, 80 | }, 81 | "configured": { 82 | Type: schema.TypeBool, 83 | Computed: true, 84 | }, 85 | }, 86 | }, 87 | }, 88 | }, 89 | } 90 | } 91 | 92 | func resourceFirmwareRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 93 | log.Printf("[TRACE] Getting OPNsense client from meta") 94 | 95 | var diags diag.Diagnostics 96 | 97 | c := meta.(*opnsense.Client) 98 | 99 | installedPlugins, err := c.FirmwareInstalledPluginsList() 100 | if err != nil { 101 | log.Printf("[DEBUG]: \n%#v", err) 102 | log.Println("[ERROR] Failed to fetch information") 103 | 104 | return diag.FromErr(err) 105 | } 106 | 107 | installedPluginMaps := make([]map[string]interface{}, len(installedPlugins)) 108 | 109 | for index, plugin := range installedPlugins { 110 | installedPluginMaps[index] = opnsense.StructToMap(plugin) 111 | } 112 | 113 | if err := d.Set("plugin", installedPluginMaps); err != nil { 114 | return diag.FromErr(err) 115 | } 116 | 117 | d.SetId("firmware") 118 | 119 | return diags 120 | } 121 | 122 | func resourceFirmwareCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 123 | c := meta.(*opnsense.Client) 124 | 125 | added := d.Get("plugin").(*schema.Set) 126 | 127 | diags := installPlugins(ctx, d, c, added) 128 | if diags.HasError() { 129 | return diags 130 | } 131 | 132 | return resourceFirmwareRead(ctx, d, meta) 133 | } 134 | 135 | func resourceFirmwareUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 136 | c := meta.(*opnsense.Client) 137 | 138 | if d.HasChange("plugin") { 139 | oldRaw, newRaw := d.GetChange("plugin") 140 | old := oldRaw.(*schema.Set) 141 | new := newRaw.(*schema.Set) 142 | 143 | added := new.Difference(old) 144 | removed := old.Difference(new) 145 | 146 | diags := installPlugins(ctx, d, c, added) 147 | if diags.HasError() { 148 | return diags 149 | } 150 | 151 | diags = removePlugins(ctx, d, c, removed) 152 | if diags.HasError() { 153 | return diags 154 | } 155 | } 156 | 157 | return resourceFirmwareRead(ctx, d, meta) 158 | } 159 | 160 | func resourceFirmwareDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 161 | c := meta.(*opnsense.Client) 162 | 163 | removed := d.Get("plugin").(*schema.Set) 164 | 165 | diags := removePlugins(ctx, d, c, removed) 166 | if diags.HasError() { 167 | return diags 168 | } 169 | 170 | resourceFirmwareRead(ctx, d, meta) 171 | d.SetId("") 172 | 173 | return diags 174 | } 175 | 176 | func statusStateConf(d *schema.ResourceData, client *opnsense.Client) *resource.StateChangeConf { 177 | createStateConf := &resource.StateChangeConf{ 178 | Pending: []string{ 179 | opnsense.StatusRunning, 180 | }, 181 | Target: []string{ 182 | opnsense.StatusDone, 183 | }, 184 | Refresh: func() (interface{}, string, error) { 185 | resp, err := client.FirmwareUpgradeStatus() 186 | if err != nil { 187 | return 0, "", err 188 | } 189 | 190 | return resp, resp.Status, nil 191 | }, 192 | Timeout: d.Timeout(schema.TimeoutCreate), 193 | 194 | Delay: 10 * time.Second, 195 | MinTimeout: 5 * time.Second, 196 | ContinuousTargetOccurence: 2, 197 | } 198 | 199 | return createStateConf 200 | } 201 | 202 | func installPlugins(ctx context.Context, 203 | d *schema.ResourceData, 204 | c *opnsense.Client, 205 | added *schema.Set) diag.Diagnostics { 206 | var diags diag.Diagnostics 207 | 208 | for _, plug := range added.List() { 209 | plugin := plug.(map[string]interface{}) 210 | 211 | name := plugin["name"].(string) 212 | 213 | err := c.FirmwareInstall(name) 214 | if err != nil { 215 | return diag.FromErr(err) 216 | } 217 | 218 | upgradeChecker := statusStateConf(d, c) 219 | 220 | _, err = upgradeChecker.WaitForStateContext(ctx) 221 | if err != nil { 222 | return diag.FromErr(err) 223 | } 224 | } 225 | 226 | return diags 227 | } 228 | 229 | func removePlugins(ctx context.Context, 230 | d *schema.ResourceData, 231 | c *opnsense.Client, 232 | removed *schema.Set) diag.Diagnostics { 233 | var diags diag.Diagnostics 234 | 235 | for _, plug := range removed.List() { 236 | plugin := plug.(map[string]interface{}) 237 | 238 | name := plugin["name"].(string) 239 | 240 | err := c.FirmwareRemove(name) 241 | if err != nil { 242 | return diag.FromErr(err) 243 | } 244 | 245 | upgradeChecker := statusStateConf(d, c) 246 | 247 | _, err = upgradeChecker.WaitForStateContext(ctx) 248 | if err != nil { 249 | return diag.FromErr(err) 250 | } 251 | } 252 | 253 | return diags 254 | } 255 | -------------------------------------------------------------------------------- /opnsense/resource_firmware_test.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | "github.com/kradalby/opnsense-go/opnsense" 12 | ) 13 | 14 | func testFirmwarePluginResource(name string, plugins []string) string { 15 | return fmt.Sprintf(` 16 | locals { 17 | plugins = ["%s"] 18 | } 19 | 20 | resource "opnsense_firmware" "%s" { 21 | dynamic "plugin" { 22 | for_each = local.plugins 23 | 24 | content { 25 | name = plugin.value 26 | installed = true 27 | 28 | } 29 | } 30 | } 31 | `, strings.Join(plugins, `", "`), name) 32 | } 33 | 34 | func testAccFirmwarePluginResourceDestroy(s *terraform.State) error { 35 | c := testAccProvider.Meta().(*opnsense.Client) 36 | 37 | installedPlugins, err := c.FirmwareInstalledPluginsList() 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if len(installedPlugins) != 0 { 43 | return fmt.Errorf("All plugins are not uninstalled, %d", len(installedPlugins)) 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func TestFirmwarePlugin_basic(t *testing.T) { 50 | rName := fmt.Sprintf("a%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) 51 | 52 | resource.Test(t, resource.TestCase{ 53 | PreCheck: func() { testAccPreCheck(t) }, 54 | Providers: testAccProviders, 55 | CheckDestroy: testAccFirmwarePluginResourceDestroy, 56 | Steps: []resource.TestStep{ 57 | { 58 | Config: testFirmwarePluginResource(rName, 59 | []string{"os-vmware"}), 60 | Check: resource.ComposeTestCheckFunc( 61 | resource.TestCheckResourceAttr( 62 | fmt.Sprintf("opnsense_firmware.%s", rName), 63 | "plugin.#", 64 | "1", 65 | ), 66 | // resource.TestCheckResourceAttr( 67 | // fmt.Sprintf("opnsense_firmware.%s", rName), 68 | // "plugin.0.name", 69 | // "os-wireguard", 70 | // ), 71 | ), 72 | }, 73 | { 74 | Config: testFirmwarePluginResource(rName, 75 | []string{"os-iperf", "os-wireguard", "os-firewall"}), 76 | Check: resource.ComposeTestCheckFunc( 77 | resource.TestCheckResourceAttr( 78 | fmt.Sprintf("opnsense_firmware.%s", rName), 79 | "plugin.#", 80 | "3", 81 | ), 82 | // resource.TestCheckResourceAttr( 83 | // fmt.Sprintf("opnsense_firmware.%s", rName), 84 | // "plugin.0.name", 85 | // "os-iperf", 86 | // ), 87 | // resource.TestCheckResourceAttr( 88 | // fmt.Sprintf("opnsense_firmware.%s", rName), 89 | // "plugin.1.name", 90 | // "os-wireguard", 91 | // ), 92 | // resource.TestCheckResourceAttr( 93 | // fmt.Sprintf("opnsense_firmware.%s", rName), 94 | // "plugin.2.name", 95 | // "os-firewall", 96 | // ), 97 | ), 98 | }, 99 | { 100 | Config: testFirmwarePluginResource(rName, 101 | []string{"os-iperf", "os-firewall"}), 102 | Check: resource.ComposeTestCheckFunc( 103 | resource.TestCheckResourceAttr( 104 | fmt.Sprintf("opnsense_firmware.%s", rName), 105 | "plugin.#", 106 | "2", 107 | ), 108 | // resource.TestCheckResourceAttr( 109 | // fmt.Sprintf("opnsense_firmware.%s", rName), 110 | // "plugin.0.name", 111 | // "os-iperf", 112 | // ), 113 | // resource.TestCheckResourceAttr( 114 | // fmt.Sprintf("opnsense_firmware.%s", rName), 115 | // "plugin.1.name", 116 | // "os-firewall", 117 | // ), 118 | ), 119 | }, 120 | { 121 | Config: testFirmwarePluginResource(rName, 122 | []string{"os-iperf", "os-wireguard"}), 123 | Check: resource.ComposeTestCheckFunc( 124 | resource.TestCheckResourceAttr( 125 | fmt.Sprintf("opnsense_firmware.%s", rName), 126 | "plugin.#", 127 | "2", 128 | ), 129 | // resource.TestCheckResourceAttr( 130 | // fmt.Sprintf("opnsense_firmware.%s", rName), 131 | // "plugin.0.name", 132 | // "os-iperf", 133 | // ), 134 | // resource.TestCheckResourceAttr( 135 | // fmt.Sprintf("opnsense_firmware.%s", rName), 136 | // "plugin.1.name", 137 | // "os-wireguard", 138 | // ), 139 | ), 140 | }, 141 | { 142 | Config: testFirmwarePluginResource(rName, 143 | []string{"os-wireguard"}), 144 | Check: resource.ComposeTestCheckFunc( 145 | resource.TestCheckResourceAttr( 146 | fmt.Sprintf("opnsense_firmware.%s", rName), 147 | "plugin.#", 148 | "1", 149 | ), 150 | // resource.TestCheckResourceAttr( 151 | // fmt.Sprintf("opnsense_firmware.%s", rName), 152 | // "plugin.0.name", 153 | // "os-wireguard", 154 | // ), 155 | ), 156 | }, 157 | }, 158 | }) 159 | } 160 | -------------------------------------------------------------------------------- /opnsense/resource_wireguard_client.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "log" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 10 | "github.com/kradalby/opnsense-go/opnsense" 11 | uuid "github.com/satori/go.uuid" 12 | ) 13 | 14 | func resourceWireGuardClient() *schema.Resource { 15 | return &schema.Resource{ 16 | Create: resourceWireGuardClientCreate, 17 | Read: resourceWireGuardClientRead, 18 | Update: resourceWireGuardClientUpdate, 19 | Delete: resourceWireGuardClientDelete, 20 | 21 | Importer: &schema.ResourceImporter{ 22 | StateContext: schema.ImportStatePassthroughContext, 23 | }, 24 | 25 | Schema: map[string]*schema.Schema{ 26 | // "uuid": { 27 | // Type: schema.TypeString, 28 | // Description: "UUID assigned to client by OPNsense", 29 | // Computed: true, 30 | // }, 31 | "enabled": { 32 | Type: schema.TypeBool, 33 | Description: "Enable the client", 34 | Required: true, 35 | }, 36 | "name": { 37 | Type: schema.TypeString, 38 | Description: "Name of the client", 39 | Required: true, 40 | }, 41 | "tunnel_address": { 42 | Type: schema.TypeSet, 43 | Required: true, 44 | Description: "List of Tunnel addresses", 45 | Elem: &schema.Schema{ 46 | Type: schema.TypeString, 47 | Description: "Tunnel address for the client, e.g. 10.0.0.1/32", 48 | ValidateFunc: validation.IsCIDRNetwork(0, 32), 49 | }, 50 | }, 51 | "public_key": { 52 | Type: schema.TypeString, 53 | Description: "Public key of the client", 54 | Required: true, 55 | }, 56 | "shared_key": { 57 | Type: schema.TypeString, 58 | Description: "Shared key of the client", 59 | Optional: true, 60 | }, 61 | "endpoint_address": { 62 | Type: schema.TypeString, 63 | Description: "IP or CNAME of remote endpoint", 64 | Optional: true, 65 | }, 66 | "endpoint_port": { 67 | Type: schema.TypeInt, 68 | Description: "Port of remote endpoint", 69 | Optional: true, 70 | ValidateFunc: validation.IntBetween(10, 65535), 71 | }, 72 | "keep_alive": { 73 | Type: schema.TypeInt, 74 | Description: "Connection keep alive", 75 | Optional: true, 76 | ValidateFunc: validation.IntAtLeast(0), 77 | }, 78 | }, 79 | } 80 | } 81 | 82 | func resourceWireGuardClientRead(d *schema.ResourceData, meta interface{}) error { 83 | log.Printf("[TRACE] Getting OPNsense client from meta") 84 | 85 | c := meta.(*opnsense.Client) 86 | 87 | log.Printf("[TRACE] Converting ID to UUID") 88 | 89 | uuid, err := uuid.FromString(d.Id()) 90 | if err != nil { 91 | log.Printf("[ERROR] Failed to parse ID") 92 | 93 | return err 94 | } 95 | 96 | log.Printf("[TRACE] Fetching client configuration from OPNsense") 97 | 98 | client, err := c.WireGuardClientGet(uuid) 99 | if err != nil { 100 | if err.Error() == "found empty array, most likely 404" { 101 | d.SetId("") 102 | 103 | return nil 104 | } 105 | 106 | log.Printf("[DEBUG]: \n%#v", err) 107 | log.Printf("[ERROR] Failed to fetch uuid: %s", uuid) 108 | 109 | return err 110 | } 111 | 112 | log.Printf("[DEBUG] Configuration from OPNsense: \n") 113 | log.Printf("[DEBUG] %#v \n", client) 114 | 115 | err = d.Set("enabled", client.Enabled) 116 | if err != nil { 117 | return err 118 | } 119 | 120 | err = d.Set("name", client.Name) 121 | if err != nil { 122 | return err 123 | } 124 | 125 | err = d.Set("public_key", client.PubKey) 126 | if err != nil { 127 | return err 128 | } 129 | 130 | err = d.Set("shared_key", client.Psk) 131 | if err != nil { 132 | return err 133 | } 134 | 135 | err = d.Set("endpoint_address", client.ServerAddress) 136 | if err != nil { 137 | return err 138 | } 139 | 140 | tunnelAddressList := opnsense.ListSelectedValues(client.TunnelAddress) 141 | 142 | err = d.Set("tunnel_address", tunnelAddressList) 143 | if err != nil { 144 | return err 145 | } 146 | 147 | if client.ServerPort != "" { 148 | serverPort, err := strconv.Atoi(client.ServerPort) 149 | if err != nil { 150 | log.Printf("[ERROR] Failed to convert ServerPort to int: %s", client.ServerPort) 151 | 152 | return err 153 | } 154 | 155 | err = d.Set("endpoint_port", serverPort) 156 | if err != nil { 157 | return err 158 | } 159 | } 160 | 161 | keepAlive, err := strconv.Atoi(client.KeepAlive) 162 | if err != nil { 163 | log.Printf("[ERROR] Failed to convert KeepAlive to int: %s", client.KeepAlive) 164 | 165 | return err 166 | } 167 | 168 | err = d.Set("keep_alive", keepAlive) 169 | if err != nil { 170 | return err 171 | } 172 | 173 | return nil 174 | } 175 | 176 | func resourceWireGuardClientCreate(d *schema.ResourceData, meta interface{}) error { 177 | c := meta.(*opnsense.Client) 178 | 179 | client := opnsense.WireGuardClientSet{} 180 | 181 | err := prepareClientConfiguration(d, &client) 182 | if err != nil { 183 | return err 184 | } 185 | 186 | uuid, err := c.WireGuardClientAdd(client) 187 | if err != nil { 188 | return err 189 | } 190 | 191 | d.SetId(uuid.String()) 192 | err = resourceWireGuardClientRead(d, meta) 193 | 194 | return err 195 | } 196 | 197 | func resourceWireGuardClientUpdate(d *schema.ResourceData, meta interface{}) error { 198 | c := meta.(*opnsense.Client) 199 | 200 | uuid, err := uuid.FromString(d.Id()) 201 | if err != nil { 202 | return err 203 | } 204 | 205 | client := opnsense.WireGuardClientSet{} 206 | 207 | err = prepareClientConfiguration(d, &client) 208 | if err != nil { 209 | return err 210 | } 211 | 212 | _, err = c.WireGuardClientSet(uuid, client) 213 | if err != nil { 214 | return err 215 | } 216 | 217 | d.SetId(uuid.String()) 218 | err = resourceWireGuardClientRead(d, meta) 219 | 220 | return err 221 | } 222 | 223 | func resourceWireGuardClientDelete(d *schema.ResourceData, meta interface{}) error { 224 | c := meta.(*opnsense.Client) 225 | 226 | uuid, err := uuid.FromString(d.Id()) 227 | if err != nil { 228 | return err 229 | } 230 | 231 | _, err = c.WireGuardClientDelete(uuid) 232 | if err != nil { 233 | return err 234 | } 235 | 236 | d.SetId("") 237 | 238 | return nil 239 | } 240 | 241 | func prepareClientConfiguration(d *schema.ResourceData, client *opnsense.WireGuardClientSet) error { 242 | client.Enabled = opnsense.Bool(d.Get("enabled").(bool)) 243 | client.Name = d.Get("name").(string) 244 | client.PubKey = d.Get("public_key").(string) 245 | client.Psk = d.Get("shared_key").(string) 246 | client.ServerAddress = d.Get("endpoint_address").(string) 247 | 248 | if endpointPort := d.Get("endpoint_port").(int); endpointPort != 0 { 249 | log.Printf("[TRACE] ENDPOINT_PORT: %d", endpointPort) 250 | client.ServerPort = strconv.Itoa(endpointPort) 251 | } 252 | 253 | client.KeepAlive = strconv.Itoa(d.Get("keep_alive").(int)) 254 | 255 | tunnelAddressList := d.Get("tunnel_address").(*schema.Set).List() 256 | tunnelAddressStringList := make([]string, len(tunnelAddressList)) 257 | 258 | for index := range tunnelAddressList { 259 | tunnelAddressStringList[index] = tunnelAddressList[index].(string) 260 | } 261 | 262 | client.TunnelAddress = strings.Join(tunnelAddressStringList, ",") 263 | 264 | return nil 265 | } 266 | -------------------------------------------------------------------------------- /opnsense/resource_wireguard_client_test.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 10 | "github.com/kradalby/opnsense-go/opnsense" 11 | ) 12 | 13 | func testWireguardClientResource(name string) string { 14 | return fmt.Sprintf(` 15 | resource "opnsense_firmware" "%s" { 16 | plugin { 17 | name = "os-wireguard" 18 | installed = true 19 | } 20 | } 21 | 22 | resource "opnsense_wireguard_client" "%s" { 23 | enabled = true 24 | name = "tjoda" 25 | tunnel_address = ["10.10.10.0/24"] 26 | public_key = "sDoPaHLw1efsq78fDaOtzPHmqAWnZImeKTfdJT3Cfk8=" 27 | endpoint_port = 51820 28 | keep_alive = 21 29 | shared_key = "" 30 | } 31 | `, name, name) 32 | } 33 | 34 | func testAccWireguardClientResourceDestroy(s *terraform.State) error { 35 | c := testAccProvider.Meta().(*opnsense.Client) 36 | 37 | clients, err := c.WireGuardClientList() 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if len(clients) != 0 { 43 | return fmt.Errorf("All clients are not removed, %d", len(clients)) 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func TestWireguardClient_basic(t *testing.T) { 50 | rName := fmt.Sprintf("a%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) 51 | 52 | resource.Test(t, resource.TestCase{ 53 | PreCheck: func() { testAccPreCheck(t) }, 54 | Providers: testAccProviders, 55 | CheckDestroy: testAccWireguardClientResourceDestroy, 56 | Steps: []resource.TestStep{ 57 | { 58 | Config: testWireguardClientResource(rName), 59 | Check: resource.ComposeTestCheckFunc( 60 | resource.TestCheckResourceAttr( 61 | fmt.Sprintf("opnsense_firmware.%s", rName), 62 | "plugin.#", 63 | "1", 64 | ), 65 | resource.TestCheckResourceAttr( 66 | fmt.Sprintf("opnsense_wireguard_client.%s", rName), 67 | "name", 68 | "tjoda", 69 | ), 70 | ), 71 | }, 72 | }, 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /opnsense/resource_wireguard_server.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 11 | "github.com/kradalby/opnsense-go/opnsense" 12 | uuid "github.com/satori/go.uuid" 13 | ) 14 | 15 | func resourceWireGuardServer() *schema.Resource { 16 | return &schema.Resource{ 17 | Create: resourceWireGuardServerCreate, 18 | Read: resourceWireGuardServerRead, 19 | Update: resourceWireGuardServerUpdate, 20 | Delete: resourceWireGuardServerDelete, 21 | 22 | Importer: &schema.ResourceImporter{ 23 | StateContext: schema.ImportStatePassthroughContext, 24 | }, 25 | 26 | Schema: map[string]*schema.Schema{ 27 | "enabled": { 28 | Type: schema.TypeBool, 29 | Description: "Enable the server", 30 | Required: true, 31 | }, 32 | "name": { 33 | Type: schema.TypeString, 34 | Description: "Name of the server", 35 | Required: true, 36 | }, 37 | "public_key": { 38 | Type: schema.TypeString, 39 | Description: "Public key of the server", 40 | Computed: true, 41 | }, 42 | "private_key": { 43 | Type: schema.TypeString, 44 | Description: "Public key of the server", 45 | Computed: true, 46 | Sensitive: true, 47 | }, 48 | "port": { 49 | Type: schema.TypeInt, 50 | Description: "Listening port for WireGuard server", 51 | Required: true, 52 | ValidateFunc: validation.IntBetween(10, 65535), 53 | }, 54 | "mtu": { 55 | Type: schema.TypeInt, 56 | Description: "Set the interface MTU for this interface. Leaving empty uses the " + 57 | "MTU from main interface which is fine for most setups.", 58 | Optional: true, 59 | ValidateFunc: validation.IntBetween(0, 16384), 60 | }, 61 | "disable_routes": { 62 | Type: schema.TypeBool, 63 | Description: "Prevent WireGuard from adding routes", 64 | Required: true, 65 | }, 66 | "tunnel_address": { 67 | Type: schema.TypeSet, 68 | Required: true, 69 | Description: "List of Tunnel addresses", 70 | Elem: &schema.Schema{ 71 | Type: schema.TypeString, 72 | Description: "Tunnel address for the server, e.g. 10.0.0.1/32", 73 | ValidateFunc: validation.IsCIDRNetwork(0, 32), 74 | }, 75 | }, 76 | "dns": { 77 | Type: schema.TypeSet, 78 | Required: true, 79 | Description: "List of DNS addresses", 80 | Elem: &schema.Schema{ 81 | Type: schema.TypeString, 82 | Description: "DNS address, e.g. 10.0.0.1", 83 | }, 84 | }, 85 | "peers": { 86 | Type: schema.TypeSet, 87 | Required: true, 88 | Description: "List of UUIDs for clients", 89 | Elem: &schema.Schema{ 90 | Type: schema.TypeString, 91 | Description: "UUIDs for clients", 92 | ValidateFunc: validation.IsUUID, 93 | }, 94 | }, 95 | }, 96 | } 97 | } 98 | 99 | func resourceWireGuardServerRead(d *schema.ResourceData, meta interface{}) error { 100 | log.Printf("[TRACE] Getting OPNsense client from meta") 101 | 102 | c := meta.(*opnsense.Client) 103 | 104 | log.Printf("[TRACE] Converting ID to UUID") 105 | 106 | uuid, err := uuid.FromString(d.Id()) 107 | if err != nil { 108 | log.Printf("[ERROR] Failed to parse ID") 109 | 110 | return err 111 | } 112 | 113 | log.Printf("[TRACE] Fetching server configuration from OPNsense") 114 | 115 | server, err := c.WireGuardServerGet(uuid) 116 | if err != nil { 117 | log.Printf("[ERROR] Failed to fetch uuid: %s", uuid) 118 | 119 | return err 120 | } 121 | 122 | log.Printf("[DEBUG] Configuration from OPNsense: \n") 123 | log.Printf("[DEBUG] %#v \n", server) 124 | 125 | err = d.Set("enabled", server.Enabled) 126 | if err != nil { 127 | return err 128 | } 129 | 130 | err = d.Set("name", server.Name) 131 | if err != nil { 132 | return err 133 | } 134 | 135 | err = d.Set("public_key", server.PubKey) 136 | if err != nil { 137 | return err 138 | } 139 | 140 | err = d.Set("private_key", server.PrivKey) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | err = d.Set("disable_routes", server.DisableRoutes) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | port, err := strconv.Atoi(server.Port) 151 | if err != nil { 152 | log.Printf("[ERROR] Failed to convert ServerPort to int: %s", server.Port) 153 | 154 | return err 155 | } 156 | 157 | err = d.Set("port", port) 158 | if err != nil { 159 | return err 160 | } 161 | 162 | if server.MTU != "" { 163 | mtu, err := strconv.Atoi(server.MTU) 164 | if err != nil { 165 | log.Printf("[ERROR] Failed to convert MTU to int: %s", server.MTU) 166 | 167 | return err 168 | } 169 | 170 | err = d.Set("mtu", mtu) 171 | if err != nil { 172 | return err 173 | } 174 | } 175 | 176 | // TODO: Handle this map[string]interface 177 | // d.Set("tunnel_address", server.TunnelAddress) 178 | if server.TunnelAddress != nil { 179 | tunnelAddressList := opnsense.ListSelectedValues(server.TunnelAddress) 180 | 181 | err = d.Set("tunnel_address", tunnelAddressList) 182 | if err != nil { 183 | return err 184 | } 185 | } 186 | 187 | if server.DNS != nil { 188 | dnsAddressList := opnsense.ListSelectedValues(server.DNS) 189 | 190 | err = d.Set("dns", dnsAddressList) 191 | if err != nil { 192 | return err 193 | } 194 | } 195 | 196 | if server.Peers != nil { 197 | peerList := opnsense.ListSelectedKeys(server.Peers) 198 | 199 | err = d.Set("peers", peerList) 200 | if err != nil { 201 | return err 202 | } 203 | } 204 | 205 | return nil 206 | } 207 | 208 | func resourceWireGuardServerCreate(d *schema.ResourceData, meta interface{}) error { 209 | c := meta.(*opnsense.Client) 210 | 211 | server := opnsense.WireGuardServerSet{} 212 | 213 | err := prepareServerConfiguration(d, &server) 214 | if err != nil { 215 | return err 216 | } 217 | 218 | err = c.WireGuardServerAdd(server) 219 | if err != nil { 220 | return err 221 | } 222 | 223 | uuids, err := c.WireGuardServerFindUUIDByName(server.Name) 224 | if err != nil { 225 | return err 226 | } 227 | 228 | if len(uuids) != 1 { 229 | err := fmt.Errorf( 230 | "server returned %d UUIDs for the given server name %w", 231 | len(uuids), ErrMoreThanOneUUIDReturned, 232 | ) 233 | log.Printf("[ERROR] %#v", err) 234 | 235 | return err 236 | } 237 | 238 | d.SetId(uuids[0].String()) 239 | 240 | err = resourceWireGuardServerRead(d, meta) 241 | 242 | return err 243 | } 244 | 245 | func resourceWireGuardServerUpdate(d *schema.ResourceData, meta interface{}) error { 246 | c := meta.(*opnsense.Client) 247 | 248 | uuid, err := uuid.FromString(d.Id()) 249 | if err != nil { 250 | return err 251 | } 252 | 253 | server := opnsense.WireGuardServerSet{} 254 | 255 | err = prepareServerConfiguration(d, &server) 256 | if err != nil { 257 | return err 258 | } 259 | 260 | _, err = c.WireGuardServerSet(uuid, server) 261 | if err != nil { 262 | return err 263 | } 264 | 265 | d.SetId(uuid.String()) 266 | err = resourceWireGuardServerRead(d, meta) 267 | 268 | return err 269 | } 270 | 271 | func resourceWireGuardServerDelete(d *schema.ResourceData, meta interface{}) error { 272 | c := meta.(*opnsense.Client) 273 | 274 | uuid, err := uuid.FromString(d.Id()) 275 | if err != nil { 276 | return err 277 | } 278 | 279 | _, err = c.WireGuardServerDelete(uuid) 280 | if err != nil { 281 | return err 282 | } 283 | 284 | d.SetId("") 285 | 286 | return nil 287 | } 288 | 289 | func prepareServerConfiguration(d *schema.ResourceData, server *opnsense.WireGuardServerSet) error { 290 | server.Enabled = opnsense.Bool(d.Get("enabled").(bool)) 291 | server.Name = d.Get("name").(string) 292 | server.PubKey = d.Get("public_key").(string) 293 | server.PrivKey = d.Get("private_key").(string) 294 | server.DisableRoutes = opnsense.Bool(d.Get("disable_routes").(bool)) 295 | 296 | server.Port = strconv.Itoa(d.Get("port").(int)) 297 | 298 | if d.Get("MTU") != nil { 299 | server.MTU = strconv.Itoa(d.Get("MTU").(int)) 300 | } 301 | 302 | tunnelAddressList := d.Get("tunnel_address").(*schema.Set).List() 303 | tunnelAddressStringList := make([]string, len(tunnelAddressList)) 304 | 305 | for index := range tunnelAddressList { 306 | tunnelAddressStringList[index] = tunnelAddressList[index].(string) 307 | } 308 | 309 | server.TunnelAddress = strings.Join(tunnelAddressStringList, ",") 310 | 311 | dnsAddressList := d.Get("dns").(*schema.Set).List() 312 | dnsAddressStringList := make([]string, len(dnsAddressList)) 313 | 314 | for index := range dnsAddressList { 315 | dnsAddressStringList[index] = dnsAddressList[index].(string) 316 | } 317 | 318 | server.DNS = strings.Join(dnsAddressStringList, ",") 319 | 320 | peerList := d.Get("peers").(*schema.Set).List() 321 | peerStringList := make([]string, len(peerList)) 322 | 323 | for index := range peerList { 324 | peerStringList[index] = peerList[index].(string) 325 | } 326 | 327 | server.Peers = strings.Join(peerStringList, ",") 328 | 329 | return nil 330 | } 331 | -------------------------------------------------------------------------------- /opnsense/resource_wireguard_server_test.go: -------------------------------------------------------------------------------- 1 | package opnsense 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 10 | "github.com/kradalby/opnsense-go/opnsense" 11 | ) 12 | 13 | func testWireguardServerResource(name string) string { 14 | return fmt.Sprintf(` 15 | resource "opnsense_firmware" "%s" { 16 | plugin { 17 | name = "os-wireguard" 18 | installed = true 19 | } 20 | } 21 | 22 | resource "opnsense_wireguard_server" "%s" { 23 | enabled = true 24 | name = "tjoda" 25 | tunnel_address = ["10.10.10.0/24"] 26 | port = 51820 27 | disable_routes = false 28 | dns = ["1.1.1.1"] 29 | peers = [] 30 | } 31 | `, name, name) 32 | } 33 | 34 | func testAccWireguardServerResourceDestroy(s *terraform.State) error { 35 | c := testAccProvider.Meta().(*opnsense.Client) 36 | 37 | servers, err := c.WireGuardServerList() 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if len(servers) != 0 { 43 | return fmt.Errorf("All servers are not removed, %d", len(servers)) 44 | } 45 | 46 | return nil 47 | } 48 | 49 | func TestWireguardServer_basic(t *testing.T) { 50 | rName := fmt.Sprintf("a%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) 51 | 52 | resource.Test(t, resource.TestCase{ 53 | PreCheck: func() { testAccPreCheck(t) }, 54 | Providers: testAccProviders, 55 | CheckDestroy: testAccWireguardServerResourceDestroy, 56 | Steps: []resource.TestStep{ 57 | { 58 | Config: testWireguardServerResource(rName), 59 | Check: resource.ComposeTestCheckFunc( 60 | resource.TestCheckResourceAttr( 61 | fmt.Sprintf("opnsense_firmware.%s", rName), 62 | "plugin.#", 63 | "1", 64 | ), 65 | resource.TestCheckResourceAttr( 66 | fmt.Sprintf("opnsense_wireguard_server.%s", rName), 67 | "name", 68 | "tjoda", 69 | ), 70 | ), 71 | }, 72 | }, 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>kradalby/renovate-config"] 3 | } 4 | -------------------------------------------------------------------------------- /scripts/changelog-links.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to 4 | # be Markdown links to the given github issues. 5 | # 6 | # This is run during releases so that the issue references in all of the 7 | # released items are presented as clickable links, but we can just use the 8 | # easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section 9 | # while merging things between releases. 10 | 11 | set -e 12 | 13 | if [[ ! -f CHANGELOG.md ]]; then 14 | echo "ERROR: CHANGELOG.md not found in pwd." 15 | echo "Please run this from the root of the terraform provider repository" 16 | exit 1 17 | fi 18 | 19 | if [[ `uname` == "Darwin" ]]; then 20 | echo "Using BSD sed" 21 | SED="sed -i.bak -E -e" 22 | else 23 | echo "Using GNU sed" 24 | SED="sed -i.bak -r -e" 25 | fi 26 | 27 | PROVIDER_URL="https:\/\/github.com\/terraform-providers\/terraform-provider-template\/issues" 28 | 29 | $SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md 30 | 31 | rm CHANGELOG.md.bak 32 | -------------------------------------------------------------------------------- /scripts/errcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check gofmt 4 | echo "==> Checking for unchecked errors..." 5 | 6 | if ! which errcheck > /dev/null; then 7 | echo "==> Installing errcheck..." 8 | go get -u github.com/kisielk/errcheck 9 | fi 10 | 11 | err_files=$(errcheck -ignoretests \ 12 | -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \ 13 | -ignore 'bytes:.*' \ 14 | -ignore 'io:Close|Write' \ 15 | $(go list ./...| grep -v /vendor/)) 16 | 17 | if [[ -n ${err_files} ]]; then 18 | echo 'Unchecked errors found in the following places:' 19 | echo "${err_files}" 20 | echo "Please handle returned errors. You can check directly with \`make errcheck\`" 21 | exit 1 22 | fi 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /scripts/gofmtcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check gofmt 4 | echo "==> Checking that code complies with gofmt requirements..." 5 | gofmt_files=$(gofmt -l `find . -name '*.go' | grep -v vendor`) 6 | if [[ -n ${gofmt_files} ]]; then 7 | echo 'gofmt needs running on the following files:' 8 | echo "${gofmt_files}" 9 | echo "You can use the command: \`make fmt\` to reformat code." 10 | exit 1 11 | fi 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /scripts/gogetcookie.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch ~/.gitcookies 4 | chmod 0600 ~/.gitcookies 5 | 6 | git config --global http.cookiefile ~/.gitcookies 7 | 8 | tr , \\t <<\__END__ >>~/.gitcookies 9 | .googlesource.com,TRUE,/,TRUE,2147483647,o,git-paul.hashicorp.com=1/z7s05EYPudQ9qoe6dMVfmAVwgZopEkZBb1a2mA5QtHE 10 | __END__ 11 | --------------------------------------------------------------------------------