├── .github └── workflows │ ├── golangci.yml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── .idea ├── .gitignore ├── misc.xml ├── modules.xml ├── terraform-provider-mongodb.iml └── vcs.xml ├── LICENSE ├── Makefile ├── README.md ├── docker ├── conf │ └── config.js ├── docker-compose-socks.yml ├── docker-compose-ssl.yaml ├── docker-compose.yml └── docker-mongo-ssl │ ├── Dockerfile │ ├── mongod.conf │ ├── scripts │ ├── run.sh │ └── setup_user.sh │ └── ssl │ ├── ca.pem │ └── kaginari.pem ├── docs ├── index.md └── resources │ ├── database_role.md │ └── database_user.md ├── examples ├── Makefile ├── documentDB │ ├── Makefile │ ├── main.tf │ └── variables.tf └── main.tf ├── go.mod ├── go.sum ├── main.go ├── mmo.md └── mongodb ├── config.go ├── helpers.go ├── provider.go ├── resource_db_role.go └── resource_db_user.go /.github/workflows/golangci.yml: -------------------------------------------------------------------------------- 1 | name: golangci 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | go_lint: 12 | name: golangci-lint 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Run golangci-lint 17 | uses: golangci/golangci-lint-action@v2 18 | with: 19 | version: v1.30 20 | skip-go-installation: true 21 | 22 | go_test: 23 | name: golang test 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Download Go modules 28 | run: go mod download 29 | - name: Run Test 30 | run: go test ./... -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | jobs: 7 | goreleaser: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Unshallow 13 | run: git fetch --prune --unshallow 14 | - name: Set up Go 15 | uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.17 18 | - name: Import GPG key 19 | id: import_gpg 20 | uses: paultyng/ghaction-import-gpg@v2.1.0 21 | env: 22 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 23 | PASSPHRASE: ${{ secrets.PASSPHRASE }} 24 | - name: Run GoReleaser 25 | uses: goreleaser/goreleaser-action@v2 26 | with: 27 | version: latest 28 | args: release --rm-dist 29 | env: 30 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.tfstate 2 | **/*.tfstate.backup 3 | **/*.idea 4 | **/.terraform 5 | **/*.locl.hcl 6 | **/testgo/** 7 | **/.terraform.lock.hcl 8 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | deadline: 10m 3 | 4 | issues: 5 | max-per-linter: 0 6 | max-same-issues: 0 7 | 8 | linters: 9 | disable-all: true 10 | enable: 11 | - deadcode 12 | - errcheck 13 | - ineffassign 14 | - interfacer 15 | - nakedret 16 | - misspell 17 | - typecheck 18 | - unused 19 | - unconvert 20 | - unparam 21 | - varcheck 22 | - vet 23 | - vetshadow 24 | 25 | linters-settings: 26 | errcheck: 27 | ignore: github.com/hashicorp/terraform-plugin-sdk/helper/schema:ForceNew|Set,fmt:.*,io:Close 28 | misspell: 29 | ignore-words: 30 | - hdinsight 31 | - exportfs -------------------------------------------------------------------------------- /.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 }}_{{ .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 | # If you want to manually examine the release before its live, uncomment this line: 52 | # draft: true 53 | changelog: 54 | skip: true -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /../../../../../../../../../:\Users\monta\go\src\github.com\Kaginari\terraform-provider-mongodb\.idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/terraform-provider-mongodb.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kaginari 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifndef VERBOSE 2 | MAKEFLAGS += --no-print-directory 3 | endif 4 | 5 | default: install 6 | 7 | .PHONY: install lint unit 8 | 9 | OS_ARCH=linux_amd64 10 | # 11 | # Set correct OS_ARCH on Mac 12 | UNAME := $(shell uname -s) 13 | ifeq ($(UNAME),Darwin) 14 | HW := $(shell uname -m) 15 | ifeq ($(HW),arm64) 16 | ARCH=$(HW) 17 | else 18 | ARCH=amd64 19 | endif 20 | OS_ARCH=darwin_$(ARCH) 21 | endif 22 | 23 | HOSTNAME=registry.terraform.io 24 | NAMESPACE=Kaginari 25 | NAME=mongodb 26 | VERSION=9.9.9 27 | ## on linux base os 28 | TERRAFORM_PLUGINS_DIRECTORY=~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 29 | 30 | 31 | install: 32 | mkdir -p ${TERRAFORM_PLUGINS_DIRECTORY} 33 | go build -o ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 34 | cd examples && rm -rf .terraform 35 | cd examples && make init 36 | re-install: 37 | rm -f ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 38 | go build -o ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 39 | cd examples && rm -rf .terraform 40 | cd examples && make init 41 | lint: 42 | golangci-lint run 43 | 44 | 45 | documentdb-test: 46 | rm -f ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 47 | go build -o ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 48 | cd examples && rm -rf .terraform 49 | cd examples/documentDB && rm -rf .terraform && make init 50 | 51 | documentdb-test-apply: 52 | rm -f ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 53 | go build -o ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 54 | cd examples && rm -rf .terraform 55 | cd examples/documentDB && rm -rf .terraform && make init && make apply 56 | 57 | documentdb-test-apply: 58 | rm -f ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 59 | go build -o ${TERRAFORM_PLUGINS_DIRECTORY}/terraform-provider-${NAME} 60 | cd examples && rm -rf .terraform 61 | cd examples/documentDB && rm -rf .terraform && make init && make destroy 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Provider Mongodb 2 | ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/Kaginari/terraform-provider-mongodb?logo=go&style=flat-square) 3 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Kaginari/terraform-provider-mongodb?logo=git&style=flat-square) 4 | ![GitHub](https://img.shields.io/github/license/Kaginari/terraform-provider-mongodb?color=yellow&style=flat-square) 5 | ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Kaginari/terraform-provider-mongodb/golangci?logo=github&style=flat-square) 6 | ![GitHub issues](https://img.shields.io/github/issues/Kaginari/terraform-provider-mongodb?logo=github&style=flat-square) 7 | 8 | 9 | This repository is a Terraform Mongodb for [Terraform](https://www.terraform.io). 10 | 11 | ### Requirements 12 | 13 | - [Terraform](https://www.terraform.io/downloads.html) >= 0.13 14 | - [Go](https://golang.org/doc/install) >= 1.17 15 | 16 | ### Installation 17 | 18 | 1. Clone the repository 19 | 1. Enter the repository directory 20 | 1. Build the provider using the `make install` command: 21 | 22 | ````bash 23 | git clone https://github.com/Kaginari/terraform-provider-mongodb 24 | cd terraform-provider-mongodb 25 | make install 26 | ```` 27 | 28 | ### To test locally 29 | 30 | **1.1: create mongo image with ssl** 31 | 32 | 33 | ````bash 34 | cd docker/docker-mongo-ssl 35 | docker build -t mongo-local . 36 | ```` 37 | **1.2: create ssl for localhost** 38 | 39 | 40 | *follow the instruction in this link* 41 | 42 | https://ritesh-yadav.github.io/tech/getting-valid-ssl-certificate-for-localhost-from-letsencrypt/ 43 | 44 | 45 | ````bash 46 | nano /etc/hosts 47 | 127.0.0.1 kaginar.herokuapp.com ### add this line 48 | ```` 49 | 50 | 51 | **1.3: start the docker-compose** 52 | ````bash 53 | cd docker 54 | docker-compose up -d 55 | ```` 56 | **1.4 : create admin user in mongo** 57 | 58 | ````bash 59 | $ docker exec -it mongo -c mongo 60 | > use admin 61 | > db.createUser({ user: "root" , pwd: "root", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"]}) 62 | ```` 63 | **2: Build the provider** 64 | 65 | follow the [Installation](#Installation) 66 | 67 | **3: Use the provider** 68 | 69 | ````bash 70 | cd mongodb 71 | make apply 72 | ```` 73 | -------------------------------------------------------------------------------- /docker/conf/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongodb: { 3 | ssl: true, 4 | sslValidate: false, 5 | } 6 | }; -------------------------------------------------------------------------------- /docker/docker-compose-socks.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | networks: 4 | network: 5 | driver: bridge 6 | 7 | services: 8 | mongo: 9 | container_name: mongo 10 | image: mongo:3.6 11 | restart: always 12 | environment: 13 | - MONGODB_USER:root 14 | - MONGODB_PASS:root 15 | - MONGODB_DATABASE=admin 16 | volumes: 17 | - mongo_data:/data/db 18 | ports: 19 | - 27017:27017 20 | networks: 21 | - network 22 | mongo-express: 23 | image: mongo-express 24 | container_name: mongo-express 25 | ports: 26 | - 8081:8081 27 | environment: 28 | ME_CONFIG_BASICAUTH_USERNAME: root 29 | ME_CONFIG_BASICAUTH_PASSWORD: root 30 | ME_CONFIG_MONGODB_SERVER: mongo 31 | ME_CONFIG_MONGODB_PORT: 27017 32 | ME_CONFIG_MONGODB_ADMINUSERNAME: root 33 | ME_CONFIG_MONGODB_ADMINPASSWORD: root 34 | links: 35 | - mongo:mongo 36 | networks: 37 | - network 38 | depends_on: 39 | - mongo 40 | socks5: 41 | image: serjs/go-socks5-proxy 42 | container_name: socks 43 | ports: 44 | - 1080:1080 45 | networks: 46 | - network 47 | depends_on: 48 | - mongo 49 | volumes: 50 | mongo_data: {} -------------------------------------------------------------------------------- /docker/docker-compose-ssl.yaml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | networks: 4 | network: 5 | driver: bridge 6 | ipam: 7 | config: 8 | - subnet: 172.30.0.0/24 9 | gateway: 172.30.0.1 10 | services: 11 | mongo: 12 | container_name: mongo 13 | image: mongo-local 14 | restart: always 15 | volumes: 16 | - mongo_data:/data/db 17 | - config_db:/data/configdb 18 | ports: 19 | - 27017:27017 20 | networks: 21 | network: 22 | ipv4_address: 172.30.0.2 23 | mongo-express: 24 | image: mongo-express 25 | container_name: mongo-express 26 | restart: always 27 | ports: 28 | - 8081:8081 29 | environment: 30 | ME_CONFIG_BASICAUTH_USERNAME: admin 31 | ME_CONFIG_BASICAUTH_PASSWORD: admin 32 | ME_CONFIG_MONGODB_SERVER: kaginari.herokuapp.com 33 | ME_CONFIG_MONGODB_PORT: 27017 34 | ME_CONFIG_MONGODB_ADMINUSERNAME: root 35 | ME_CONFIG_MONGODB_ADMINPASSWORD: root 36 | network_mode: host 37 | volumes: 38 | - "./conf/config.js:/node_modules/mongo-express/config.js:ro" 39 | depends_on: 40 | - mongo 41 | volumes: 42 | mongo_data: {} 43 | config_db: {} 44 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | networks: 4 | network: 5 | driver: bridge 6 | 7 | services: 8 | mongo: 9 | container_name: mongo 10 | image: mongo:3.6 11 | restart: always 12 | environment: 13 | - MONGODB_USER:root 14 | - MONGODB_PASS:root 15 | - MONGODB_DATABASE=admin 16 | volumes: 17 | - mongo_data:/data/db 18 | ports: 19 | - 27017:27017 20 | networks: 21 | - network 22 | mongo-express: 23 | image: mongo-express 24 | container_name: mongo-express 25 | ports: 26 | - 8081:8081 27 | environment: 28 | ME_CONFIG_BASICAUTH_USERNAME: root 29 | ME_CONFIG_BASICAUTH_PASSWORD: root 30 | ME_CONFIG_MONGODB_SERVER: mongo 31 | ME_CONFIG_MONGODB_PORT: 27017 32 | ME_CONFIG_MONGODB_ADMINUSERNAME: root 33 | ME_CONFIG_MONGODB_ADMINPASSWORD: root 34 | links: 35 | - mongo:mongo 36 | networks: 37 | - network 38 | depends_on: 39 | - mongo 40 | volumes: 41 | mongo_data: {} -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mongo:3.6.2-jessie 2 | 3 | COPY scripts /home/mongodb/scripts 4 | 5 | COPY ssl /home/mongodb/ssl 6 | 7 | COPY mongod.conf /home/mongodb 8 | 9 | WORKDIR /home/mongodb 10 | 11 | RUN ["chmod", "+x", "/home/mongodb/scripts/"] 12 | 13 | CMD ["/home/mongodb/scripts/run.sh"] -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/mongod.conf: -------------------------------------------------------------------------------- 1 | net: 2 | bindIp: 0.0.0.0 3 | port: 27017 4 | ssl: 5 | CAFile: /home/mongodb/ssl/ca.pem 6 | PEMKeyFile: /home/mongodb/ssl/kaginari.pem 7 | mode: requireSSL 8 | disabledProtocols: "TLS1_0,TLS1_1" 9 | allowConnectionsWithoutCertificates: true 10 | storage: 11 | journal: 12 | enabled: true -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sleep 5 4 | 5 | chown -R mongodb:mongodb /home/mongodb 6 | 7 | nohup gosu mongodb mongod --dbpath=/data/db & 8 | 9 | nohup gosu mongodb mongo admin --eval "help" > /dev/null 2>&1 10 | RET=$? 11 | 12 | while [[ "$RET" -ne 0 ]]; do 13 | echo "Waiting for MongoDB to start..." 14 | mongo admin --eval "help" > /dev/null 2>&1 15 | RET=$? 16 | sleep 2 17 | done 18 | 19 | bash /home/mongodb/scripts/setup_user.sh 20 | 21 | gosu mongodb mongod --dbpath=/data/db --config mongod.conf --bind_ip_all --auth -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/scripts/setup_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "************************************************************" 4 | echo "Setting up users..." 5 | echo "************************************************************" 6 | 7 | # create root user 8 | nohup gosu mongodb mongo admin --eval "db.createUser({user: 'root', pwd: 'root', roles:[{ role: 'root', db: 'admin' }]});" 9 | 10 | # create app user/database 11 | nohup gosu mongodb mongo admin --eval "db.createUser({ user: 'admin', pwd: 'admin', roles: ['userAdminAnyDatabase', 'dbAdminAnyDatabase', 'readWriteAnyDatabase']});" 12 | 13 | echo "************************************************************" 14 | echo "Shutting down" 15 | echo "************************************************************" 16 | nohup gosu mongodb mongo admin --eval "db.shutdownServer();" -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/ssl/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ 3 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 4 | DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow 5 | PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD 6 | Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 7 | AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O 8 | rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq 9 | OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b 10 | xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 11 | 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD 12 | aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV 13 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG 14 | SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 15 | ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr 16 | AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz 17 | R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 18 | JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo 19 | Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ 20 | -----END CERTIFICATE----- 21 | -----BEGIN CERTIFICATE----- 22 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ 23 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 24 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow 25 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT 26 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC 27 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF 28 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 29 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 30 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA 31 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj 32 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T 33 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG 34 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv 35 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k 36 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw 37 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC 38 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz 39 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu 40 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF 41 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo 42 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ 43 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu 44 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG 45 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 46 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== 47 | -----END CERTIFICATE----- 48 | -------------------------------------------------------------------------------- /docker/docker-mongo-ssl/ssl/kaginari.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgptuYwTaYmOqC 3 | nTN72QKBqEXHW/yN9gZLJyTmPlcDrBXR8WY0WiKaDpJbHvH8HTgt12wUjFW3P6py 4 | DtnkTdtz3OXt6BZjejXZgAPW/KA10+/3GyZgfDWFfUKe/r5D5RxUduK5QVEyOVHT 5 | kUqpcxl5WR7eK6Xt01ElLeKNO1yhjT0J11nOWezfI9w6Q443N+XV+/k3HJ36382A 6 | 1ZeXQ3NcLZdJs6eGitb+3gk1vFZVFE2+kF0ApMw/+Qt7LciciDCM99x/N5rFqBul 7 | n010WfUfpwDsnh6Iq98hmecTYLP1dP0xM1IWAGoRSOkNY8wHuxvzxajlBHS0iY4p 8 | r/ffNHkBAgMBAAECggEAHbwEdRd95WyYKyixeMDHx/u/PpD2A8h/jbVnDP6I2HMn 9 | br5BbnsoYF9GE3t8ym8WENYIeR0oWEx+XbIF/k2yypUeMZR9YFgkU2dwToBfntbl 10 | WVU7GyyiM1zl0cvQp3xma/O9LxC52JPnY0NHEGnvUxh9sB1gDs7H/BusDPvpvzS7 11 | /O+KSE056426fwmkGXpnNmQ8lKyMRKKIZNgcVW6TlLyU6i0ruChhYbMqYsqdHtEM 12 | 8rVU7M5kIiqUja6bdh4B14tvvz6BbrZkP9BrkTDhRIp77fK1Mn5h3YLoGjIQLj6w 13 | FbazUPhobOoJP/8WIWyxYl8/yWNr3Ru50ZaDnLtiCQKBgQDN7ytd5gl5ET6CzZmJ 14 | vLa+eqCD0E4raFzJMH4U07xvQ8ti7chUIx6q2/s89lSWTBIc/moPMbfs06a7mj12 15 | 0nEYf9/u6dYk+Gh5pebTGAZItV63cOajiNu6o8pSUJpz9/kEqXYNnBJV6LB0JK09 16 | 4fcdunzCpfdPX664ZvsiNK6R1wKBgQDHtWviapU08CKYFtl6pCeSIT8dljnZv9Pp 17 | GheUtmGODNCW5um5Vpa6rPvIs/duy0t4jcm0SjDvyeJ78JLtnHka431/srX9xlR2 18 | xasnIcXh6B0jnMDTp+ZWTQAhS3y2l5KLv4YJLdUPst0gviiv0eDOFSPg30uBQJpc 19 | l4Tm0awg5wKBgQCnu9rSzH+CwOztlZEtgyxF0ZPUSWKiMIsCxCCtzhh5d/q9RXga 20 | L9DW0f69FNao5KUMQJ0aayCoIWx4+ZR+p8G+dslqy8PEsSBHlT2BStwzdKcFO0xg 21 | fySZzLcKfOSQ+LU3et/RDgJRPwoaT5VcBiVFbZQY5x2c5Q5m3FpI7igSWQKBgB6j 22 | 6ByB68iGe1hIUS+u1d9muG9KqC+Pbezasvl/DfKkZrBwVzW3YkLb3XmKmxDlofuq 23 | DWNa6q0vlU8ctv47vpzwgEXCXofEERtz8nF7jge9/BKFr1QJ854UDEwPb9/322UT 24 | inYIESNqduDaLBXlpo8X0TxkJgp7pfNE0AA19SnLAoGAarXjfqkVWJu2R9skjH/0 25 | zfdb6CYFtHVpjrbZBlDnZ/3WpErbFtJNuAkEqItaCcxKA+PsB4RQJLRVkATd+WzA 26 | voZeEskCQ5EgdfamEOJCY7OdIOSOCSXyS3MaAsh8iub2ef6IBX4u6jqgtBkzsKMo 27 | fXRxB8ShNEvTjhpzL8iKDtk= 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIFZDCCBEygAwIBAgISA8SqREPofGLDM8dZi7IG8VhWMA0GCSqGSIb3DQEBCwUA 31 | MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD 32 | ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDExMTcwOTEyMzJaFw0y 33 | MTAyMTUwOTEyMzJaMCExHzAdBgNVBAMTFmthZ2luYXJpLmhlcm9rdWFwcC5jb20w 34 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgptuYwTaYmOqCnTN72QKB 35 | qEXHW/yN9gZLJyTmPlcDrBXR8WY0WiKaDpJbHvH8HTgt12wUjFW3P6pyDtnkTdtz 36 | 3OXt6BZjejXZgAPW/KA10+/3GyZgfDWFfUKe/r5D5RxUduK5QVEyOVHTkUqpcxl5 37 | WR7eK6Xt01ElLeKNO1yhjT0J11nOWezfI9w6Q443N+XV+/k3HJ36382A1ZeXQ3Nc 38 | LZdJs6eGitb+3gk1vFZVFE2+kF0ApMw/+Qt7LciciDCM99x/N5rFqBuln010WfUf 39 | pwDsnh6Iq98hmecTYLP1dP0xM1IWAGoRSOkNY8wHuxvzxajlBHS0iY4pr/ffNHkB 40 | AgMBAAGjggJrMIICZzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH 41 | AwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPw4gn5Yl4PbX0RP 42 | 1Mo7qs7qcoG5MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsG 43 | AQUFBwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNl 44 | bmNyeXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNl 45 | bmNyeXB0Lm9yZy8wIQYDVR0RBBowGIIWa2FnaW5hcmkuaGVyb2t1YXBwLmNvbTBM 46 | BgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIB 47 | FhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUE 48 | gfIA8AB3AG9Tdqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABddWxEcIA 49 | AAQDAEgwRgIhAJRDaIgJKCAg7lCAaGAK9onUh1gzx+uQvpHHdOZJ24txAiEA98Mb 50 | 6wJ3Rll3WkxZRwJOlfxUhcJuD13SscngM/8FKVkAdQD2XJQv0XcwIhRUGAgwlFaO 51 | 400TGTO/3wwvIAvMTvFk4wAAAXXVsRGVAAAEAwBGMEQCIAgeIRe/lTcktVumQcID 52 | RF2oh1+lLWlBi8G9inbMiOaSAiBvCLVPbnd5ePMSlOBcFFVkRW5Hxs7m7oDWgLEl 53 | cX0VCTANBgkqhkiG9w0BAQsFAAOCAQEAYO+7ahYDDhc4Pihstsewdcat/lixzHsV 54 | R2Rqv5c4EodsWqGykOqfMyiCLoiVAP1b9ztELdARD612Vd68cz6pFyIbz+i2b8Li 55 | 7hUNYAs4Q6GsOBv5SVqD6HSJdob07JxnLSl2XvfR49eylVISl8gzeOi6uqu/rO1O 56 | clCOk4TMNZ61EfnJogP74EecAEISi+cLbCIrAuO79h0Ex/Fbea83JNuG2VSNMOKK 57 | c9La4Cn0jcBrOfBLAcHbKWj2M1dZe9Zq631n3X0pyZCf0pe1lozrvCi6CDvAEjwu 58 | /ZXNwyua3gf3zn7g+MmO7BeKntkapcsYJMaAoNgDl/bZX0h0oQrBZA== 59 | -----END CERTIFICATE----- 60 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | # MongoDB Provider 3 | 4 | The MongoDB provider is used to interact with the resources supported by [MongoDB](https://www.mongodb.com/). The provider needs to be configured with the proper credentials before it can be used. 5 | 6 | Use the navigation to the left to read about the available provider resources. 7 | 8 | You may want to consider pinning the [provider version](https://www.terraform.io/docs/configuration/providers.html#provider-versions) to ensure you have a chance to review and prepare for changes. 9 | 10 | ## Example Usage 11 | 12 | ```hcl 13 | # Configure the MongoDB Provider 14 | provider "mongodb" { 15 | host = "127.0.0.1" 16 | port = "27017" 17 | username = "root" 18 | password = "root" 19 | auth_database = "admin" 20 | ssl = true 21 | replica_set = "replica-set" #optional 22 | retrywrites = false # default true 23 | direct = true // default false 24 | proxy = "socks5://myproxy:8080" // Optional 25 | 26 | } 27 | ``` 28 | 29 | ## Example Usage with ssl 30 | 31 | ```hcl 32 | # Configure the MongoDB Provider 33 | provider "mongodb" { 34 | 35 | insecure_skip_verify = true # default false (set to true to ignore hostname verification) 36 | # -> specify certificate path 37 | certificate = file(pathexpand("path/to/certificate/ca.pem")) 38 | 39 | 40 | } 41 | ``` 42 | 43 | ### Environment variables 44 | 45 | You can also provide your credentials via the environment variables, MONGO_HOST, MONGO_PORT, MONGO_USR, and MONGO_PWD respectively: 46 | 47 | ```hcl 48 | provider "mongodb" { 49 | auth_database = "admin" 50 | } 51 | ``` 52 | 53 | Usage (prefix the export commands with a space to avoid the keys being recorded in OS history): 54 | 55 | ```shell 56 | $ export MONGO_HOST="xxxx" 57 | $ export MONGO_PORT="xxxx" 58 | $ export MONGO_USR="xxxx" 59 | $ export MONGO_PWD="xxxx" 60 | $ terraform plan 61 | ``` 62 | 63 | 64 | 65 | 66 | ## Certificate information : 67 | Specify certificate information either with a directory or directly with the content of the files for connecting to the Mongodb host via TLS. 68 | 69 | ```hcl 70 | provider "mongodb" { 71 | host = "127.0.0.1" 72 | port = "27017" 73 | username = "root" 74 | password = "root" 75 | auth_database = "admin" 76 | ssl = true 77 | # -> specify either 78 | certificate = pathexpand("~/.mongodb/ca.pem") 79 | 80 | } 81 | ``` 82 | ## Argument Reference 83 | 84 | In addition to [generic `provider` 85 | arguments](https://www.terraform.io/docs/configuration/providers.html) (e.g. 86 | `alias` and `version`), the following arguments are supported in the MongoDB 87 | `provider` block: 88 | 89 | * `host` - (Optional) This is the host your MongoDB Server. It must be 90 | provided, but it can also be sourced from the `MONGO_HOST` 91 | environment variable. 92 | * `port` - (Optional) This is the port that your MongoDB Server uses. It must be 93 | provided, but it can also be sourced from the `MONGO_PORT` 94 | environment variable. 95 | 96 | * `certificate` - (Optional) Path to a directory with certificate files for connecting to the Docker host via TLS. I. If the path is blank, the MONGODB_CERT will also be checked. 97 | 98 | * `username ` - (Optional) Specifies a username with which to authenticate to the MongoDB database. It must be 99 | provided, but it can also be sourced from the `MONGO_USR` 100 | environment variable. 101 | * `password ` - (Optional) Specifies a password with which to authenticate to the MongoDB database. It must be 102 | provided, but it can also be sourced from the `MONGO_PWD` 103 | environment variable. 104 | * `auth_database ` - (Required) Specifies the authentication database where the specified `username` has been created. 105 | * `ssl ` - (Optional) `default = false `set it to true to connect to a deployment using TLS/SSL with SCRAM authentication. 106 | * `retrywrites ` - (Optional) `default = true `Retryable writes allow MongoDB drivers to automatically retry certain write operations a single time if they encounter network errors, or if they cannot find a healthy primary in the replica sets or sharded cluster. 107 | * `direct ` - (Optional) `default = false ` determine if a direct connection is needed.. 108 | * `proxy ` - (Optional) `default = "" ` determine if connecting via a SOCKS5 proxy is needed, it can also be sourced from the `ALL_PROXY` or `all_proxy` environment variable. 109 | 110 | -------------------------------------------------------------------------------- /docs/resources/database_role.md: -------------------------------------------------------------------------------- 1 | # mongodb_db_role 2 | 3 | `mongodb_db_role` provides a Custom DB Role resource. The customDBRoles resource lets you retrieve, create and modify the custom MongoDB roles in your mongo database server. Use custom MongoDB roles to specify custom sets of privileges. 4 | 5 | 6 | ## Example Usages 7 | 8 | ```hcl 9 | resource "mongodb_db_role" "example_role" { 10 | name = "role_name" 11 | database = "my_database" 12 | privilege { 13 | db = "admin" 14 | collection = "*" 15 | actions = ["collStats"] 16 | } 17 | privilege { 18 | db = "my_database" 19 | collection = "" 20 | actions = ["listCollections", "createCollection","createIndex", "dropIndex", "insert", "remove", "renameCollectionSameDB", "update"] 21 | } 22 | 23 | 24 | } 25 | ``` 26 | ## Example Usage with inherited roles 27 | 28 | ```hcl 29 | resource "mongodb_db_role" "role" { 30 | database = "admin" 31 | name = "new_role" 32 | privilege { 33 | db = "admin" 34 | collection = "" 35 | actions = ["collStats"] 36 | } 37 | } 38 | 39 | resource "mongodb_db_role" "role_2" { 40 | depends_on = [mongodb_db_role.role] 41 | database = "admin" 42 | name = "new_role3" 43 | 44 | inherited_role { 45 | role = mongodb_db_role.role.name 46 | db = "admin" 47 | } 48 | } 49 | ``` 50 | ## Argument Reference 51 | 52 | * `database` - (Optional) **default="admin"** The database of the role. 53 | 54 | ~> **IMPORTANT:** If a role is created in a specific database you can only use it as inherited in another role in the same database. 55 | 56 | * `name` - (Required) Name of the custom role. 57 | 58 | -> **NOTE:** The specified role name can only contain letters, digits, underscores, and dashes. Additionally, you cannot specify a role name which meets any of the following criteria: 59 | 60 | * Is a name already used by an existing custom role 61 | * Is a name of any of the built-in roles see [built-in-roles](https://docs.mongodb.com/manual/reference/built-in-roles/index.html) 62 | 63 | ### Privilege 64 | Each object in the privilege array represents an individual privilege action granted by the role. It is not required. 65 | 66 | * `actions` - (Required) Array of the privilege action. For a complete list of actions available , see [Custom Role Actions](https://docs.mongodb.com/manual/reference/privilege-actions/) 67 | -> **Note**: The privilege actions available to the Custom Roles API resource represent a subset of the privilege actions available in the Atlas Custom Roles UI. 68 | * `db` Database on which the action is granted. 69 | * `collection` - (Optional) Collection on which the action is granted. 70 | -> **Note**: If collection value is an empty string, the actions are granted on all collections within the database specified in the privilege.db field. 71 | 72 | ### Inherited Roles 73 | Each object in the inheritedRoles array represents a key-value pair indicating the inherited role and the database on which the role is granted. It is an optional field. 74 | 75 | * `db` (Required) Database on which the inherited role is granted. 76 | 77 | -> **NOTE** This value should be admin for all roles except read and readWrite. 78 | 79 | * `role` (Required) Name of the inherited role. This can either be another custom role or a [built-in role](https://docs.mongodb.com/manual/reference/built-in-roles/index.html). 80 | 81 | 82 | ## Import 83 | 84 | ## Import 85 | 86 | Mongodb users can be imported using the hex encoded id, e.g. for a user named `user_test` and his database id `test_db` : 87 | 88 | ```sh 89 | $ printf '%s' "test_db.role_test" | base64 90 | ## this is the output of the command above it will encode db.rolename to HEX 91 | dGVzdF9kYi5yb2xlX3Rlc3Q= 92 | 93 | $ terraform import mongodb_db_role.example_role dGVzdF9kYi5yb2xlX3Rlc3Q= 94 | ``` -------------------------------------------------------------------------------- /docs/resources/database_user.md: -------------------------------------------------------------------------------- 1 | # Mongo Database User 2 | 3 | Provides a Database User resource. 4 | 5 | Each user has a set of roles that provide access to the databases. 6 | 7 | ~> **IMPORTANT:** All arguments including the password will be stored in the raw state as plain-text. [Read more about sensitive data in state.](https://www.terraform.io/docs/state/sensitive-data.html) 8 | 9 | ## Example Usages 10 | 11 | ##### - create user with predefined role 12 | ```hcl 13 | 14 | resource "mongodb_db_user" "user" { 15 | auth_database = "my_database" 16 | name = "example" 17 | password = "example" 18 | role { 19 | role = "readAnyDatabase" 20 | db = "my_database" 21 | } 22 | 23 | } 24 | ``` 25 | 26 | ##### - create user with [custom role]() `example_role` 27 | ```hcl 28 | variable "username" { 29 | description = "the user name" 30 | } 31 | variable "password" { 32 | description = "the user password" 33 | } 34 | 35 | resource "mongodb_db_user" "user_with_custom role" { 36 | depends_on = [mongodb_db_role.example_role] 37 | auth_database = "my_database" 38 | name = var.username 39 | password = var.password 40 | role { 41 | role = mongodb_db_role.example_role.name 42 | db = "my_database" 43 | } 44 | role { 45 | role = "readAnyDatabase" 46 | db = "admin" 47 | } 48 | } 49 | ``` 50 | ## Argument Reference 51 | 52 | * `auth_database` - (Required) Database against which Mongo authenticates the user. A user must provide both a username and authentication database to log into MongoDB. 53 | * `role` - (optional) List of user’s roles and the databases / collections on which the roles apply. A role allows the user to perform particular actions on the specified database. A role on the admin database can include privileges that apply to the other databases as well. See [Role](#role) below for more details. 54 | 55 | * `name` - (Required) Username for authenticating to MongoDB. 56 | * `password` - (Required) User's initial password. A value is required to create the database user, however the argument but may be removed from your Terraform configuration after user creation without impacting the user, password or Terraform management. 57 | 58 | ~> **IMPORTANT:** --- Passwords may show up in Terraform related logs and it will be stored in the Terraform state file as plain-text. Password can be changed after creation using your preferred method, e.g. via the MongoDB Shell, to ensure security. If you do change management of the password to outside of Terraform be sure to remove the argument from the Terraform configuration so it is not inadvertently updated to the original password. 59 | 60 | ### Role 61 | 62 | Block mapping a user's role to a database / collection. A role allows the user to perform particular actions on the specified database. A role on the admin database can include privileges that apply to the other databases as well. 63 | 64 | -> **NOTE:** The available privilege actions for custom MongoDB roles support a subset of MongoDB commands. 65 | 66 | * `role` - (Required) Name of the role to grant. See [Create a Database User](https://docs.mongodb.com/manual/reference/method/db.createUser/#create-administrative-user-with-roles) `roles`. 67 | 68 | -> **NOTE:** you can also use [built-in-roles](https://docs.mongodb.com/manual/reference/built-in-roles/index.html) 69 | * `db` - (Required) Database on which the user has the specified role. A role on the `admin` database can include privileges that apply to the other databases. 70 | 71 | 72 | 73 | ## Import 74 | 75 | Mongodb users can be imported using the hex encoded id, e.g. for a user named `user_test` and his database id `test_db` : 76 | 77 | ```sh 78 | $ printf '%s' "test_db.user_test" | base64 79 | ## this is the output of the command above it will encode db.username to HEX 80 | dGVzdF9kYi51c2VyX3Rlc3Q= 81 | 82 | $ terraform import mongodb_db_user.example_user dGVzdF9kYi51c2VyX3Rlc3Q= 83 | ``` -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | TERRAFORM_PLUGINS_DIRECTORY=${HOME}/.terraform.d/plugins 2 | 3 | init: 4 | cd 5 | terraform init \ 6 | -plugin-dir=${TERRAFORM_PLUGINS_DIRECTORY} 7 | 8 | apply: 9 | terraform apply 10 | 11 | plan: 12 | terraform plan 13 | 14 | destroy: 15 | terraform destroy -------------------------------------------------------------------------------- /examples/documentDB/Makefile: -------------------------------------------------------------------------------- 1 | TERRAFORM_PLUGINS_DIRECTORY=${HOME}/.terraform.d/plugins 2 | 3 | init: 4 | cd 5 | terraform init \ 6 | -plugin-dir=${TERRAFORM_PLUGINS_DIRECTORY} 7 | 8 | apply: 9 | terraform apply 10 | 11 | plan: 12 | terraform plan 13 | 14 | destroy: 15 | terraform destroy -------------------------------------------------------------------------------- /examples/documentDB/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | 4 | required_providers { 5 | mongodb = { 6 | source = "registry.terraform.io/Kaginari/mongodb" 7 | version = "9.9.9" 8 | } 9 | } 10 | } 11 | provider "mongodb" { 12 | host = "documentdb-test-terraform.cluster-ro-ctclcdufsrkx.eu-west-3.docdb.amazonaws.com" 13 | port = "27017" 14 | username = "" 15 | password = "" 16 | ssl = true 17 | direct = true 18 | certificate = file(pathexpand("rds-combined-ca-bundle.pem")) 19 | } 20 | resource "mongodb_db_user" "user" { 21 | auth_database = "admin" 22 | name = "monta" 23 | password = "monta" 24 | role { 25 | role = "readAnyDatabase" 26 | db = "admin" 27 | } 28 | role { 29 | role = "readWrite" 30 | db = "local" 31 | } 32 | role { 33 | role = "readWrite" 34 | db = "monta" 35 | } 36 | 37 | 38 | } -------------------------------------------------------------------------------- /examples/documentDB/variables.tf: -------------------------------------------------------------------------------- 1 | variable "username" { 2 | description = "the user name" 3 | default = "monta_username" 4 | } 5 | variable "password" { 6 | description = "the user password" 7 | default = "monta_password" 8 | } -------------------------------------------------------------------------------- /examples/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | 4 | required_providers { 5 | mongodb = { 6 | source = "registry.terraform.io/Kaginari/mongodb" 7 | version = "9.9.9" 8 | } 9 | } 10 | } 11 | 12 | provider "mongodb" { 13 | host = "mongo" 14 | port = "27017" 15 | username = "root" 16 | password = "root" 17 | ssl = false 18 | auth_database = "admin" 19 | proxy = "socks5://localhost:1080" 20 | } 21 | 22 | variable "username" { 23 | description = "the user name" 24 | default = "monta" 25 | } 26 | variable "password" { 27 | description = "the user password" 28 | default = "monta" 29 | } 30 | 31 | resource "mongodb_db_role" "role" { 32 | name = "custom_role_test" 33 | privilege { 34 | db = "admin" 35 | collection = "*" 36 | actions = ["collStats"] 37 | } 38 | privilege { 39 | db = "ds" 40 | collection = "*" 41 | actions = ["collStats"] 42 | } 43 | 44 | 45 | } 46 | 47 | resource "mongodb_db_role" "role_2" { 48 | depends_on = [mongodb_db_role.role] 49 | database = "admin" 50 | name = "new_role3" 51 | inherited_role { 52 | role = mongodb_db_role.role.name 53 | db = "admin" 54 | } 55 | privilege { 56 | db = "not_inhireted" 57 | collection = "*" 58 | actions = ["collStats"] 59 | } 60 | } 61 | resource "mongodb_db_role" "role4" { 62 | depends_on = [mongodb_db_role.role] 63 | database = "exemple" 64 | name = "new_role4" 65 | } 66 | 67 | resource "mongodb_db_user" "user" { 68 | auth_database = "exemple" 69 | name = "monta" 70 | password = "monta" 71 | role { 72 | role = mongodb_db_role.role.name 73 | db = "admin" 74 | } 75 | role { 76 | role = "readAnyDatabase" 77 | db = "admin" 78 | } 79 | role { 80 | role = "readWrite" 81 | db = "local" 82 | } 83 | role { 84 | role = "readWrite" 85 | db = "monta" 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Kaginari/terraform-provider-mongodb 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.1.0 7 | github.com/mitchellh/mapstructure v1.1.2 8 | go.mongodb.org/mongo-driver v1.7.0 9 | golang.org/x/net v0.0.0-20200707034311-ab3426394381 10 | ) 11 | 12 | require ( 13 | github.com/agext/levenshtein v1.2.2 // indirect 14 | github.com/apparentlymart/go-textseg v1.0.0 // indirect 15 | github.com/go-stack/stack v1.8.0 // indirect 16 | github.com/golang/protobuf v1.4.2 // indirect 17 | github.com/golang/snappy v0.0.1 // indirect 18 | github.com/hashicorp/errwrap v1.0.0 // indirect 19 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect 20 | github.com/hashicorp/go-hclog v0.9.2 // indirect 21 | github.com/hashicorp/go-multierror v1.0.0 // indirect 22 | github.com/hashicorp/go-plugin v1.3.0 // indirect 23 | github.com/hashicorp/go-uuid v1.0.1 // indirect 24 | github.com/hashicorp/go-version v1.2.1 // indirect 25 | github.com/hashicorp/hcl/v2 v2.3.0 // indirect 26 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect 27 | github.com/klauspost/compress v1.9.5 // indirect 28 | github.com/mitchellh/copystructure v1.0.0 // indirect 29 | github.com/mitchellh/go-testing-interface v1.0.4 // indirect 30 | github.com/mitchellh/go-wordwrap v1.0.0 // indirect 31 | github.com/mitchellh/reflectwalk v1.0.1 // indirect 32 | github.com/oklog/run v1.0.0 // indirect 33 | github.com/pkg/errors v0.9.1 // indirect 34 | github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect 35 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 36 | github.com/xdg-go/scram v1.0.2 // indirect 37 | github.com/xdg-go/stringprep v1.0.2 // indirect 38 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 39 | github.com/zclconf/go-cty v1.2.1 // indirect 40 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect 41 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect 42 | golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect 43 | golang.org/x/text v0.3.5 // indirect 44 | google.golang.org/appengine v1.6.6 // indirect 45 | google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect 46 | google.golang.org/grpc v1.30.0 // indirect 47 | google.golang.org/protobuf v1.25.0 // indirect 48 | ) 49 | -------------------------------------------------------------------------------- /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/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= 15 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 16 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 17 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 18 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 19 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 20 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 21 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 22 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 23 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 24 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 25 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 26 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 27 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 28 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 29 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 30 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 31 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 32 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 33 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 34 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 35 | github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 36 | github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= 37 | github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 38 | github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= 39 | github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 40 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 41 | github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= 42 | github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 43 | github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= 44 | github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 45 | github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= 46 | github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= 47 | github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= 48 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 49 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 50 | github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= 51 | github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 52 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 53 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 54 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 55 | github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 56 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 57 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 58 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 59 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 60 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 61 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 62 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 63 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 64 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 65 | github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= 66 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 67 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 68 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 69 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 70 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 71 | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 72 | github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= 73 | github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= 74 | github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 75 | github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= 76 | github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= 77 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 78 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 79 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 80 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 81 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 82 | github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= 83 | github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 84 | github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= 85 | github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= 86 | github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= 87 | github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 88 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 89 | github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= 90 | github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= 91 | github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= 92 | github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= 93 | github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= 94 | github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= 95 | github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= 96 | github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= 97 | github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= 98 | github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= 99 | github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= 100 | github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= 101 | github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= 102 | github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= 103 | github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= 104 | github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= 105 | github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= 106 | github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= 107 | github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= 108 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 109 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 110 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 111 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 112 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 113 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 114 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 115 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 116 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 117 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 118 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 119 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 120 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 121 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 122 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 123 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 124 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 125 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 126 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 127 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 128 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 129 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 130 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 131 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 132 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 133 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 134 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 135 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 136 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 137 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 138 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 139 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 140 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 141 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 142 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 143 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 144 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 145 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 146 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 147 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 148 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 149 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 150 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 151 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 152 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 153 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 154 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 155 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 156 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 157 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 158 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 159 | github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= 160 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 161 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 162 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= 163 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= 164 | github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= 165 | github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= 166 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 167 | github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= 168 | github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 169 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 170 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 171 | github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= 172 | github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= 173 | github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= 174 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 175 | github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= 176 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 177 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 178 | github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= 179 | github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 180 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 181 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 182 | github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= 183 | github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= 184 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 185 | github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= 186 | github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= 187 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.1.0 h1:Z5K9y5UGVQO7gvLFk6NMA/v1JZW/HLzJ/TTSoLkqQyY= 188 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.1.0/go.mod h1:GP0lmw4Y+XV1OfTmi/hK75t5KWGGzoOzEgUBPGZ6Wq4= 189 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 190 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= 191 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 192 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 193 | github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 194 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 195 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 196 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 197 | github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= 198 | github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= 199 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 200 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 201 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 202 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 203 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 204 | github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= 205 | github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 206 | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 207 | github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= 208 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 209 | github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= 210 | github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 211 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 212 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 213 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 214 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 215 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 216 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 217 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 218 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 219 | github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= 220 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 221 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 222 | github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= 223 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= 224 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 225 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 226 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 227 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 228 | github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 229 | github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= 230 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 231 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 232 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 233 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 234 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 235 | github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= 236 | github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 237 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 238 | github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= 239 | github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 240 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 241 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 242 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 243 | github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= 244 | github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 245 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= 246 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 247 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 248 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= 249 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 250 | github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= 251 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 252 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 253 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 254 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 255 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 256 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 257 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 258 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 259 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 260 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 261 | github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 262 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 263 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 264 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 265 | github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 266 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 267 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 268 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 269 | github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 270 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 271 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 272 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 273 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 274 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 275 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 276 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 277 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 278 | github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= 279 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 280 | github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 281 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 282 | github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 283 | github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= 284 | github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 285 | github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= 286 | github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= 287 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= 288 | github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= 289 | github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= 290 | github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= 291 | github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= 292 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= 293 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= 294 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 295 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 296 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 297 | github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 298 | github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= 299 | github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 300 | go.mongodb.org/mongo-driver v1.7.0 h1:hHrvOBWlWB2c7+8Gh/Xi5jj82AgidK/t7KVXBZ+IyUA= 301 | go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= 302 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 303 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 304 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 305 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 306 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 307 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 308 | golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 309 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 310 | golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 311 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 312 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 313 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 314 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 315 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 316 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 317 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 318 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 319 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 320 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 321 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 322 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 323 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 324 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 325 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 326 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 327 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 328 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 329 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 330 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 331 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 332 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 333 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 334 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 335 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 336 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 337 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 338 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 339 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 340 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 341 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 342 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 343 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 344 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 345 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 346 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 347 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 348 | golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 349 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 350 | golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 351 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 352 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 353 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 354 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 355 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 356 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 357 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 358 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 359 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 360 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 361 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 362 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 363 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 364 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 365 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 366 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 367 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 368 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 369 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 370 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 371 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 372 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 373 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 374 | golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= 375 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 376 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 377 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 378 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 379 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 380 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 381 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 382 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 383 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 384 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 385 | golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 386 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 387 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 388 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 389 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= 390 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 391 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 392 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 393 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 394 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 395 | golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 396 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 397 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 398 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 399 | golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 400 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 401 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 402 | golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 403 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 404 | golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 405 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 406 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 407 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 408 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 409 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 410 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 411 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 412 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 413 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 414 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 415 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 416 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 417 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 418 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 419 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 420 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 421 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 422 | golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= 423 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 424 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 425 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 426 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 427 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 428 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 429 | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= 430 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 431 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 432 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 433 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 434 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 435 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 436 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 437 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 438 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 439 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 440 | golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 441 | golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 442 | golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 443 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 444 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 445 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 446 | golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 447 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 448 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 449 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 450 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 451 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 452 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 453 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 454 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 455 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 456 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 457 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 458 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 459 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 460 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 461 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 462 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 463 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 464 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 465 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 466 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 467 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 468 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 469 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 470 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 471 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 472 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 473 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 474 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 475 | golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 476 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 477 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 478 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 479 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 480 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 481 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 482 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 483 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 484 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 485 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 486 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 487 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 488 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 489 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 490 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 491 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 492 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 493 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 494 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 495 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 496 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 497 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 498 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 499 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 500 | google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= 501 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 502 | google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 503 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 504 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 505 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 506 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 507 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 508 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 509 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 510 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 511 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 512 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 513 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 514 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 515 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 516 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 517 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 518 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 519 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 520 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 521 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 522 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 523 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 524 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 525 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 526 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 527 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 528 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 529 | google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxtiIncJxFXeCyq84ixuKWVCaCAi9Oc= 530 | google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 531 | google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 532 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 533 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 534 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 535 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 536 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 537 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 538 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 539 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 540 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 541 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 542 | google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= 543 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 544 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 545 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 546 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 547 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 548 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 549 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 550 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 551 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 552 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 553 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 554 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 555 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 556 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 557 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 558 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 559 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 560 | gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 561 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 562 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 563 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 564 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 565 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 566 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 567 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 568 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 569 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 570 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 571 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 572 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 573 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 574 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 575 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 576 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 577 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 578 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Kaginari/terraform-provider-mongodb/mongodb" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 6 | ) 7 | 8 | func main() { 9 | plugin.Serve(&plugin.ServeOpts{ 10 | ProviderFunc: mongodb.Provider, 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /mmo.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /mongodb/config.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "crypto/x509" 7 | "errors" 8 | "fmt" 9 | "go.mongodb.org/mongo-driver/bson" 10 | "go.mongodb.org/mongo-driver/mongo" 11 | "go.mongodb.org/mongo-driver/mongo/options" 12 | "golang.org/x/net/proxy" 13 | "net/url" 14 | "strconv" 15 | "time" 16 | ) 17 | 18 | type ClientConfig struct { 19 | Host string 20 | Port string 21 | Username string 22 | Password string 23 | DB string 24 | Ssl bool 25 | InsecureSkipVerify bool 26 | ReplicaSet string 27 | RetryWrites bool 28 | Certificate string 29 | Direct bool 30 | Proxy string 31 | } 32 | type DbUser struct { 33 | Name string `json:"name"` 34 | Password string `json:"password"` 35 | } 36 | 37 | type Role struct { 38 | Role string `json:"role"` 39 | Db string `json:"db"` 40 | } 41 | 42 | func (role Role) String() string { 43 | return fmt.Sprintf("{ role : %s , db : %s }", role.Role, role.Db) 44 | } 45 | 46 | type PrivilegeDto struct { 47 | Db string `json:"db"` 48 | Collection string `json:"collection"` 49 | Actions []string `json:"actions"` 50 | } 51 | 52 | type Privilege struct { 53 | Resource Resource `json:"resource"` 54 | Actions []string `json:"actions"` 55 | } 56 | type SingleResultGetUser struct { 57 | Users []struct { 58 | Id string `json:"_id"` 59 | User string `json:"user"` 60 | Db string `json:"db"` 61 | Roles []struct { 62 | Role string `json:"role"` 63 | Db string `json:"db"` 64 | } `json:"roles"` 65 | } `json:"users"` 66 | } 67 | type SingleResultGetRole struct { 68 | Roles []struct { 69 | Role string `json:"role"` 70 | Db string `json:"db"` 71 | InheritedRoles []struct { 72 | Role string `json:"role"` 73 | Db string `json:"db"` 74 | } `json:"inheritedRoles"` 75 | Privileges []struct { 76 | Resource struct { 77 | Db string `json:"db"` 78 | Collection string `json:"collection"` 79 | } `json:"resource"` 80 | Actions []string `json:"actions"` 81 | } `json:"privileges"` 82 | } `json:"roles"` 83 | } 84 | 85 | func addArgs(arguments string, newArg string) string { 86 | if arguments != "" { 87 | return arguments + "&" + newArg 88 | } else { 89 | return "/?" + newArg 90 | } 91 | 92 | } 93 | 94 | func (c *ClientConfig) MongoClient() (*mongo.Client, error) { 95 | 96 | var verify = false 97 | var arguments = "" 98 | 99 | arguments = addArgs(arguments, "retrywrites="+strconv.FormatBool(c.RetryWrites)) 100 | 101 | if c.Ssl { 102 | arguments = addArgs(arguments, "ssl=true") 103 | } 104 | 105 | if c.ReplicaSet != "" && c.Direct == false { 106 | arguments = addArgs(arguments, "replicaSet="+c.ReplicaSet) 107 | } 108 | 109 | if c.Direct { 110 | arguments = addArgs(arguments, "connect="+"direct") 111 | } 112 | 113 | var uri = "mongodb://" + c.Host + ":" + c.Port + arguments 114 | 115 | dialer, dialerErr := proxyDialer(c) 116 | 117 | if dialerErr != nil { 118 | return nil, dialerErr 119 | } 120 | /* 121 | @Since: v0.0.9 122 | verify certificate 123 | */ 124 | if c.InsecureSkipVerify { 125 | verify = true 126 | } 127 | /* 128 | @Since: v0.0.7 129 | add certificate support for documentDB 130 | */ 131 | if c.Certificate != "" { 132 | tlsConfig, err := getTLSConfigWithAllServerCertificates([]byte(c.Certificate), verify) 133 | if err != nil { 134 | return nil, err 135 | } 136 | mongoClient, err := mongo.NewClient(options.Client().ApplyURI(uri).SetAuth(options.Credential{ 137 | AuthSource: c.DB, Username: c.Username, Password: c.Password, 138 | }).SetTLSConfig(tlsConfig).SetDialer(dialer)) 139 | 140 | return mongoClient, err 141 | } 142 | 143 | client, err := mongo.NewClient(options.Client().ApplyURI(uri).SetAuth(options.Credential{ 144 | AuthSource: c.DB, Username: c.Username, Password: c.Password, 145 | }).SetDialer(dialer)) 146 | return client, err 147 | } 148 | 149 | func getTLSConfigWithAllServerCertificates(ca []byte, verify bool) (*tls.Config, error) { 150 | /* As of version 1.2.1, the MongoDB Go Driver will only use the first CA server certificate found in sslcertificateauthorityfile. 151 | The code below addresses this limitation by manually appending all server certificates found in sslcertificateauthorityfile 152 | to a custom TLS configuration used during client creation. */ 153 | 154 | tlsConfig := new(tls.Config) 155 | 156 | tlsConfig.InsecureSkipVerify = verify 157 | tlsConfig.RootCAs = x509.NewCertPool() 158 | ok := tlsConfig.RootCAs.AppendCertsFromPEM(ca) 159 | 160 | if !ok { 161 | return tlsConfig, errors.New("Failed parsing pem file") 162 | } 163 | 164 | return tlsConfig, nil 165 | } 166 | 167 | func (privilege Privilege) String() string { 168 | return fmt.Sprintf("{ resource : %s , actions : %s }", privilege.Resource, privilege.Actions) 169 | } 170 | 171 | type Resource struct { 172 | Db string `json:"db"` 173 | Collection string `json:"collection"` 174 | } 175 | 176 | func (resource Resource) String() string { 177 | return fmt.Sprintf(" { db : %s , collection : %s }", resource.Db, resource.Collection) 178 | } 179 | 180 | func createUser(client *mongo.Client, user DbUser, roles []Role, database string) error { 181 | var result *mongo.SingleResult 182 | if len(roles) != 0 { 183 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createUser", Value: user.Name}, 184 | {Key: "pwd", Value: user.Password}, {Key: "roles", Value: roles}}) 185 | } else { 186 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createUser", Value: user.Name}, 187 | {Key: "pwd", Value: user.Password}, {Key: "roles", Value: []bson.M{}}}) 188 | } 189 | 190 | if result.Err() != nil { 191 | return result.Err() 192 | } 193 | return nil 194 | } 195 | 196 | func getUser(client *mongo.Client, username string, database string) (SingleResultGetUser, error) { 197 | var result *mongo.SingleResult 198 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "usersInfo", Value: bson.D{ 199 | {Key: "user", Value: username}, 200 | {Key: "db", Value: database}, 201 | }, 202 | }}) 203 | var decodedResult SingleResultGetUser 204 | err := result.Decode(&decodedResult) 205 | if err != nil { 206 | return decodedResult, err 207 | } 208 | return decodedResult, nil 209 | } 210 | 211 | func getRole(client *mongo.Client, roleName string, database string) (SingleResultGetRole, error) { 212 | var result *mongo.SingleResult 213 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "rolesInfo", Value: bson.D{ 214 | {Key: "role", Value: roleName}, 215 | {Key: "db", Value: database}, 216 | }, 217 | }, 218 | {Key: "showPrivileges", Value: true}, 219 | }) 220 | var decodedResult SingleResultGetRole 221 | err := result.Decode(&decodedResult) 222 | if err != nil { 223 | return decodedResult, err 224 | } 225 | return decodedResult, nil 226 | } 227 | 228 | func createRole(client *mongo.Client, role string, roles []Role, privilege []PrivilegeDto, database string) error { 229 | var privileges []Privilege 230 | var result *mongo.SingleResult 231 | for _, element := range privilege { 232 | var prv Privilege 233 | prv.Resource = Resource{ 234 | Db: element.Db, 235 | Collection: element.Collection, 236 | } 237 | prv.Actions = element.Actions 238 | privileges = append(privileges, prv) 239 | } 240 | if len(roles) != 0 && len(privileges) != 0 { 241 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createRole", Value: role}, 242 | {Key: "privileges", Value: privileges}, {Key: "roles", Value: roles}}) 243 | } else if len(roles) == 0 && len(privileges) != 0 { 244 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createRole", Value: role}, 245 | {Key: "privileges", Value: privileges}, {Key: "roles", Value: []bson.M{}}}) 246 | } else if len(roles) != 0 && len(privileges) == 0 { 247 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createRole", Value: role}, 248 | {Key: "privileges", Value: []bson.M{}}, {Key: "roles", Value: roles}}) 249 | } else { 250 | result = client.Database(database).RunCommand(context.Background(), bson.D{{Key: "createRole", Value: role}, 251 | {Key: "privileges", Value: []bson.M{}}, {Key: "roles", Value: []bson.M{}}}) 252 | } 253 | 254 | if result.Err() != nil { 255 | return result.Err() 256 | } 257 | return nil 258 | } 259 | 260 | func MongoClientInit(conf *MongoDatabaseConfiguration) (*mongo.Client, error) { 261 | 262 | client, err := conf.Config.MongoClient() 263 | if err != nil { 264 | return nil, err 265 | } 266 | ctx, cancel := context.WithTimeout(context.Background(), conf.MaxConnLifetime*time.Second) 267 | defer cancel() 268 | err = client.Connect(ctx) 269 | if err != nil { 270 | return nil, err 271 | } 272 | err = client.Ping(ctx, nil) 273 | if err != nil { 274 | return nil, err 275 | } 276 | return client, nil 277 | } 278 | 279 | func proxyDialer(c *ClientConfig) (options.ContextDialer, error) { 280 | proxyFromEnv := proxy.FromEnvironment().(options.ContextDialer) 281 | proxyFromProvider := c.Proxy 282 | 283 | if len(proxyFromProvider) > 0 { 284 | proxyURL, err := url.Parse(proxyFromProvider) 285 | if err != nil { 286 | return nil, err 287 | } 288 | proxyDialer, err := proxy.FromURL(proxyURL, proxy.Direct) 289 | if err != nil { 290 | return nil, err 291 | } 292 | 293 | return proxyDialer.(options.ContextDialer), nil 294 | } 295 | 296 | return proxyFromEnv, nil 297 | } 298 | -------------------------------------------------------------------------------- /mongodb/helpers.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/go-cty/cty" 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | ) 9 | 10 | func validateDiagFunc(validateFunc func(interface{}, string) ([]string, []error)) schema.SchemaValidateDiagFunc { 11 | return func(i interface{}, path cty.Path) diag.Diagnostics { 12 | warnings, errs := validateFunc(i, fmt.Sprintf("%+v", path)) 13 | var diags diag.Diagnostics 14 | for _, warning := range warnings { 15 | diags = append(diags, diag.Diagnostic{ 16 | Severity: diag.Warning, 17 | Summary: warning, 18 | }) 19 | } 20 | for _, err := range errs { 21 | diags = append(diags, diag.Diagnostic{ 22 | Severity: diag.Error, 23 | Summary: err.Error(), 24 | }) 25 | } 26 | return diags 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /mongodb/provider.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 8 | "regexp" 9 | "time" 10 | ) 11 | 12 | func Provider() *schema.Provider { 13 | return &schema.Provider{ 14 | Schema: map[string]*schema.Schema{ 15 | "host": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | DefaultFunc: schema.EnvDefaultFunc("MONGO_HOST", "127.0.0.1"), 19 | Description: "The mongodb server address", 20 | }, 21 | "port": { 22 | Type: schema.TypeString, 23 | Required: true, 24 | DefaultFunc: schema.EnvDefaultFunc("MONGO_PORT", "27017"), 25 | Description: "The mongodb server port", 26 | }, 27 | "certificate": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | DefaultFunc: schema.EnvDefaultFunc("MONGODB_CERT", ""), 31 | Description: "PEM-encoded content of Mongodb host CA certificate", 32 | }, 33 | 34 | "username": { 35 | Type: schema.TypeString, 36 | Required: true, 37 | DefaultFunc: schema.EnvDefaultFunc("MONGO_USR", nil), 38 | Description: "The mongodb user", 39 | }, 40 | "password": { 41 | Type: schema.TypeString, 42 | Required: true, 43 | DefaultFunc: schema.EnvDefaultFunc("MONGO_PWD", nil), 44 | Description: "The mongodb password", 45 | }, 46 | "auth_database": { 47 | Type: schema.TypeString, 48 | Optional: true, 49 | Default: "admin", 50 | Description: "The mongodb auth database", 51 | }, 52 | "replica_set": { 53 | Type: schema.TypeString, 54 | Optional: true, 55 | Default: "", 56 | Description: "The mongodb replica set", 57 | }, 58 | "insecure_skip_verify": { 59 | Type: schema.TypeBool, 60 | Optional: true, 61 | Default: false, 62 | Description: "ignore hostname verification", 63 | }, 64 | "ssl": { 65 | Type: schema.TypeBool, 66 | Optional: true, 67 | Default: false, 68 | Description: "ssl activation", 69 | }, 70 | "direct": { 71 | Type: schema.TypeBool, 72 | Optional: true, 73 | Default: false, 74 | Description: "enforces a direct connection instead of discovery", 75 | }, 76 | "retrywrites": { 77 | Type: schema.TypeBool, 78 | Optional: true, 79 | Default: true, 80 | Description: "Retryable Writes", 81 | }, 82 | "proxy": { 83 | Type: schema.TypeString, 84 | Optional: true, 85 | DefaultFunc: schema.MultiEnvDefaultFunc([]string{ 86 | "ALL_PROXY", 87 | "all_proxy", 88 | }, nil), 89 | ValidateDiagFunc: validateDiagFunc(validation.StringMatch(regexp.MustCompile("^socks5h?://.*:\\d+$"), "The proxy URL is not a valid socks url.")), 90 | }, 91 | }, 92 | ResourcesMap: map[string]*schema.Resource{ 93 | "mongodb_db_user": resourceDatabaseUser(), 94 | "mongodb_db_role": resourceDatabaseRole(), 95 | }, 96 | DataSourcesMap: map[string]*schema.Resource{}, 97 | ConfigureContextFunc: providerConfigure, 98 | } 99 | } 100 | 101 | type MongoDatabaseConfiguration struct { 102 | Config *ClientConfig 103 | MaxConnLifetime time.Duration 104 | } 105 | 106 | func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { 107 | var diags diag.Diagnostics 108 | 109 | clientConfig := ClientConfig{ 110 | Host: d.Get("host").(string), 111 | Port: d.Get("port").(string), 112 | Username: d.Get("username").(string), 113 | Password: d.Get("password").(string), 114 | DB: d.Get("auth_database").(string), 115 | Ssl: d.Get("ssl").(bool), 116 | ReplicaSet: d.Get("replica_set").(string), 117 | Certificate: d.Get("certificate").(string), 118 | InsecureSkipVerify: d.Get("insecure_skip_verify").(bool), 119 | Direct: d.Get("direct").(bool), 120 | RetryWrites: d.Get("retrywrites").(bool), 121 | Proxy: d.Get("proxy").(string), 122 | } 123 | 124 | return &MongoDatabaseConfiguration{ 125 | Config: &clientConfig, 126 | MaxConnLifetime: 10, 127 | }, diags 128 | 129 | } 130 | -------------------------------------------------------------------------------- /mongodb/resource_db_role.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "fmt" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/mitchellh/mapstructure" 10 | "go.mongodb.org/mongo-driver/bson" 11 | "strings" 12 | ) 13 | 14 | func resourceDatabaseRole() *schema.Resource { 15 | return &schema.Resource{ 16 | CreateContext: resourceDatabaseRoleCreate, 17 | ReadContext: resourceDatabaseRoleRead, 18 | UpdateContext: resourceDatabaseRoleUpdate, 19 | DeleteContext: resourceDatabaseRoleDelete, 20 | Importer: &schema.ResourceImporter{ 21 | StateContext: schema.ImportStatePassthroughContext, 22 | }, 23 | Schema: map[string]*schema.Schema{ 24 | "database": { 25 | Type: schema.TypeString, 26 | Optional: true, 27 | Default: "admin", 28 | }, 29 | "name": { 30 | Type: schema.TypeString, 31 | Required: true, 32 | }, 33 | "privilege": { 34 | Type: schema.TypeSet, 35 | Optional: true, 36 | MaxItems: 10, 37 | Elem: &schema.Resource{ 38 | Schema: map[string]*schema.Schema{ 39 | 40 | "db": { 41 | Type: schema.TypeString, 42 | Optional: true, 43 | }, 44 | "collection": { 45 | Type: schema.TypeString, 46 | Optional: true, 47 | }, 48 | 49 | "actions": { 50 | Type: schema.TypeList, 51 | Optional: true, 52 | Elem: &schema.Schema{ 53 | Type: schema.TypeString, 54 | }, 55 | }, 56 | }, 57 | }, 58 | }, 59 | "inherited_role": { 60 | Type: schema.TypeSet, 61 | Optional: true, 62 | MaxItems: 2, 63 | Elem: &schema.Resource{ 64 | Schema: map[string]*schema.Schema{ 65 | "db": { 66 | Type: schema.TypeString, 67 | Optional: true, 68 | }, 69 | "role": { 70 | Type: schema.TypeString, 71 | Required: true, 72 | }, 73 | }, 74 | }, 75 | }, 76 | }, 77 | } 78 | } 79 | 80 | func resourceDatabaseRoleCreate(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 81 | var config = i.(*MongoDatabaseConfiguration) 82 | client , connectionError := MongoClientInit(config) 83 | if connectionError != nil { 84 | return diag.Errorf("Error connecting to database : %s ", connectionError) 85 | } 86 | var role = data.Get("name").(string) 87 | var database = data.Get("database").(string) 88 | var roleList []Role 89 | var privileges []PrivilegeDto 90 | 91 | privilege := data.Get("privilege").(*schema.Set).List() 92 | roles := data.Get("inherited_role").(*schema.Set).List() 93 | 94 | roleMapErr := mapstructure.Decode(roles, &roleList) 95 | if roleMapErr != nil { 96 | return diag.Errorf("Error decoding map : %s ", roleMapErr) 97 | } 98 | privMapErr := mapstructure.Decode(privilege, &privileges) 99 | if privMapErr != nil { 100 | return diag.Errorf("Error decoding map : %s ", privMapErr) 101 | } 102 | 103 | 104 | err := createRole(client, role, roleList, privileges, database) 105 | 106 | if err != nil { 107 | return diag.Errorf("Could not create the role : %s ", err) 108 | } 109 | str := database+"."+role 110 | encoded := base64.StdEncoding.EncodeToString([]byte(str)) 111 | data.SetId(encoded) 112 | return resourceDatabaseRoleRead(ctx, data, i) 113 | } 114 | 115 | func resourceDatabaseRoleDelete(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 116 | var config = i.(*MongoDatabaseConfiguration) 117 | client , connectionError := MongoClientInit(config) 118 | if connectionError != nil { 119 | return diag.Errorf("Error connecting to database : %s ", connectionError) 120 | } 121 | var stateId = data.State().ID 122 | roleName, database , err := resourceDatabaseRoleParseId(stateId) 123 | 124 | if err != nil { 125 | return diag.Errorf("%s", err) 126 | } 127 | 128 | db := client.Database(database) 129 | result := db.RunCommand(context.Background(), bson.D{{Key: "dropRole", Value: roleName}}) 130 | 131 | if result.Err() != nil { 132 | return diag.Errorf("%s",result.Err()) 133 | } 134 | 135 | return nil 136 | } 137 | 138 | func resourceDatabaseRoleUpdate(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 139 | var config = i.(*MongoDatabaseConfiguration) 140 | client , connectionError := MongoClientInit(config) 141 | if connectionError != nil { 142 | return diag.Errorf("Error connecting to database : %s ", connectionError) 143 | } 144 | var role = data.Get("name").(string) 145 | var stateId = data.State().ID 146 | roleName, database , err := resourceDatabaseRoleParseId(stateId) 147 | 148 | if err != nil { 149 | return diag.Errorf("%s",err) 150 | } 151 | 152 | db := client.Database(database) 153 | result := db.RunCommand(context.Background(), bson.D{{Key: "dropRole", Value: roleName}}) 154 | 155 | if result.Err() != nil { 156 | return diag.Errorf("%s", result.Err()) 157 | } 158 | 159 | var roleList []Role 160 | var privileges []PrivilegeDto 161 | 162 | privilege := data.Get("privilege").(*schema.Set).List() 163 | roles := data.Get("inherited_role").(*schema.Set).List() 164 | 165 | roleMapErr := mapstructure.Decode(roles, &roleList) 166 | if roleMapErr != nil { 167 | return diag.Errorf("Error decoding map : %s ", roleMapErr) 168 | } 169 | privMapErr := mapstructure.Decode(privilege, &privileges) 170 | if privMapErr != nil { 171 | return diag.Errorf("Error decoding map : %s ", privMapErr) 172 | } 173 | 174 | err2 := createRole(client, role, roleList, privileges, database) 175 | 176 | if err2 != nil { 177 | return diag.Errorf("Could not create the role : %s ", err) 178 | } 179 | str := database+"."+role 180 | encoded := base64.StdEncoding.EncodeToString([]byte(str)) 181 | data.SetId(encoded) 182 | 183 | 184 | return resourceDatabaseRoleRead(ctx, data, i) 185 | } 186 | 187 | func resourceDatabaseRoleRead(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 188 | var diags diag.Diagnostics 189 | var config = i.(*MongoDatabaseConfiguration) 190 | client , connectionError := MongoClientInit(config) 191 | if connectionError != nil { 192 | return diag.Errorf("Error connecting to database : %s ", connectionError) 193 | } 194 | stateID := data.State().ID 195 | roleName, database , err := resourceDatabaseRoleParseId(stateID) 196 | if err != nil { 197 | return diag.Errorf("%s",err) 198 | } 199 | result , decodeError := getRole(client,roleName,database) 200 | if decodeError != nil { 201 | return diag.Errorf("Error decoding role : %s ", err) 202 | } 203 | if len(result.Roles) == 0 { 204 | return diag.Errorf("Role does not exist") 205 | } 206 | inheritedRoles := make([]interface{}, len(result.Roles[0].InheritedRoles)) 207 | 208 | for i, s := range result.Roles[0].InheritedRoles { 209 | inheritedRoles[i] = map[string]interface{}{ 210 | "db": s.Db, 211 | "role": s.Role, 212 | } 213 | } 214 | dataSetError := data.Set("inherited_role", inheritedRoles) 215 | if dataSetError != nil { 216 | return diag.Errorf("Error setting inherited roles : %s ", err) 217 | } 218 | privileges := make([]interface{}, len(result.Roles[0].Privileges)) 219 | 220 | for i, s := range result.Roles[0].Privileges { 221 | privileges[i] = map[string]interface{}{ 222 | "db": s.Resource.Db, 223 | "collection": s.Resource.Collection, 224 | "actions": s.Actions, 225 | } 226 | } 227 | dataSetError = data.Set("privilege", privileges) 228 | if dataSetError != nil { 229 | return diag.Errorf("Error setting role privilege : %s ", err) 230 | } 231 | dataSetError = data.Set("database", database) 232 | if dataSetError != nil { 233 | return diag.Errorf("Error setting role database : %s ", err) 234 | } 235 | dataSetError = data.Set("name", roleName) 236 | if dataSetError != nil { 237 | return diag.Errorf("Error setting role nam: %s ", err) 238 | } 239 | 240 | data.SetId(stateID) 241 | diags = nil 242 | return diags 243 | } 244 | 245 | func resourceDatabaseRoleParseId(id string) (string, string, error) { 246 | result , errEncoding := base64.StdEncoding.DecodeString(id) 247 | 248 | if errEncoding != nil { 249 | return "", "", fmt.Errorf("unexpected format of ID Error : %s", errEncoding) 250 | } 251 | parts := strings.SplitN(string(result), ".", 2) 252 | if len(parts) != 2 || parts[0] == "" || parts[1] == "" { 253 | return "", "", fmt.Errorf("unexpected format of ID (%s), expected database.roleName", id) 254 | } 255 | 256 | database := parts[0] 257 | roleName := parts[1] 258 | 259 | return roleName , database , nil 260 | } 261 | 262 | -------------------------------------------------------------------------------- /mongodb/resource_db_user.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "fmt" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/mitchellh/mapstructure" 10 | "go.mongodb.org/mongo-driver/bson" 11 | "strings" 12 | ) 13 | 14 | func resourceDatabaseUser() *schema.Resource { 15 | return &schema.Resource{ 16 | CreateContext: resourceDatabaseUserCreate, 17 | ReadContext: resourceDatabaseUserRead, 18 | UpdateContext: resourceDatabaseUserUpdate, 19 | DeleteContext: resourceDatabaseUserDelete, 20 | Importer: &schema.ResourceImporter{ 21 | StateContext: schema.ImportStatePassthroughContext, 22 | }, 23 | Schema: map[string]*schema.Schema{ 24 | "auth_database": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | }, 28 | "name":{ 29 | Type: schema.TypeString, 30 | Required: true, 31 | }, 32 | "password":{ 33 | Type: schema.TypeString, 34 | Required: true, 35 | }, 36 | "role": { 37 | Type: schema.TypeSet, 38 | Optional: true, 39 | MaxItems: 25, 40 | Elem: &schema.Resource{ 41 | Schema: map[string]*schema.Schema{ 42 | "db": { 43 | Type: schema.TypeString, 44 | Optional: true, 45 | }, 46 | "role": { 47 | Type: schema.TypeString, 48 | Required: true, 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | } 55 | } 56 | 57 | 58 | 59 | func resourceDatabaseUserDelete(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 60 | var config = i.(*MongoDatabaseConfiguration) 61 | client , connectionError := MongoClientInit(config) 62 | if connectionError != nil { 63 | return diag.Errorf("Error connecting to database : %s ", connectionError) 64 | } 65 | var stateId = data.State().ID 66 | var database = data.Get("auth_database").(string) 67 | 68 | id, errEncoding := base64.StdEncoding.DecodeString(stateId) 69 | if errEncoding != nil { 70 | return diag.Errorf("ID mismatch %s", errEncoding) 71 | } 72 | 73 | // StateID is a concatenation of database and username. We only use the username here. 74 | splitId := strings.Split(string(id), ".") 75 | userName := splitId[1] 76 | 77 | adminDB := client.Database(database) 78 | 79 | result := adminDB.RunCommand(context.Background(), bson.D{{Key: "dropUser", Value: userName}}) 80 | if result.Err() != nil { 81 | return diag.Errorf("%s",result.Err()) 82 | } 83 | 84 | return nil 85 | } 86 | 87 | func resourceDatabaseUserUpdate(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 88 | var config = i.(*MongoDatabaseConfiguration) 89 | client , connectionError := MongoClientInit(config) 90 | if connectionError != nil { 91 | return diag.Errorf("Error connecting to database : %s ", connectionError) 92 | } 93 | var stateId = data.State().ID 94 | _, errEncoding := base64.StdEncoding.DecodeString(stateId) 95 | if errEncoding != nil { 96 | return diag.Errorf("ID mismatch %s", errEncoding) 97 | } 98 | 99 | var userName = data.Get("name").(string) 100 | var database = data.Get("auth_database").(string) 101 | var userPassword = data.Get("password").(string) 102 | 103 | adminDB := client.Database(database) 104 | 105 | result := adminDB.RunCommand(context.Background(), bson.D{{Key: "dropUser", Value: userName}}) 106 | if result.Err() != nil { 107 | return diag.Errorf("%s",result.Err()) 108 | } 109 | var roleList []Role 110 | var user = DbUser{ 111 | Name: userName, 112 | Password: userPassword, 113 | } 114 | roles := data.Get("role").(*schema.Set).List() 115 | roleMapErr := mapstructure.Decode(roles, &roleList) 116 | if roleMapErr != nil { 117 | return diag.Errorf("Error decoding map : %s ", roleMapErr) 118 | } 119 | err2 := createUser(client,user,roleList,database) 120 | if err2 != nil { 121 | return diag.Errorf("Could not create the user : %s ", err2) 122 | } 123 | 124 | newId := database+"."+userName 125 | encoded := base64.StdEncoding.EncodeToString([]byte(newId)) 126 | data.SetId(encoded) 127 | return resourceDatabaseUserRead(ctx, data, i) 128 | } 129 | 130 | func resourceDatabaseUserRead(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 131 | var config = i.(*MongoDatabaseConfiguration) 132 | client , connectionError := MongoClientInit(config) 133 | if connectionError != nil { 134 | return diag.Errorf("Error connecting to database : %s ", connectionError) 135 | } 136 | stateID := data.State().ID 137 | username, database , err := resourceDatabaseUserParseId(stateID) 138 | if err != nil { 139 | return diag.Errorf("%s",err) 140 | } 141 | result , decodeError := getUser(client,username,database) 142 | if decodeError != nil { 143 | return diag.Errorf("Error decoding user : %s ", err) 144 | } 145 | if len(result.Users) == 0 { 146 | return diag.Errorf("user does not exist") 147 | } 148 | roles := make([]interface{}, len(result.Users[0].Roles)) 149 | 150 | for i, s := range result.Users[0].Roles { 151 | roles[i] = map[string]interface{}{ 152 | "db": s.Db, 153 | "role": s.Role, 154 | } 155 | } 156 | dataSetError := data.Set("role", roles) 157 | if dataSetError != nil { 158 | return diag.Errorf("error setting role : %s " , dataSetError) 159 | } 160 | dataSetError = data.Set("auth_database", database) 161 | if dataSetError != nil { 162 | return diag.Errorf("error setting auth_db : %s " , dataSetError) 163 | } 164 | dataSetError = data.Set("password", data.Get("password")) 165 | if dataSetError != nil { 166 | return diag.Errorf("error setting password : %s " , dataSetError) 167 | } 168 | data.SetId(stateID) 169 | return nil 170 | } 171 | 172 | func resourceDatabaseUserCreate(ctx context.Context, data *schema.ResourceData, i interface{}) diag.Diagnostics { 173 | var config = i.(*MongoDatabaseConfiguration) 174 | client , connectionError := MongoClientInit(config) 175 | if connectionError != nil { 176 | return diag.Errorf("Error connecting to database : %s ", connectionError) 177 | } 178 | var database = data.Get("auth_database").(string) 179 | var userName = data.Get("name").(string) 180 | var userPassword = data.Get("password").(string) 181 | var roleList []Role 182 | var user = DbUser{ 183 | Name: userName, 184 | Password: userPassword, 185 | } 186 | roles := data.Get("role").(*schema.Set).List() 187 | roleMapErr := mapstructure.Decode(roles, &roleList) 188 | if roleMapErr != nil { 189 | return diag.Errorf("Error decoding map : %s ", roleMapErr) 190 | } 191 | err := createUser(client,user,roleList,database) 192 | if err != nil { 193 | return diag.Errorf("Could not create the user : %s ", err) 194 | } 195 | str := database+"."+userName 196 | encoded := base64.StdEncoding.EncodeToString([]byte(str)) 197 | data.SetId(encoded) 198 | return resourceDatabaseUserRead(ctx, data, i) 199 | } 200 | 201 | func resourceDatabaseUserParseId(id string) (string, string, error){ 202 | result , errEncoding := base64.StdEncoding.DecodeString(id) 203 | 204 | if errEncoding != nil { 205 | return "", "", fmt.Errorf("unexpected format of ID Error : %s", errEncoding) 206 | } 207 | parts := strings.SplitN(string(result), ".", 2) 208 | if len(parts) != 2 || parts[0] == "" || parts[1] == "" { 209 | return "", "", fmt.Errorf("unexpected format of ID (%s), expected attribute1.attribute2", id) 210 | } 211 | 212 | database := parts[0] 213 | userName := parts[1] 214 | 215 | return userName , database , nil 216 | } 217 | --------------------------------------------------------------------------------