├── .dockerignore ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── build.go ├── build │ ├── awscodebuild.go │ ├── awscodebuild_test.go │ ├── circleciv2.go │ ├── circleciv2_test.go │ ├── githubactions.go │ ├── githubactions_test.go │ ├── local.go │ ├── local_test.go │ ├── provider.go │ └── utils.go ├── root.go ├── scaffolder.go ├── scaffolder_test.go ├── terraform.go ├── terraform_test.go ├── upgrade.go └── utils.go ├── examples └── fargate-create.yml ├── go.mod ├── go.sum └── main.go /.dockerignore: -------------------------------------------------------------------------------- 1 | fargate-create 2 | vendor 3 | iac 4 | .terraform 5 | hidden.env 6 | Dockerfile.build 7 | .vscode 8 | terraform.tfvars 9 | fargate.json -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | 7 | jobs: 8 | test: 9 | name: Test 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | 14 | - name: Install Go 15 | uses: actions/setup-go@v1 16 | with: 17 | go-version: 1.18 18 | 19 | - name: Run unit tests 20 | run: make test 21 | 22 | - name: Build for all platforms 23 | run: make dist 24 | 25 | - name: Push up a new pre-release 26 | if: ${{ contains(github.ref,'pre')}} 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.SECRET_GITHUB_TOKEN }} 29 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 30 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 31 | run: make prerelease 32 | 33 | - name: Push up a new normal release 34 | if: ${{ !contains(github.ref,'pre')}} 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.SECRET_GITHUB_TOKEN }} 37 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 38 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 39 | run: make release -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | fargate-create 2 | vendor 3 | iac 4 | .terraform 5 | hidden.env 6 | Dockerfile.build 7 | .vscode 8 | terraform.tfvars 9 | fargate.jsondist 10 | dist 11 | develop 12 | master 13 | release 14 | pre 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.9.0 (2020-07-06) 2 | 3 | ### Features 4 | 5 | - adds support for aws cli v2 when generating the deploy.sh script (#34) 6 | 7 | 8 | ## 0.8.0 (2019-12-09) 9 | 10 | ### Features 11 | 12 | - adds `githubactions` build provider [#32](https://github.com/turnerlabs/fargate-create/pull/32) 13 | - adds `awscodebuild` build provider [#33](https://github.com/turnerlabs/fargate-create/pull/33) 14 | 15 | 16 | ## 0.7.1 (2019-08-12) 17 | 18 | ### Bug Fixes 19 | 20 | - AWS Region not respected for tf state bucket in environments [#27](https://github.com/turnerlabs/fargate-create/issues/27) 21 | 22 | 23 | ## 0.7.0 (2019-06-10) 24 | 25 | ### Features 26 | 27 | - updates outputted docker-compose.yml to v3.7 28 | 29 | 30 | ## 0.6.1 (2019-02-22) 31 | 32 | ### Features 33 | 34 | - Documentation 35 | 36 | 37 | ## 0.6.0 (2019-02-22) 38 | 39 | ### Features 40 | 41 | - New `upgrade` command ([#20](https://github.com/turnerlabs/fargate-create/issues/20)) 42 | 43 | 44 | ## 0.5.0 (2019-01-09) 45 | 46 | ### Features 47 | 48 | - New `build` command framework with support for Circle CI ([#16](https://github.com/turnerlabs/fargate-create/pull/16)) 49 | - Release binaries now hosted in s3 ([#18](https://github.com/turnerlabs/fargate-create/pull/18)) 50 | 51 | 52 | ## 0.4.0 (2018-11-14) 53 | 54 | ### Features 55 | 56 | - adds support for scheduled tasks ([#15](https://github.com/turnerlabs/fargate-create/pull/15)) 57 | 58 | 59 | ## 0.3.0 (2018-09-20) 60 | 61 | ### Features 62 | 63 | - Sets optional port in docker-compose.yml ([#13](https://github.com/turnerlabs/fargate-create/issues/13)) 64 | 65 | ### Bug Fixes 66 | 67 | - Fixes issue parsing Terraform comments ([#12](https://github.com/turnerlabs/fargate-create/issues/12)) 68 | 69 | 70 | ## 0.2.1 (2018-09-12) 71 | 72 | ### Features 73 | 74 | - Readme doc update 75 | 76 | 77 | ## 0.2.0 (2018-08-21) 78 | 79 | ### Features 80 | 81 | - Changed the default template to always pull the latest (using git) 82 | 83 | 84 | ## 0.1.0 (2018-08-08) 85 | 86 | ### Features 87 | 88 | - Initial Release 89 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Thanks for your interest in the project! We want to welcome contributors so we put together the following set of guidelines to help participate. 4 | 5 | ## Workflow 6 | 7 | - **Did you find a bug?** 8 | 9 | Awesome! Please feel free to open an issue first, or if you have a fix open a 10 | pull request that describes the bug with code that demonstrates the bug in a 11 | test and addresses it. 12 | 13 | - **Do you want to add a feature?** 14 | 15 | Features begin life as a proposal. Please open a pull request with a proposal 16 | that explains the feature, its use case, considerations, and design. This will 17 | allow interested contributors to weigh in, refine the idea, and ensure there's 18 | no wasted time in the event a feature doesn't fit with our direction. 19 | 20 | ## Setup 21 | 22 | - Ensure you're using golang 1.10+. 23 | 24 | ```console 25 | go version 26 | ``` 27 | 28 | - Install [`dep`][dep] if not present on your system. See their [installation 29 | instructions][dep-install] and [releases page][dep-releases] for details. 30 | 31 | - Install the source code from GitHub 32 | 33 | ```console 34 | go get github.com/turnerlabs/fargate-create 35 | ``` 36 | 37 | - Run `dep ensure` to install required dependencies 38 | 39 | ```console 40 | cd $GOPATH/src/github.com/turnerlabs/fargate-create 41 | dep ensure 42 | ``` 43 | 44 | - Make sure you can run the tests 45 | 46 | ```console 47 | make test 48 | ``` 49 | 50 | ## Testing 51 | 52 | - Tests can be run via `go test` or `make test` 53 | 54 | - To generate mocks as you add functionality, run `make mocks` or use `go 55 | generate` directly 56 | 57 | ## Building 58 | 59 | - To build a binary for your platform run `make` 60 | 61 | - For cross-building for all supported platforms, run `make dist` which builds 62 | binaries for darwin (64-bit) and linux (Arm, 32-bit, 64-bit). 63 | 64 | ## Making Changes 65 | 66 | * Create a feature branch from where you want to base your work. 67 | * This is usually the `develop` branch. 68 | * To quickly create a feature branch; `git checkout -b feature/my-feature`. Please avoid working directly on the 69 | `master` branch. 70 | * Make commits of logical units. 71 | * Run `go fmt ./cmd` before committing. 72 | * Make sure you have added the necessary tests for your changes. 73 | * Run _all_ the tests to assure nothing else was accidentally broken. 74 | 75 | ## Submitting Changes 76 | 77 | * Push your changes to a feature branch in your fork of the repository. 78 | * Submit a pull request to the `develop` branch to the repository in the turnerlabs organization. 79 | 80 | ## Release Process 81 | 82 | * After a feature pull request has been merged into the `develop` branch, a CI build will be automatically kicked off. The CI build will run unit tests, do a multi-platform build and automatically deploy the build to the [Github releases](https://github.com/turnerlabs/fargate-create/releases) page as a pre-release using the latest tag (`git describe --tags`) as the version number. 83 | * After the core team decides which features will be included in the next release, a release branch is created (e.g., `release/v0.5`) from develop. 84 | * The `CHANGELOG.md` file is updated to document the release in the release branch. 85 | * The release branch is merged to `master`, tagged, and pushed (along with tags). 86 | * This will kick off a build that builds using the latest tag and deploys as a Github release. 87 | * The release branch is then merged back to `develop`, tagged for pre-release (to start next version, e.g. v0.6.0-pre) and pushed. 88 | 89 | ## Licensing 90 | 91 | This project is released under the [Apache 2.0 license][apache]. 92 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/aws/aws-sdk-go" 6 | packages = [ 7 | "aws", 8 | "aws/awserr", 9 | "aws/awsutil", 10 | "aws/client", 11 | "aws/client/metadata", 12 | "aws/corehandlers", 13 | "aws/credentials", 14 | "aws/credentials/ec2rolecreds", 15 | "aws/credentials/endpointcreds", 16 | "aws/credentials/stscreds", 17 | "aws/csm", 18 | "aws/defaults", 19 | "aws/ec2metadata", 20 | "aws/endpoints", 21 | "aws/request", 22 | "aws/session", 23 | "aws/signer/v4", 24 | "internal/sdkio", 25 | "internal/sdkrand", 26 | "internal/sdkuri", 27 | "internal/shareddefaults", 28 | "private/protocol", 29 | "private/protocol/eventstream", 30 | "private/protocol/eventstream/eventstreamapi", 31 | "private/protocol/query", 32 | "private/protocol/query/queryutil", 33 | "private/protocol/rest", 34 | "private/protocol/restxml", 35 | "private/protocol/xml/xmlutil", 36 | "service/s3", 37 | "service/sts" 38 | ] 39 | revision = "bc3f534c19ffdf835e524e11f0f825b3eaf541c3" 40 | version = "v1.14.31" 41 | 42 | [[projects]] 43 | branch = "master" 44 | name = "github.com/bgentry/go-netrc" 45 | packages = ["netrc"] 46 | revision = "9fd32a8b3d3d3f9d43c341bfe098430e07609480" 47 | 48 | [[projects]] 49 | name = "github.com/go-ini/ini" 50 | packages = ["."] 51 | revision = "358ee7663966325963d4e8b2e1fbd570c5195153" 52 | version = "v1.38.1" 53 | 54 | [[projects]] 55 | branch = "master" 56 | name = "github.com/hashicorp/go-cleanhttp" 57 | packages = ["."] 58 | revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d" 59 | 60 | [[projects]] 61 | name = "github.com/hashicorp/go-getter" 62 | packages = [ 63 | ".", 64 | "helper/url" 65 | ] 66 | revision = "a33f09ce9feed989941a4dfe08b3890a0f8aceb9" 67 | 68 | [[projects]] 69 | branch = "master" 70 | name = "github.com/hashicorp/go-safetemp" 71 | packages = ["."] 72 | revision = "b1a1dbde6fdc11e3ae79efd9039009e22d4ae240" 73 | 74 | [[projects]] 75 | branch = "master" 76 | name = "github.com/hashicorp/go-version" 77 | packages = ["."] 78 | revision = "270f2f71b1ee587f3b609f00f422b76a6b28f348" 79 | 80 | [[projects]] 81 | name = "github.com/inconshreveable/mousetrap" 82 | packages = ["."] 83 | revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" 84 | version = "v1.0" 85 | 86 | [[projects]] 87 | name = "github.com/jmespath/go-jmespath" 88 | packages = ["."] 89 | revision = "0b12d6b5" 90 | 91 | [[projects]] 92 | branch = "master" 93 | name = "github.com/mitchellh/go-homedir" 94 | packages = ["."] 95 | revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66" 96 | 97 | [[projects]] 98 | branch = "master" 99 | name = "github.com/mitchellh/go-testing-interface" 100 | packages = ["."] 101 | revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28" 102 | 103 | [[projects]] 104 | name = "github.com/spf13/cobra" 105 | packages = ["."] 106 | revision = "a114f312e075f65bf30d6d9a1430113f857e543b" 107 | 108 | [[projects]] 109 | name = "github.com/spf13/pflag" 110 | packages = ["."] 111 | revision = "583c0c0531f06d5278b7d917446061adc344b5cd" 112 | version = "v1.0.1" 113 | 114 | [[projects]] 115 | name = "github.com/ulikunitz/xz" 116 | packages = [ 117 | ".", 118 | "internal/hash", 119 | "internal/xlog", 120 | "lzma" 121 | ] 122 | revision = "0c6b41e72360850ca4f98dc341fd999726ea007f" 123 | version = "v0.5.4" 124 | 125 | [[projects]] 126 | name = "gopkg.in/yaml.v2" 127 | packages = ["."] 128 | revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" 129 | version = "v2.2.1" 130 | 131 | [solve-meta] 132 | analyzer-name = "dep" 133 | analyzer-version = 1 134 | inputs-digest = "49fc4592f370732218f5cdea99b6bc1826056bcb685815fd67e29c9eb2813504" 135 | solver-name = "gps-cdcl" 136 | solver-version = 1 137 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | [[constraint]] 2 | name = "github.com/aws/aws-sdk-go" 3 | version = "1.14.26" 4 | 5 | [[constraint]] 6 | name = "github.com/spf13/cobra" 7 | revision = "a114f312e075f65bf30d6d9a1430113f857e543b" 8 | 9 | [[constraint]] 10 | name = "github.com/hashicorp/go-getter" 11 | revision = "a33f09ce9feed989941a4dfe08b3890a0f8aceb9" 12 | 13 | [[constraint]] 14 | name = "gopkg.in/yaml.v2" 15 | version = "2.2.1" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Warner Media, LLC. All other rights reserved. 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. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: mocks test build dist clean 2 | 3 | PACKAGES := $(shell go list ./... | grep -v /mock) 4 | BUILD_VERSION := $(shell git describe --tags) 5 | AWS_DEFAULT_REGION := us-east-1 6 | 7 | test: 8 | go test -race -cover $(PACKAGES) 9 | 10 | build: 11 | make clean 12 | go build -v 13 | 14 | dist: 15 | echo building ${BUILD_VERSION} 16 | GOOS=linux GOARCH=386 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_linux_386 17 | GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_linux_amd64 18 | GOOS=linux GOARCH=arm64 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_linux_arm64 19 | GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_darwin_amd64 20 | GOOS=darwin GOARCH=arm64 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_darwin_arm64 21 | GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=${BUILD_VERSION}" -o dist/ncd_windows_amd64.exe 22 | 23 | prerelease: 24 | gh release create ${BUILD_VERSION} --generate-notes --prerelease dist/* 25 | aws s3 cp dist/ s3://get-fargate-create.turnerlabs.io/${BUILD_VERSION}/ --recursive --region ${AWS_DEFAULT_REGION} 26 | echo ${BUILD_VERSION} > develop && aws s3 cp ./develop s3://get-fargate-create.turnerlabs.io/ --region ${AWS_DEFAULT_REGION} 27 | 28 | release: 29 | gh release create ${BUILD_VERSION} --generate-notes dist/* 30 | aws s3 cp dist/ s3://get-fargate-create.turnerlabs.io/${BUILD_VERSION}/ --recursive --region ${AWS_DEFAULT_REGION} 31 | echo ${BUILD_VERSION} > master && aws s3 cp ./master s3://get-fargate-create.turnerlabs.io/ --region ${AWS_DEFAULT_REGION} 32 | 33 | clean: 34 | rm -f fargate-create 35 | rm -rf iac 36 | rm -rf fargate-create-template 37 | rm -rf dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fargate-create 2 | ============== 3 | 4 | A CLI tool for scaffolding out new [AWS ECS/Fargate](https://aws.amazon.com/fargate/) applications based on [terraform-ecs-fargate](https://github.com/turnerlabs/terraform-ecs-fargate) and [Fargate CLI](https://github.com/turnerlabs/fargate). 5 | 6 | 7 | ### Why? 8 | 9 | The main design goal of this project is to create an easy and maintainable Fargate experience by separating `infrastructure` related concerns and `application` related concerns using tools that are optimized for each. 10 | 11 | ### Installation 12 | 13 | You can install the CLI with a curl utility script (macos/linux) or by downloading the binary from the releases page. Once installed you'll get the `fargate-create` command. 14 | 15 | ``` 16 | curl -s get-fargate-create.turnerlabs.io | sh 17 | ```` 18 | 19 | ### Usage 20 | 21 | Assuming you have a project with a [Dockerfile]()... 22 | 23 | Specify your template's input parameters in [terraform.tfvars](https://www.terraform.io/docs/configuration/variables.html) (or terraform.json). The [default web application template's](https://github.com/turnerlabs/terraform-ecs-fargate) input looks something like this. Note: [any Terraform template can be used](#extensibility) 24 | 25 | ```hcl 26 | # app/env to scaffold 27 | app = "my-app" 28 | environment = "dev" 29 | 30 | internal = "true" 31 | container_port = "8080" 32 | replicas = "1" 33 | health_check = "/health" 34 | region = "us-east-1" 35 | aws_profile = "default" 36 | vpc = "vpc-123" 37 | private_subnets = "subnet-123,subnet-456" 38 | public_subnets = "subnet-789,subnet-012" 39 | tags = { 40 | application = "my-app" 41 | environment = "dev" 42 | } 43 | ``` 44 | 45 | ```shell 46 | $ fargate-create 47 | scaffolding my-app dev 48 | Looking up AWS Account ID using profile: default 49 | downloading terraform template git@github.com:turnerlabs/terraform-ecs-fargate 50 | installing terraform template 51 | 52 | done 53 | ``` 54 | 55 | Now you have all the files you need to spin up something in Fargate. Note that the Terraform files can be edited or customized. You can also use your own Terraform template using the `--template` flag. 56 | 57 | Infrastructure: provision using Terraform 58 | ```shell 59 | cd iac/base 60 | terraform init && terraform apply 61 | cd ../env/dev 62 | terraform init && terraform apply 63 | ``` 64 | 65 | Application: build/push using Docker and deploy using Fargate CLI 66 | ```shell 67 | docker-compose build 68 | login=$(aws ecr get-login --no-include-email) && eval "$login" 69 | docker-compose push 70 | fargate service deploy -f docker-compose.yml 71 | ``` 72 | 73 | To scaffold out additional environnments, simply change the `environment` input parameter in `terraform.tfvars` and re-run 74 | ```shell 75 | $ fargate-create 76 | scaffolding my-app prod 77 | Looking up AWS Account ID using profile: default 78 | downloading terraform template git@github.com:turnerlabs/terraform-ecs-fargate 79 | installing terraform template 80 | iac/base already exists, ignoring 81 | 82 | done 83 | ``` 84 | 85 | And then bring up the new environment (no need to apply base again since it's shared): 86 | ```shell 87 | cd ../prod 88 | terraform init && terraform apply 89 | ``` 90 | 91 | You'll end up with a directory structure that looks something like this: 92 | ``` 93 | . 94 | |____iac 95 | | |____base 96 | | |____env 97 | | | |____dev 98 | | | |____prod 99 | ``` 100 | 101 | As changes are made to the various upstream templates over time, the `upgrade` command can be used to keep installed versions up to date. 102 | 103 | ```bash 104 | fargate-create upgrade 105 | ``` 106 | 107 | 108 | ### Stacks 109 | 110 | The following stacks are popular configurations that can be used with `fargate-create` 111 | 112 | - [Web Application (ALB - HTTP or HTTPS)](https://github.com/turnerlabs/terraform-ecs-fargate#fargate-create) 113 | - [Web Application (ALB - HTTPS/DNS)](https://github.com/turnerlabs/terraform-ecs-fargate-dns-https#fargate-create) 114 | - [Web API Gateway](https://github.com/turnerlabs/terraform-ecs-fargate-apigateway#fargate-create) 115 | - [Scheduled Task](https://github.com/turnerlabs/terraform-ecs-fargate-scheduled-task#fargate-create) 116 | - [Background Worker (service)](https://github.com/turnerlabs/terraform-ecs-fargate-background-worker#fargate-create) 117 | - [Network Application (NLB)](https://github.com/turnerlabs/terraform-ecs-fargate-nlb#fargate-create) 118 | - [Airflow](https://github.com/turnerlabs/terraform-ecs-fargate-airflow#fargate-create) 119 | 120 | 121 | ### Help 122 | 123 | ``` 124 | Scaffold out new AWS ECS/Fargate applications based on Terraform templates and Fargate CLI 125 | 126 | Usage: 127 | fargate-create [flags] 128 | fargate-create [command] 129 | 130 | Examples: 131 | 132 | # Scaffold an environment using the latest default template 133 | fargate-create 134 | 135 | # Do not prompt for options 136 | fargate-create -y 137 | 138 | # Use a template stored in github 139 | fargate-create -t git@github.com:turnerlabs/terraform-ecs-fargate?ref=v0.4.3 140 | 141 | # Scaffold out files for various build systems 142 | fargate-create build circleciv2 143 | 144 | # keep your template up to date 145 | fargate-create upgrade 146 | 147 | # Use a template stored in s3 148 | AWS_ACCESS_KEY=xyz AWS_SECRET_KEY=xyz AWS_REGION=us-east-1 \ 149 | fargate-create -t s3::https://s3.amazonaws.com/my-bucket/my-template 150 | 151 | # Use a template stored in your file system 152 | fargate-create -t ~/my-template 153 | 154 | # Use a specific input file 155 | fargate-create -f app.tfvars 156 | 157 | # Use a JSON input file 158 | fargate-create -f app.json 159 | 160 | 161 | Available Commands: 162 | build Scaffold out artifacts for various build systems 163 | help Help about any command 164 | upgrade Keep a terraform template up to date 165 | 166 | Flags: 167 | -f, --file string file specifying Terraform input variables, in either HCL or JSON format (default "terraform.tfvars") 168 | -h, --help help for fargate-create 169 | -d, --target-dir string target directory where code is outputted (default "iac") 170 | -t, --template string URL of a compatible Terraform template (default "git@github.com:turnerlabs/terraform-ecs-fargate") 171 | -v, --verbose Verbose output 172 | --version version for fargate-create 173 | -y, --yes don't ask questions and use defaults 174 | ``` 175 | 176 | 177 | ### CI/CD 178 | 179 | Using this technique, it's easy to codegen CI/CD pipelines for many popular build tools. The `build` command supports this. 180 | 181 | ```shell 182 | $ fargate-create build 183 | ``` 184 | 185 | The following providers are supported: 186 | 187 | - [circleciv2](https://circleci.com/) 188 | - [githubactions](https://github.com/features/actions) 189 | - [awscodebuild](https://aws.amazon.com/codebuild/) 190 | 191 | 192 | ### Extensibility 193 | 194 | `fargate-create` can scaffold out any Terraform template (specified by `--template`) that meets the following requirements: 195 | 196 | - `base` and `env/dev` directory structure 197 | - a `env/dev/main.tf` with an s3 remote state backend 198 | - `app` and `environment` input variables 199 | 200 | Your template can be downloaded from a variety of locations using a variety of protocols. The following are supported: 201 | 202 | - Local files (`~/my-template`) 203 | - Git (`git@github.com:my-org/my-template`) 204 | - Amazon S3 (`s3::https://s3.amazonaws.com/my-bucket/my-template`) 205 | - HTTP (`http://server/my-template/`) 206 | 207 | Optionally: 208 | 209 | - add a `fargate-create.yml` ([example here](examples/fargate-create.yml)) to your template to drive custom configuration, prompting for defaults, etc. 210 | 211 | An [example](https://github.com/turnerlabs/terraform-ecs-fargate-scheduled-task/) of an extended template: 212 | ```shell 213 | $ fargate-create -f my-scheduledtask.tfvars -t git@github.com:turnerlabs/terraform-ecs-fargate-scheduled-task 214 | ``` 215 | -------------------------------------------------------------------------------- /cmd/build.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/turnerlabs/fargate-create/cmd/build" 11 | ) 12 | 13 | var buildCmd = &cobra.Command{ 14 | Use: "build", 15 | Short: "Scaffold out artifacts for various build systems", 16 | Long: "Scaffold out artifacts for various build systems", 17 | Args: cobra.ExactArgs(1), 18 | Run: doBuild, 19 | Example: ` 20 | fargate-create build local 21 | fargate-create build circleciv2 22 | fargate-create build githubactions 23 | `, 24 | } 25 | 26 | func init() { 27 | rootCmd.AddCommand(buildCmd) 28 | } 29 | 30 | func doBuild(cmd *cobra.Command, args []string) { 31 | 32 | //load build provider 33 | providerString := args[0] 34 | provider, err := build.GetProvider(providerString) 35 | check(err) 36 | 37 | //get artifacts 38 | artifacts, err := provider.ProvideArtifacts(context) 39 | check(err) 40 | 41 | //write artifacts to file system 42 | if artifacts != nil { 43 | for _, artifact := range artifacts { 44 | //create directories if needed 45 | dirs := filepath.Dir(artifact.FilePath) 46 | err = os.MkdirAll(dirs, os.ModePerm) 47 | check(err) 48 | 49 | if _, err := os.Stat(artifact.FilePath); err == nil { 50 | //exists 51 | fmt.Print(artifact.FilePath + " already exists. Overwrite? ") 52 | if askForConfirmation() { 53 | err = ioutil.WriteFile(artifact.FilePath, []byte(artifact.FileContents), artifact.FileMode) 54 | fmt.Println("wrote " + artifact.FilePath) 55 | check(err) 56 | } 57 | } else { 58 | //doesn't exist 59 | err = ioutil.WriteFile(artifact.FilePath, []byte(artifact.FileContents), artifact.FileMode) 60 | fmt.Println("wrote " + artifact.FilePath) 61 | check(err) 62 | } 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /cmd/build/awscodebuild.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | //AWSCodeBuild represents a Github Actions build provider 4 | type AWSCodeBuild struct{} 5 | 6 | //ProvideArtifacts is the Provider implementation 7 | func (provider AWSCodeBuild) ProvideArtifacts(context Context) ([]*Artifact, error) { 8 | artifacts := []*Artifact{} 9 | artifacts = append(artifacts, createArtifact("buildspec.yml", getAWSBuildspecYAML(context))) 10 | return artifacts, nil 11 | } 12 | 13 | func getAWSBuildspecYAML(context Context) string { 14 | contextTemplate := getContextTemplate(context) 15 | 16 | textTemplate := `version: 0.2 17 | phases: 18 | install: 19 | runtime-versions: 20 | docker: 18 21 | commands: 22 | - nohup /usr/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2& 23 | pre_build: 24 | commands: 25 | - export FARGATE_CLUSTER={{ .App }}-{{ .Env }} 26 | - export FARGATE_SERVICE={{ .App }}-{{ .Env }} 27 | - export REPO={{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/{{ .App }} 28 | 29 | # build image:tag 30 | - export VERSION=0.1.0 31 | # - export VERSION=$(jq -r .version < package.json) 32 | - export BUILD=$(echo ${CODEBUILD_BUILD_ID} | cut -d ":" -f 2) 33 | - export BRANCH=$(echo ${CODEBUILD_WEBHOOK_HEAD_REF} | cut -d "/" -f 3) 34 | - export IMAGE=${REPO}:${VERSION}-${BRANCH}.${BUILD} 35 | 36 | # login to ECR registry 37 | - login=$(aws ecr get-login --no-include-email) && eval "$login" 38 | build: 39 | commands: 40 | - docker build -t ${IMAGE} . 41 | - docker push ${IMAGE} 42 | post_build: 43 | commands: 44 | - fargate service deploy -i ${IMAGE}` 45 | 46 | return applyTemplate(textTemplate, contextTemplate) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/build/awscodebuild_test.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestProvider_AWSCodeBuild(t *testing.T) { 10 | 11 | ctx := mockContext{ 12 | App: "my-app", 13 | Env: "dev", 14 | Account: "123456789", 15 | Region: "us-west-1", 16 | } 17 | 18 | provider, err := GetProvider("awscodebuild") 19 | if err != nil { 20 | t.Fail() 21 | } 22 | artifacts, err := provider.ProvideArtifacts(ctx) 23 | if err != nil { 24 | t.Fail() 25 | } 26 | if artifacts == nil { 27 | t.Fail() 28 | } 29 | 30 | yaml := artifacts[0].FileContents 31 | t.Log(yaml) 32 | if artifacts[0].FilePath != "buildspec.yml" { 33 | t.Fail() 34 | } 35 | 36 | repo := fmt.Sprintf(`REPO=%v.dkr.ecr.%s.amazonaws.com/%v`, ctx.Account, ctx.Region, ctx.App) 37 | t.Log(repo) 38 | if !strings.Contains(yaml, repo) { 39 | t.Error("expecting", repo) 40 | } 41 | cluster := fmt.Sprintf("FARGATE_CLUSTER=%s-%s", ctx.App, ctx.Env) 42 | if !strings.Contains(yaml, cluster) { 43 | t.Error("expecting", cluster) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cmd/build/circleciv2.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import "fmt" 4 | 5 | //CircleCIv2 represents a circle ci v2 build provider 6 | type CircleCIv2 struct{} 7 | 8 | //ProvideArtifacts is the Provider implementation 9 | func (provider CircleCIv2) ProvideArtifacts(context Context) ([]*Artifact, error) { 10 | 11 | artifacts := []*Artifact{} 12 | artifacts = append(artifacts, createArtifact(".circleci/config.yml", getCircleCIv2YAML())) 13 | artifacts = append(artifacts, createArtifact(".circleci/config.env", getConfigEnv(context))) 14 | 15 | fmt.Println() 16 | fmt.Println(`Be sure to supply the following environment variables in your Circle CI build: 17 | AWS_ACCESS_KEY_ID (terraform state show aws_iam_access_key.cicd_keys) 18 | AWS_SECRET_ACCESS_KEY (terraform state show aws_iam_access_key.cicd_keys) 19 | AWS_DEFAULT_REGION=us-east-1`) 20 | fmt.Println() 21 | 22 | return artifacts, nil 23 | } 24 | 25 | func getCircleCIv2YAML() string { 26 | return ` 27 | version: 2 28 | jobs: 29 | build: 30 | docker: 31 | - image: quay.io/turner/fargate-cicd 32 | environment: 33 | VAR: .circleci/config.env 34 | steps: 35 | - checkout 36 | - setup_remote_docker: 37 | version: 18.06.0-ce 38 | - run: 39 | name: Set docker image 40 | command: | 41 | source ${VAR} 42 | # either manage version in config.env or some other way 43 | # for node.js apps you can use version from package.json 44 | # VERSION=$(jq -r .version < package.json) 45 | BUILD=${CIRCLE_BUILD_NUM} 46 | if [ "${CIRCLE_BRANCH}" != "master" ]; then 47 | BUILD=${CIRCLE_BRANCH}.${CIRCLE_BUILD_NUM} 48 | fi 49 | echo "export IMAGE=${REPO}:${VERSION}-${BUILD}" >> ${VAR} 50 | cat ${VAR} 51 | - run: 52 | name: Login to registry 53 | command: login=$(aws ecr get-login --no-include-email) && eval "$login" 54 | - run: 55 | name: Build app image 56 | command: . ${VAR}; docker build -t ${IMAGE} . 57 | - run: 58 | name: Push app image to registry 59 | command: . ${VAR}; docker push ${IMAGE} 60 | - run: 61 | name: Deploy 62 | command: . ${VAR}; fargate service deploy -i ${IMAGE}` 63 | } 64 | 65 | func getConfigEnv(context Context) string { 66 | contextTemplate := getContextTemplate(context) 67 | 68 | textTemplate := `export FARGATE_CLUSTER="{{ .App }}-{{ .Env }}" 69 | export FARGATE_SERVICE="{{ .App }}-{{ .Env }}" 70 | export REPO="{{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/{{ .App }}" 71 | export VERSION="0.1.0" 72 | ` 73 | return applyTemplate(textTemplate, contextTemplate) 74 | } 75 | -------------------------------------------------------------------------------- /cmd/build/circleciv2_test.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestProvider_CircleCIv2(t *testing.T) { 10 | 11 | ctx := mockContext{ 12 | App: "my-app", 13 | Env: "dev", 14 | Account: "123456789", 15 | Region: "us-west-1", 16 | } 17 | 18 | provider, err := GetProvider("circleciv2") 19 | if err != nil { 20 | t.Fail() 21 | } 22 | artifacts, err := provider.ProvideArtifacts(ctx) 23 | if err != nil { 24 | t.Fail() 25 | } 26 | if artifacts == nil { 27 | t.Fail() 28 | } 29 | 30 | t.Log(artifacts[0].FileContents) 31 | if artifacts[0].FilePath != ".circleci/config.yml" { 32 | t.Fail() 33 | } 34 | 35 | configEnv := artifacts[1].FileContents 36 | t.Log(configEnv) 37 | if artifacts[1].FilePath != ".circleci/config.env" { 38 | t.Fail() 39 | } 40 | 41 | lines := strings.Split(configEnv, "\n") 42 | 43 | if strings.TrimSpace(lines[1]) != fmt.Sprintf(`export FARGATE_CLUSTER="%v-%v"`, ctx.App, ctx.Env) { 44 | t.Error("not expecting", lines[1]) 45 | } 46 | if strings.TrimSpace(lines[2]) != fmt.Sprintf(`export FARGATE_SERVICE="%v-%v"`, ctx.App, ctx.Env) { 47 | t.Error("not expecting", lines[2]) 48 | } 49 | if strings.TrimSpace(lines[3]) != fmt.Sprintf(`export REPO="%v.dkr.ecr.%s.amazonaws.com/%v"`, ctx.Account, ctx.Region, ctx.App) { 50 | t.Error("not expecting", lines[3]) 51 | } 52 | if strings.TrimSpace(lines[4]) != `export VERSION="0.1.0"` { 53 | t.Error("not expecting", lines[4]) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cmd/build/githubactions.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import "fmt" 4 | 5 | //GithubActions represents a Github Actions build provider 6 | type GithubActions struct{} 7 | 8 | //ProvideArtifacts is the Provider implementation 9 | func (provider GithubActions) ProvideArtifacts(context Context) ([]*Artifact, error) { 10 | artifacts := []*Artifact{} 11 | artifacts = append(artifacts, createArtifact(fmt.Sprintf(".github/workflows/%s.yml", context.GetEnvironment()), getGithubActionsYAML(context))) 12 | 13 | fmt.Println() 14 | fmt.Println(`Be sure to add the following secrets to your Github repository: 15 | AWS_ACCESS_KEY_ID (terraform state show aws_iam_access_key.cicd_keys) 16 | AWS_SECRET_ACCESS_KEY (terraform state show aws_iam_access_key.cicd_keys)`) 17 | fmt.Println() 18 | 19 | return artifacts, nil 20 | } 21 | 22 | func getGithubActionsYAML(context Context) string { 23 | contextTemplate := getContextTemplate(context) 24 | 25 | textTemplate := `name: {{ .Env }} 26 | on: 27 | push: 28 | branches: 29 | - develop 30 | jobs: 31 | cicd: 32 | name: Deploy develop branch to {{ .Env }} environment 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@master 36 | 37 | - name: Set docker image 38 | env: 39 | REPO: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/{{ .App }} 40 | VERSION: 0.1.0 41 | run: | 42 | BRANCH=$(echo $GITHUB_REF | cut -d "/" -f 3) 43 | SHA_SHORT=$(echo $GITHUB_SHA | head -c7) 44 | echo "export IMAGE=$REPO:$VERSION-$BRANCH.$SHA_SHORT" >> ./env 45 | cat ./env 46 | - name: Build image 47 | uses: turnerlabs/fargate-cicd-action@master 48 | with: 49 | args: . ./env; docker build -t $IMAGE . 50 | 51 | - name: Login to ECR 52 | uses: turnerlabs/fargate-cicd-action@master 53 | env: 54 | AWS_DEFAULT_REGION: {{ .Region }} 55 | AWS_ACCESS_KEY_ID: ${{"{{ secrets.AWS_ACCESS_KEY_ID }}"}} 56 | AWS_SECRET_ACCESS_KEY: ${{"{{ secrets.AWS_SECRET_ACCESS_KEY }}"}} 57 | with: 58 | args: login=$(aws ecr get-login --no-include-email) && eval "$login" 59 | 60 | - name: Push image to ECR 61 | uses: turnerlabs/fargate-cicd-action@master 62 | with: 63 | args: . ./env; docker push $IMAGE 64 | 65 | - name: Deploy image to fargate 66 | uses: turnerlabs/fargate-cicd-action@master 67 | env: 68 | AWS_DEFAULT_REGION: {{ .Region }} 69 | AWS_ACCESS_KEY_ID: ${{"{{ secrets.AWS_ACCESS_KEY_ID }}"}} 70 | AWS_SECRET_ACCESS_KEY: ${{"{{ secrets.AWS_SECRET_ACCESS_KEY }}"}} 71 | FARGATE_CLUSTER: {{ .App }}-{{ .Env }} 72 | FARGATE_SERVICE: {{ .App }}-{{ .Env }} 73 | with: 74 | args: . ./env; fargate service deploy -i $IMAGE` 75 | 76 | return applyTemplate(textTemplate, contextTemplate) 77 | } 78 | -------------------------------------------------------------------------------- /cmd/build/githubactions_test.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestProvider_GithubActions(t *testing.T) { 10 | 11 | ctx := mockContext{ 12 | App: "my-app", 13 | Env: "dev", 14 | Account: "123456789", 15 | Region: "us-west-1", 16 | } 17 | 18 | provider, err := GetProvider("githubactions") 19 | if err != nil { 20 | t.Fail() 21 | } 22 | artifacts, err := provider.ProvideArtifacts(ctx) 23 | if err != nil { 24 | t.Fail() 25 | } 26 | if artifacts == nil { 27 | t.Fail() 28 | } 29 | 30 | yaml := artifacts[0].FileContents 31 | t.Log(yaml) 32 | if artifacts[0].FilePath != fmt.Sprintf(".github/workflows/%s.yml", ctx.Env) { 33 | t.Fail() 34 | } 35 | 36 | repo := fmt.Sprintf(`REPO: %v.dkr.ecr.%s.amazonaws.com/%v`, ctx.Account, ctx.Region, ctx.App) 37 | t.Log(repo) 38 | if !strings.Contains(yaml, repo) { 39 | t.Error("expecting", repo) 40 | } 41 | accessKey := "AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}" 42 | if !strings.Contains(yaml, accessKey) { 43 | t.Error("expecting", accessKey) 44 | } 45 | cluster := fmt.Sprintf("FARGATE_CLUSTER: %s-%s", ctx.App, ctx.Env) 46 | if !strings.Contains(yaml, cluster) { 47 | t.Error("expecting", cluster) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cmd/build/local.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | //Local represents a local build provider 4 | type Local struct{} 5 | 6 | //ProvideArtifacts is the Provider implementation 7 | func (provider Local) ProvideArtifacts(context Context) ([]*Artifact, error) { 8 | 9 | //output a build.sh that uses docker to build/push 10 | contextTemplate := getContextTemplate(context) 11 | artifacts := []*Artifact{} 12 | buildScript := createArtifact("build.sh", getLocalBuildScript(contextTemplate)) 13 | buildScript.FileMode = 0700 14 | artifacts = append(artifacts, buildScript) 15 | return artifacts, nil 16 | } 17 | 18 | func getLocalBuildScript(context contextTemplate) string { 19 | textTemplate := ` 20 | #! /bin/bash 21 | set -e 22 | 23 | # build image 24 | IMAGE="{{ .Account }}.dkr.ecr.us-east-1.amazonaws.com/{{ .App }}:0.1.0" 25 | docker build -t ${IMAGE} . 26 | 27 | # push image to ECR repo 28 | login=$(aws ecr get-login --no-include-email) && eval "$login" 29 | docker push ${IMAGE} 30 | ` 31 | return applyTemplate(textTemplate, context) 32 | } 33 | -------------------------------------------------------------------------------- /cmd/build/local_test.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | type mockContext struct { 10 | App string 11 | Env string 12 | Account string 13 | Region string 14 | } 15 | 16 | func (c mockContext) GetApp() string { 17 | return c.App 18 | } 19 | 20 | func (c mockContext) GetEnvironment() string { 21 | return c.Env 22 | } 23 | 24 | func (c mockContext) GetAccount() string { 25 | return c.Account 26 | } 27 | 28 | func (c mockContext) GetRegion() string { 29 | return c.Region 30 | } 31 | 32 | func TestProvider_Local(t *testing.T) { 33 | 34 | ctx := mockContext{ 35 | App: "my-app", 36 | Env: "dev", 37 | Account: "123456789", 38 | Region: "us-east-1", 39 | } 40 | 41 | provider, err := GetProvider("local") 42 | if err != nil { 43 | t.Fail() 44 | } 45 | artifacts, err := provider.ProvideArtifacts(ctx) 46 | if err != nil { 47 | t.Fail() 48 | } 49 | if artifacts == nil { 50 | t.Fail() 51 | } 52 | if artifacts[0].FilePath != "build.sh" { 53 | t.Fail() 54 | } 55 | t.Log(artifacts[0].FileContents) 56 | 57 | image := fmt.Sprintf(`IMAGE="%v.dkr.ecr.us-east-1.amazonaws.com/%v:0.1.0"`, ctx.Account, ctx.App) 58 | if !strings.Contains(artifacts[0].FileContents, image) { 59 | t.Errorf("expecting " + image) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /cmd/build/provider.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | //Artifact represents a build artifact 10 | type Artifact struct { 11 | FilePath string 12 | FileContents string 13 | FileMode os.FileMode 14 | } 15 | 16 | //Context represents a build context 17 | type Context interface { 18 | GetApp() string 19 | GetEnvironment() string 20 | GetAccount() string 21 | GetRegion() string 22 | } 23 | 24 | type contextTemplate struct { 25 | App string 26 | Env string 27 | Account string 28 | Region string 29 | } 30 | 31 | func getContextTemplate(context Context) contextTemplate { 32 | return contextTemplate{ 33 | App: context.GetApp(), 34 | Env: context.GetEnvironment(), 35 | Account: context.GetAccount(), 36 | Region: context.GetRegion(), 37 | } 38 | } 39 | 40 | func createArtifact(filePath string, fileContents string) *Artifact { 41 | return &Artifact{ 42 | FilePath: filePath, 43 | FileContents: fileContents, 44 | FileMode: 0644, 45 | } 46 | } 47 | 48 | //Provider represents a build provider 49 | type Provider interface { 50 | ProvideArtifacts(context Context) ([]*Artifact, error) 51 | } 52 | 53 | //GetProvider returns a build provider based on its name 54 | func GetProvider(provider string) (Provider, error) { 55 | providerString := strings.ToLower(provider) 56 | 57 | if providerString == "local" { 58 | return Local{}, nil 59 | } 60 | 61 | if providerString == "circleciv2" { 62 | return CircleCIv2{}, nil 63 | } 64 | 65 | if providerString == "githubactions" { 66 | return GithubActions{}, nil 67 | } 68 | 69 | if providerString == "awscodebuild" { 70 | return AWSCodeBuild{}, nil 71 | } 72 | 73 | return nil, errors.New("build provider not supported: " + provider) 74 | } 75 | -------------------------------------------------------------------------------- /cmd/build/utils.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "text/tabwriter" 8 | "text/template" 9 | ) 10 | 11 | func check(e error) { 12 | if e != nil { 13 | log.Fatal("ERROR: ", e) 14 | } 15 | } 16 | 17 | func applyTemplate(textTemplate string, data interface{}) string { 18 | //create a formatted template 19 | buf := new(bytes.Buffer) 20 | w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', tabwriter.DiscardEmptyColumns) 21 | tmpl, err := template.New("t").Parse(textTemplate) 22 | check(err) 23 | fmt.Fprintln(w) 24 | 25 | //execute the template with the data 26 | err = tmpl.Execute(w, data) 27 | check(err) 28 | w.Flush() 29 | return buf.String() 30 | } 31 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/sts" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | const ( 16 | tempDir = "fargate-create-template" 17 | templateConfigFile = "fargate-create.yml" 18 | targetInfrastructureDir = "iac" 19 | varFormatHCL = ".tfvars" 20 | varFormatJSON = ".json" 21 | defaultTemplate = "git@github.com:turnerlabs/terraform-ecs-fargate" 22 | ) 23 | 24 | var verbose bool 25 | var varFile string 26 | var targetDir string 27 | var templateURL string 28 | var yesUseDefaults bool 29 | var context scaffoldContext 30 | 31 | var rootCmd = &cobra.Command{ 32 | Use: "fargate-create", 33 | Short: "Scaffold out new AWS ECS/Fargate applications based on Terraform templates and Fargate CLI", 34 | Run: run, 35 | PersistentPreRun: persistentPreRun, 36 | Example: ` 37 | # Scaffold an environment using the latest default template 38 | fargate-create 39 | 40 | # Do not prompt for options 41 | fargate-create -y 42 | 43 | # Use a template stored in github 44 | fargate-create -t git@github.com:turnerlabs/terraform-ecs-fargate?ref=v0.4.3 45 | 46 | # Scaffold out files for various build systems 47 | fargate-create build circleciv2 48 | 49 | # keep your template up to date 50 | fargate-create upgrade 51 | 52 | # Use a template stored in s3 53 | AWS_ACCESS_KEY=xyz AWS_SECRET_KEY=xyz AWS_REGION=us-east-1 \ 54 | fargate-create -t s3::https://s3.amazonaws.com/my-bucket/my-template 55 | 56 | # Use a template stored in your file system 57 | fargate-create -t ~/my-template 58 | 59 | # Use a specific input file 60 | fargate-create -f app.tfvars 61 | 62 | # Use a JSON input file 63 | fargate-create -f app.json 64 | `, 65 | } 66 | 67 | // Execute ... 68 | func Execute(version string) { 69 | rootCmd.Version = version 70 | rootCmd.Execute() 71 | } 72 | 73 | func init() { 74 | rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output") 75 | rootCmd.PersistentFlags().StringVarP(&varFile, "file", "f", "terraform.tfvars", "file specifying Terraform input variables, in either HCL or JSON format") 76 | rootCmd.PersistentFlags().StringVarP(&targetDir, "target-dir", "d", targetInfrastructureDir, "target directory where code is outputted") 77 | rootCmd.PersistentFlags().StringVarP(&templateURL, "template", "t", defaultTemplate, "URL of a compatible Terraform template") 78 | rootCmd.PersistentFlags().BoolVarP(&yesUseDefaults, "yes", "y", false, "don't ask questions and use defaults") 79 | } 80 | 81 | type scaffoldContext struct { 82 | App string 83 | Env string 84 | Profile string 85 | AccountID string 86 | Region string 87 | Format string 88 | ContainerPort string 89 | } 90 | 91 | func (context scaffoldContext) GetApp() string { 92 | return context.App 93 | } 94 | 95 | func (context scaffoldContext) GetEnvironment() string { 96 | return context.Env 97 | } 98 | 99 | func (context scaffoldContext) GetAccount() string { 100 | return context.AccountID 101 | } 102 | 103 | func (context scaffoldContext) GetRegion() string { 104 | return context.Region 105 | } 106 | 107 | //gets run before every command 108 | func persistentPreRun(cmd *cobra.Command, args []string) { 109 | 110 | if !(cmd.Name() == "fargate-create" || cmd.Name() == "build") { 111 | return 112 | } 113 | 114 | //validate that input varFile exists 115 | if _, err := os.Stat(varFile); os.IsNotExist(err) { 116 | fmt.Printf("Can't find %s. Use the --file flag to specify a .tfvars or .json file \n", varFile) 117 | os.Exit(-1) 118 | } 119 | 120 | //parse app, env, profile from input file 121 | fileBits, err := ioutil.ReadFile(varFile) 122 | check(err) 123 | varFormat := strings.ToLower(filepath.Ext(varFile)) 124 | app, env, profile, region, containerPort, err := parseInputVars(varFormat, string(fileBits)) 125 | check(err) 126 | fmt.Printf("scaffolding %s %s\n", app, env) 127 | 128 | //lookup aws account id using profile 129 | debug("looking up AWS Account ID") 130 | fmt.Println("Looking up AWS Account ID using profile: " + profile) 131 | accountID, err := getAWSAccountID(profile) 132 | if err != nil { 133 | fmt.Println() 134 | fmt.Printf("The following error occurred while looking up AWS Account ID using profile: \"%s\". Please make sure the profile %s exists in ~/.aws/credentials and has valid keys:", profile, profile) 135 | fmt.Println() 136 | fmt.Println() 137 | fmt.Println(err) 138 | os.Exit(-1) 139 | } 140 | 141 | //set context for scaffolder 142 | context = scaffoldContext{ 143 | App: app, 144 | Env: env, 145 | Profile: profile, 146 | Region: region, 147 | AccountID: accountID, 148 | Format: varFormat, 149 | ContainerPort: containerPort, 150 | } 151 | } 152 | 153 | func run(cmd *cobra.Command, args []string) { 154 | 155 | //scaffold out project environment 156 | scaffold(&context) 157 | 158 | fmt.Println() 159 | fmt.Println("done") 160 | } 161 | 162 | func getAWSAccountID(profile string) (string, error) { 163 | //call sts get-caller-identity 164 | os.Setenv("AWS_PROFILE", profile) 165 | svc := sts.New(session.New()) 166 | input := &sts.GetCallerIdentityInput{} 167 | result, err := svc.GetCallerIdentity(input) 168 | if err != nil { 169 | return "", err 170 | } 171 | return *result.Account, nil 172 | } 173 | -------------------------------------------------------------------------------- /cmd/scaffolder.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | getter "github.com/hashicorp/go-getter" 11 | yaml "gopkg.in/yaml.v2" 12 | ) 13 | 14 | type scaffoldTemplate struct { 15 | Base templateDirectory 16 | Env templateDirectory 17 | } 18 | 19 | type templateDirectory struct { 20 | Directory string 21 | Configuration *templateConfig 22 | Installed bool 23 | } 24 | 25 | const templateTypeService = "Service" 26 | const templateTypeScheduledTask = "ScheduledTask" 27 | const defaultTemplateType = templateTypeService 28 | const baseDir = "base" 29 | const envDir = "env" 30 | const devDir = "dev" 31 | 32 | type templateConfig struct { 33 | TemplateType string `yaml:"templateType"` 34 | Prompts []*prompt `yaml:"prompts"` 35 | } 36 | 37 | type prompt struct { 38 | Question string `yaml:"question"` 39 | Default string `yaml:"default"` 40 | FilesToDeleteIfNo []string `yaml:"filesToDeleteIfNo"` 41 | } 42 | 43 | func scaffold(context *scaffoldContext) { 44 | 45 | //scaffold out infrastructure files 46 | template := scaffoldInfrastructure(context) 47 | 48 | //scaffold application files 49 | scaffoldApplication(context, template) 50 | 51 | //apply any template configurations 52 | applyTemplateConfiguration(template.Base) 53 | applyTemplateConfiguration(template.Env) 54 | } 55 | 56 | func applyTemplateConfiguration(t templateDirectory) { 57 | if t.Configuration != nil { 58 | for _, prompt := range t.Configuration.Prompts { 59 | //if -y, use defaults, otherwise prompt 60 | response := prompt.Default 61 | if !yesUseDefaults { 62 | fmt.Println() 63 | q := fmt.Sprintf("%s (%s) ", prompt.Question, prompt.Default) 64 | response = promptAndGetResponse(q, prompt.Default) 65 | } 66 | yes := containsString(okayResponses, response) 67 | if !yes && prompt.FilesToDeleteIfNo != nil { 68 | for _, file := range prompt.FilesToDeleteIfNo { 69 | p := filepath.Join(t.Directory, file) 70 | fmt.Println("deleting ", p) 71 | err := os.Remove(p) 72 | check(err) 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | func scaffoldInfrastructure(context *scaffoldContext) *scaffoldTemplate { 80 | 81 | //fetch terraform template 82 | templateDir := downloadTerraformTemplate() 83 | debug("downloaded to:", templateDir) 84 | 85 | result := installTerraformTemplate(templateDir, context.Env) 86 | debug("environment installed to:", result.Env.Directory) 87 | 88 | //copy var file into base module 89 | if result.Base.Installed { 90 | debug(fmt.Sprintf("copying %s to %s", varFile, result.Base.Directory)) 91 | targetFile := getTargetVarFile(context.Format) 92 | err := copyFile(varFile, filepath.Join(result.Base.Directory, targetFile)) 93 | check(err) 94 | } 95 | 96 | //copy var file into environment module 97 | debug(fmt.Sprintf("copying %s to %s", varFile, result.Env.Directory)) 98 | targetFile := getTargetVarFile(context.Format) 99 | err := copyFile(varFile, filepath.Join(result.Env.Directory, targetFile)) 100 | check(err) 101 | 102 | //update tf backend in main.tf to match app/env 103 | transformMainTFToContext(result.Env.Directory, context.Profile, context.App, context.Env, context.Region) 104 | 105 | return result 106 | } 107 | 108 | func transformMainTFToContext(dir string, profile string, app string, env string, region string) { 109 | mainTfFile := filepath.Join(dir, "main.tf") 110 | fileBits, err := ioutil.ReadFile(mainTfFile) 111 | check(err) 112 | maintf := updateTerraformBackend(string(fileBits), profile, app, env, region) 113 | err = ioutil.WriteFile(mainTfFile, []byte(maintf), 0644) 114 | check(err) 115 | } 116 | 117 | //fetches and installs the tf template and returns the output directory 118 | func downloadTerraformTemplate() string { 119 | 120 | client := getter.Client{ 121 | Src: templateURL, 122 | Dst: "./" + tempDir, 123 | Mode: getter.ClientModeAny, 124 | } 125 | 126 | fmt.Println("downloading terraform template", templateURL) 127 | err := client.Get() 128 | check(err) 129 | debug("done") 130 | 131 | return tempDir 132 | } 133 | 134 | //installs a template for the specified environment and returns a scaffoldTemplate 135 | func installTerraformTemplate(templateDir string, environment string) *scaffoldTemplate { 136 | 137 | result := scaffoldTemplate{ 138 | Base: templateDirectory{}, 139 | Env: templateDirectory{}, 140 | } 141 | 142 | //create infrastructure directory (if not already there) 143 | targetInfraDir := targetDir 144 | fmt.Println("installing terraform template") 145 | if _, err := os.Stat(targetInfraDir); os.IsNotExist(err) { 146 | debug("creating directory:", targetInfraDir) 147 | err = os.MkdirAll(targetInfraDir, 0755) 148 | check(err) 149 | } else { 150 | debug(targetInfraDir + " already exists") 151 | } 152 | 153 | //copy over infrastructure/base (if not already there) 154 | sourceBaseDir := filepath.Join(templateDir, baseDir) 155 | destBaseDir := filepath.Join(targetInfraDir, baseDir) 156 | if _, err := os.Stat(destBaseDir); os.IsNotExist(err) { 157 | debug(fmt.Sprintf("copying %s to %s", sourceBaseDir, destBaseDir)) 158 | err = copyDir(sourceBaseDir, destBaseDir) 159 | check(err) 160 | 161 | result.Base.Installed = true 162 | result.Base.Directory = destBaseDir 163 | 164 | //does template contain a fargate-create.yml config? is so, load it 165 | result.Base.Configuration = loadTemplateConfig(result.Base.Directory) 166 | 167 | } else { 168 | fmt.Println(destBaseDir + " already exists, ignoring") 169 | } 170 | 171 | //if environment directory exists, prompt to override, if no, then exit 172 | sourceEnvDir := filepath.Join(templateDir, envDir, devDir) 173 | destEnvDir := filepath.Join(targetInfraDir, envDir, environment) 174 | 175 | yes := true 176 | if _, err := os.Stat(destEnvDir); err == nil { 177 | //exists 178 | fmt.Print(destEnvDir + " already exists. Overwrite? ") 179 | if yes = askForConfirmation(); yes { 180 | debug("deleting", destEnvDir) 181 | //delete environment directory (all files) 182 | err = os.RemoveAll(destEnvDir) 183 | check(err) 184 | } 185 | } else { 186 | //doesn't exist 187 | debug(destEnvDir + " doesn't exist") 188 | } 189 | 190 | if yes { 191 | //env directory either doesn't exist or user wants to overwrite 192 | //copy repo/env/${env} -> ./infrastructure/env/${env} 193 | debug(fmt.Sprintf("copying %s to %s", sourceEnvDir, destEnvDir)) 194 | err := copyDir(sourceEnvDir, destEnvDir) 195 | check(err) 196 | 197 | result.Env.Installed = true 198 | result.Env.Directory = destEnvDir 199 | 200 | //does template contain a fargate-create.yml config? is so, load it 201 | result.Env.Configuration = loadTemplateConfig(result.Env.Directory) 202 | } 203 | 204 | // finally, delete temp dir 205 | debug("deleting:", tempDir) 206 | err := os.RemoveAll(tempDir) 207 | check(err) 208 | 209 | return &result 210 | } 211 | 212 | func loadTemplateConfig(dir string) *templateConfig { 213 | configFile := filepath.Join(dir, templateConfigFile) 214 | var config templateConfig 215 | if _, err := os.Stat(configFile); !os.IsNotExist(err) { 216 | debug("found template config: ", dir) 217 | //load yaml 218 | dat, err := ioutil.ReadFile(configFile) 219 | check(err) 220 | err = yaml.Unmarshal(dat, &config) 221 | check(err) 222 | 223 | //default template type 224 | if config.TemplateType == "" { 225 | config.TemplateType = defaultTemplateType 226 | } 227 | } else { 228 | debug("didn't find template config: ", dir) 229 | return nil 230 | } 231 | return &config 232 | } 233 | 234 | func getTargetVarFile(format string) string { 235 | targetFile := "" 236 | if format == varFormatHCL { 237 | targetFile = "terraform.tfvars" 238 | } 239 | if format == varFormatJSON { 240 | targetFile = "terraform.tfvars.json" 241 | } 242 | return targetFile 243 | } 244 | 245 | func scaffoldApplication(context *scaffoldContext, t *scaffoldTemplate) { 246 | 247 | //write the application files to the env directory 248 | targetAppDir := t.Env.Directory 249 | 250 | //write a docker-compose.yml file 251 | dockerComposeYml := getDockerComposeYml(context) 252 | dockerComposeYmlFile := filepath.Join(targetAppDir, "docker-compose.yml") 253 | debug("writing", dockerComposeYmlFile) 254 | err := ioutil.WriteFile(dockerComposeYmlFile, []byte(dockerComposeYml), 0644) 255 | check(err) 256 | 257 | //write hidden.env 258 | hiddenEnvFileName := filepath.Join(targetAppDir, "hidden.env") 259 | sampleContents := "#FOO=bar\n" 260 | err = ioutil.WriteFile(hiddenEnvFileName, []byte(sampleContents), 0644) 261 | check(err) 262 | 263 | //write a fargate.yml for the cli 264 | fargateYml := getFargateYaml(context, t.Env.Configuration) 265 | fargateYmlFile := filepath.Join(targetAppDir, "fargate.yml") 266 | debug("writing", fargateYmlFile) 267 | err = ioutil.WriteFile(fargateYmlFile, []byte(fargateYml), 0644) 268 | check(err) 269 | 270 | //write deploy.sh 271 | deployScript := getDeployScript(context, t.Env.Configuration) 272 | deployScriptFile := filepath.Join(targetAppDir, "deploy.sh") 273 | debug("writing", deployScriptFile) 274 | err = ioutil.WriteFile(deployScriptFile, []byte(deployScript), 0755) 275 | check(err) 276 | 277 | //ignored files 278 | hiddenenv := strings.Split(hiddenEnvFileName, "/") 279 | ignoredFiles := []string{hiddenenv[len(hiddenenv)-1], ".terraform"} 280 | ensureFileContains(".gitignore", ignoredFiles) 281 | ensureFileContains(".dockerignore", ignoredFiles) 282 | } 283 | 284 | func getFargateYaml(context *scaffoldContext, config *templateConfig) string { 285 | textTemplate := `cluster: {{.App}}-{{.Env}} 286 | service: {{.App}}-{{.Env}}` 287 | if config.TemplateType == templateTypeScheduledTask { 288 | textTemplate += ` 289 | task: {{.App}}-{{.Env}} 290 | rule: {{.App}}-{{.Env}} 291 | ` 292 | } 293 | return applyTemplate(textTemplate, context) 294 | } 295 | 296 | func getDockerComposeYml(context *scaffoldContext) string { 297 | 298 | //only add docker ports if container_port context variable is specified 299 | var t string 300 | if context.ContainerPort != "" { 301 | t = `version: "3.7" 302 | services: 303 | {{.App}}: 304 | build: ../../../ 305 | image: {{.AccountID}}.dkr.ecr.{{.Region}}.amazonaws.com/{{.App}}:0.1.0 306 | ports: 307 | - {{.ContainerPort}}:{{.ContainerPort}} 308 | env_file: 309 | - hidden.env 310 | labels: 311 | aws.ecs.fargate.deploy: 1 312 | #x-fargate-secrets: 313 | #KEY: value 314 | ` 315 | } else { 316 | t = `version: "3.7" 317 | services: 318 | {{.App}}: 319 | build: ../../../ 320 | image: {{.AccountID}}.dkr.ecr.{{.Region}}.amazonaws.com/{{.App}}:0.1.0 321 | env_file: 322 | - hidden.env 323 | labels: 324 | aws.ecs.fargate.deploy: 1 325 | #x-fargate-secrets: 326 | #KEY: value 327 | ` 328 | } 329 | return applyTemplate(t, context) 330 | } 331 | 332 | func getDeployScript(context *scaffoldContext, config *templateConfig) string { 333 | t := `#!/bin/bash 334 | set -e 335 | 336 | # build image 337 | docker-compose build 338 | 339 | export AWS_PROFILE={{.Profile}} 340 | export AWS_DEFAULT_REGION={{.Region}} 341 | 342 | # login to ECR 343 | version=$(aws --version | awk -F'[/.]' '{print $2}') 344 | if [ $version -eq "1" ]; then 345 | login=$(aws ecr get-login --no-include-email) && eval "$login" 346 | else 347 | aws ecr get-login-password | docker login --username AWS --password-stdin {{.AccountID}}.dkr.ecr.{{.Region}}.amazonaws.com 348 | fi 349 | 350 | # push image to ECR repo 351 | docker-compose push` 352 | 353 | if config.TemplateType == templateTypeService { 354 | t += ` 355 | # deploy image and env vars 356 | fargate service deploy -f docker-compose.yml 357 | ` 358 | } else if config.TemplateType == templateTypeScheduledTask { 359 | t += ` 360 | # deploy image and env vars 361 | REVISION=$(fargate task register -f docker-compose.yml) 362 | fargate events target -r ${REVISION} 363 | ` 364 | } 365 | 366 | return applyTemplate(t, context) 367 | } 368 | -------------------------------------------------------------------------------- /cmd/scaffolder_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | const tmpDir = "./tmptest" 12 | 13 | func TestIgnoreSensitiveFiles_New(t *testing.T) { 14 | 15 | //arrange 16 | teardownTestCase := setupTestCase(t) 17 | defer teardownTestCase(t) 18 | file := filepath.Join(tmpDir, ".gitignore") 19 | 20 | //act 21 | ignored := []string{"foo"} 22 | ensureFileContains(file, ignored) 23 | 24 | //assert 25 | //fail if file doesn't contain 1 instance of foo 26 | dat, err := ioutil.ReadFile(file) 27 | if err != nil { 28 | t.Error(err) 29 | } 30 | contents := string(dat) 31 | t.Log(contents) 32 | if strings.Count(contents, "foo") != 1 { 33 | t.Error("expecting 1 occurance of foo") 34 | } 35 | } 36 | 37 | func TestIgnoreSensitiveFiles_Existing(t *testing.T) { 38 | 39 | //arrange 40 | teardownTestCase := setupTestCase(t) 41 | defer teardownTestCase(t) 42 | file := filepath.Join(tmpDir, ".gitignore") 43 | 44 | //create .gitignore with existing entry 45 | d1 := []byte("foo\nbar") 46 | err := ioutil.WriteFile(file, d1, 0644) 47 | if err != nil { 48 | t.Error(err) 49 | } 50 | 51 | //test 52 | ignored := []string{"foo"} 53 | ensureFileContains(file, ignored) 54 | 55 | //assert 56 | //fail if file doesn't contain 1 instance of foo 57 | dat, err := ioutil.ReadFile(file) 58 | if err != nil { 59 | t.Error(err) 60 | } 61 | contents := string(dat) 62 | t.Log(contents) 63 | if strings.Count(contents, "foo") != 1 { 64 | t.Error("expecting 1 occurance of foo") 65 | } 66 | } 67 | 68 | func TestIgnoreSensitiveFiles_Existing_Multiple(t *testing.T) { 69 | 70 | //arrange 71 | teardownTestCase := setupTestCase(t) 72 | defer teardownTestCase(t) 73 | file := filepath.Join(tmpDir, ".gitignore") 74 | 75 | //create .gitignore with existing entry 76 | d1 := []byte("foo\nbar") 77 | err := ioutil.WriteFile(file, d1, 0644) 78 | if err != nil { 79 | t.Error(err) 80 | } 81 | 82 | //test 83 | ignored := []string{"foo", "baz"} 84 | ensureFileContains(file, ignored) 85 | 86 | //assert 87 | //fail if file doesn't contain 1 instance of foo 88 | dat, err := ioutil.ReadFile(file) 89 | if err != nil { 90 | t.Error(err) 91 | } 92 | contents := string(dat) 93 | t.Log(contents) 94 | if strings.Count(contents, "foo") != 1 { 95 | t.Error("expecting 1 occurance of foo") 96 | } 97 | if strings.Count(contents, "bar") != 1 { 98 | t.Error("expecting 1 occurance of bar") 99 | } 100 | if strings.Count(contents, "baz") != 1 { 101 | t.Error("expecting 1 occurance of baz") 102 | } 103 | } 104 | 105 | func setupTestCase(t *testing.T) func(t *testing.T) { 106 | t.Log("setup test case") 107 | 108 | //create tmpDir 109 | err := os.MkdirAll(tmpDir, 0755) 110 | if err != nil { 111 | t.Error("error creating", tmpDir) 112 | } 113 | 114 | return func(t *testing.T) { 115 | t.Log("teardown test case") 116 | 117 | //delete 118 | os.RemoveAll(tmpDir) 119 | } 120 | } 121 | 122 | func TestDockerComposeYml_Port(t *testing.T) { 123 | 124 | context := scaffoldContext{ 125 | AccountID: "abc", 126 | App: "my-app", 127 | ContainerPort: "3000", 128 | Env: "dev", 129 | Profile: "default", 130 | Region: "us-east-1", 131 | Format: ".tfvars", 132 | } 133 | 134 | yml := getDockerComposeYml(&context) 135 | t.Log(yml) 136 | 137 | expected := "- 3000:3000" 138 | if !strings.Contains(yml, expected) { 139 | t.Errorf("expected: %s; actual: %s", expected, yml) 140 | } 141 | } 142 | 143 | func TestDockerComposeYml_NoPort(t *testing.T) { 144 | 145 | context := scaffoldContext{ 146 | AccountID: "abc", 147 | App: "my-app", 148 | ContainerPort: "", 149 | Env: "dev", 150 | Profile: "default", 151 | Region: "us-east-1", 152 | Format: ".tfvars", 153 | } 154 | 155 | yml := getDockerComposeYml(&context) 156 | t.Log(yml) 157 | 158 | notexpected := "ports:" 159 | if strings.Contains(yml, notexpected) { 160 | t.Errorf("not expected: %s; actual: %s", notexpected, yml) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /cmd/terraform.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | ) 9 | 10 | func parseInputVars(format string, input string) (string, string, string, string, string, error) { 11 | if format == varFormatHCL { 12 | return parseInputVarsHCL(input) 13 | } 14 | if format == varFormatJSON { 15 | return parseInputVarsJSON(input) 16 | } 17 | return "", "", "", "", "", errors.New(`unknown var format: "` + format + `"`) 18 | } 19 | 20 | func parseInputVarsJSON(input string) (string, string, string, string, string, error) { 21 | var data map[string]interface{} 22 | 23 | err := json.Unmarshal([]byte(input), &data) 24 | check(err) 25 | 26 | app := data["app"].(string) 27 | environment := data["environment"].(string) 28 | profile := data["aws_profile"].(string) 29 | region := data["region"].(string) 30 | containerPort := data["container_port"].(string) 31 | 32 | //did we find it? 33 | if app == "" { 34 | return "", "", "", "", "", errors.New(`missing variable: "app"`) 35 | } 36 | if environment == "" { 37 | return "", "", "", "", "", errors.New(`missing variable: "environment"`) 38 | } 39 | if profile == "" { 40 | return "", "", "", "", "", errors.New(`missing variable: "profile"`) 41 | } 42 | if region == "" { 43 | return "", "", "", "", "", errors.New(`missing variable: "region"`) 44 | } 45 | 46 | return app, environment, profile, region, containerPort, nil 47 | } 48 | 49 | func parseInputVarsHCL(tf string) (string, string, string, string, string, error) { 50 | app := "" 51 | environment := "" 52 | profile := "" 53 | region := "" 54 | containerPort := "" 55 | 56 | //look for variables 57 | lines := strings.Split(tf, "\n") 58 | inTags := false 59 | for _, line := range lines { 60 | trimmed := strings.TrimSpace(line) 61 | //ignore whitespace and comments 62 | if trimmed == "" || strings.HasPrefix(trimmed, "//") || strings.HasPrefix(trimmed, "#") { 63 | continue 64 | } 65 | if trimmed == "tags = {" { 66 | inTags = true 67 | continue 68 | } 69 | if inTags { 70 | if trimmed == "}" { 71 | inTags = false 72 | } 73 | continue 74 | } 75 | //key = "value" 76 | parts := strings.Split(trimmed, "=") 77 | if len(parts) == 2 { 78 | key := strings.TrimSpace(parts[0]) 79 | value := strings.TrimSpace(parts[1]) 80 | 81 | //remove quotes (app = "foo") 82 | value = strings.Replace(value, `"`, "", -1) 83 | 84 | //remove trailing comments (app = "foo" #comment) 85 | comments := strings.Split(value, "#") 86 | value = strings.TrimSpace(comments[0]) 87 | 88 | if key == "app" { 89 | app = value 90 | } 91 | if key == "environment" { 92 | environment = value 93 | } 94 | if key == "aws_profile" { 95 | profile = value 96 | } 97 | if key == "region" { 98 | region = value 99 | } 100 | if key == "container_port" { 101 | containerPort = value 102 | } 103 | } 104 | } 105 | 106 | //did we find it? 107 | if app == "" { 108 | return "", "", "", "", "", errors.New(`missing variable: "app"`) 109 | } 110 | if environment == "" { 111 | return "", "", "", "", "", errors.New(`missing variable: "environment"`) 112 | } 113 | if profile == "" { 114 | return "", "", "", "", "", errors.New(`missing variable: "profile"`) 115 | } 116 | if region == "" { 117 | return "", "", "", "", "", errors.New(`missing variable: "region"`) 118 | } 119 | 120 | return app, environment, profile, region, containerPort, nil 121 | } 122 | 123 | func updateTerraformBackend(tf string, profile string, app string, env string, region string) string { 124 | //update terraform.backend (which doesn't support dynamic variables) 125 | // profile = "" 126 | // bucket = "" 127 | // key = "dev.terraform.tfstate" 128 | tmp := strings.Split(tf, "\n") 129 | newTf := "" 130 | for _, line := range tmp { 131 | updatedLine := line 132 | trimmed := strings.TrimSpace(line) 133 | if strings.HasPrefix(trimmed, `profile = ""`) { 134 | updatedLine = fmt.Sprintf(` profile = "%s"`, profile) 135 | } 136 | if strings.HasPrefix(trimmed, "bucket") { 137 | updatedLine = fmt.Sprintf(` bucket = "tf-state-%s"`, app) 138 | } 139 | if strings.HasPrefix(trimmed, "key") { 140 | updatedLine = fmt.Sprintf(` key = "%s.terraform.tfstate"`, env) 141 | } 142 | if strings.HasPrefix(trimmed, "region") { 143 | updatedLine = fmt.Sprintf(` region = "%s"`, region) 144 | } 145 | 146 | newTf += updatedLine + "\n" 147 | } 148 | return newTf 149 | } 150 | -------------------------------------------------------------------------------- /cmd/terraform_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestUpdateTerraformBackend(t *testing.T) { 10 | 11 | tf := ` 12 | terraform { 13 | backend "s3" { 14 | region = "us-east-1" 15 | profile = "" 16 | bucket = "" 17 | key = "dev.terraform.tfstate" 18 | } 19 | } 20 | 21 | provider "aws" { 22 | region = "${var.region}" 23 | profile = "${var.aws_profile}" 24 | } 25 | ` 26 | 27 | profile := "my-profile" 28 | app := "my-app" 29 | env := "qa" 30 | region := "us-east-1" 31 | result := updateTerraformBackend(tf, profile, app, env, region) 32 | t.Log(result) 33 | 34 | expected := fmt.Sprintf(`profile = "%s"`, profile) 35 | if !strings.Contains(result, expected) { 36 | t.Errorf("expected: %s; actual: %s", expected, result) 37 | } 38 | expected = fmt.Sprintf(`bucket = "tf-state-%s"`, app) 39 | if !strings.Contains(result, expected) { 40 | t.Errorf("expected: %s; actual: %s", expected, result) 41 | } 42 | } 43 | 44 | func TestUpdateTerraformBackend_Region(t *testing.T) { 45 | 46 | tf := ` 47 | terraform { 48 | backend "s3" { 49 | region = "us-east-1" 50 | profile = "" 51 | bucket = "" 52 | key = "dev.terraform.tfstate" 53 | } 54 | } 55 | 56 | provider "aws" { 57 | region = "${var.region}" 58 | profile = "${var.aws_profile}" 59 | } 60 | ` 61 | 62 | profile := "my-profile" 63 | app := "my-app" 64 | env := "qa" 65 | region := "us-west-1" 66 | result := updateTerraformBackend(tf, profile, app, env, region) 67 | t.Log(result) 68 | 69 | expected := fmt.Sprintf(`profile = "%s"`, profile) 70 | if !strings.Contains(result, expected) { 71 | t.Errorf("expected: %s; actual: %s", expected, result) 72 | } 73 | expected = fmt.Sprintf(`bucket = "tf-state-%s"`, app) 74 | if !strings.Contains(result, expected) { 75 | t.Errorf("expected: %s; actual: %s", expected, result) 76 | } 77 | expected = fmt.Sprintf(`region = "%s"`, region) 78 | if !strings.Contains(result, expected) { 79 | t.Errorf("expected: %s; actual: %s", expected, result) 80 | } 81 | } 82 | 83 | 84 | func TestParseInputVars(t *testing.T) { 85 | 86 | tf := ` 87 | region = "us-east-2" 88 | 89 | aws_profile = "default" 90 | 91 | saml_role = "devops" 92 | 93 | app = "my-app" 94 | 95 | environment = "qa" 96 | 97 | container_port = "8080" 98 | 99 | tags = { 100 | application = "" 101 | environment = "dev" 102 | team = "" 103 | customer = "" 104 | contact-email = "" 105 | } 106 | 107 | internal = "true" 108 | ` 109 | app, env, profile, region, containerPort, err := parseInputVars(varFormatHCL, tf) 110 | 111 | t.Log(app) 112 | t.Log(env) 113 | t.Log(profile) 114 | t.Log(region) 115 | t.Log(containerPort) 116 | if err != nil { 117 | t.Error(err) 118 | } 119 | 120 | expected := "my-app" 121 | if app != expected { 122 | t.Errorf("expected: %s; actual: %s", expected, app) 123 | } 124 | expected = "qa" 125 | if env != expected { 126 | t.Errorf("expected: %s; actual: %s", expected, env) 127 | } 128 | expected = "default" 129 | if profile != expected { 130 | t.Errorf("expected: %s; actual: %s", expected, profile) 131 | } 132 | expected = "us-east-2" 133 | if region != expected { 134 | t.Errorf("expected: %s; actual: %s", expected, profile) 135 | } 136 | expected = "8080" 137 | if containerPort != expected { 138 | t.Errorf("expected: %s; actual: %s", containerPort, profile) 139 | } 140 | } 141 | 142 | func TestParseInputVars_OptionalContainerPort(t *testing.T) { 143 | 144 | tf := ` 145 | region = "us-east-2" 146 | 147 | aws_profile = "default" 148 | 149 | saml_role = "devops" 150 | 151 | app = "my-app" 152 | 153 | environment = "qa" 154 | 155 | tags = { 156 | application = "" 157 | environment = "dev" 158 | team = "" 159 | customer = "" 160 | contact-email = "" 161 | } 162 | 163 | internal = "true" 164 | ` 165 | app, env, profile, region, containerPort, err := parseInputVars(varFormatHCL, tf) 166 | 167 | t.Log(app) 168 | t.Log(env) 169 | t.Log(profile) 170 | t.Log(region) 171 | t.Log(containerPort) 172 | if err != nil { 173 | t.Error(err) 174 | } 175 | 176 | expected := "my-app" 177 | if app != expected { 178 | t.Errorf("expected: %s; actual: %s", expected, app) 179 | } 180 | expected = "qa" 181 | if env != expected { 182 | t.Errorf("expected: %s; actual: %s", expected, env) 183 | } 184 | expected = "default" 185 | if profile != expected { 186 | t.Errorf("expected: %s; actual: %s", expected, profile) 187 | } 188 | expected = "us-east-2" 189 | if region != expected { 190 | t.Errorf("expected: %s; actual: %s", expected, profile) 191 | } 192 | expected = "" 193 | if containerPort != expected { 194 | t.Errorf("expected: %s; actual: %s", containerPort, profile) 195 | } 196 | } 197 | 198 | func TestParseInputVars_comments(t *testing.T) { 199 | 200 | tf := ` 201 | region = "us-east-2" 202 | 203 | aws_profile = "default" 204 | 205 | saml_role = "devops" 206 | 207 | app = "my-app" #comment 208 | 209 | environment = "qa" 210 | 211 | tags = { 212 | application = "" 213 | environment = "dev" 214 | team = "" 215 | customer = "" 216 | contact-email = "" 217 | } 218 | 219 | internal = "true" 220 | ` 221 | app, env, profile, region, _, err := parseInputVars(varFormatHCL, tf) 222 | 223 | t.Log(app) 224 | t.Log(env) 225 | t.Log(profile) 226 | t.Log(region) 227 | if err != nil { 228 | t.Error(err) 229 | } 230 | 231 | expected := "my-app" 232 | if app != expected { 233 | t.Errorf("expected: %s; actual: %s", expected, app) 234 | } 235 | expected = "qa" 236 | if env != expected { 237 | t.Errorf("expected: %s; actual: %s", expected, env) 238 | } 239 | expected = "default" 240 | if profile != expected { 241 | t.Errorf("expected: %s; actual: %s", expected, profile) 242 | } 243 | expected = "us-east-2" 244 | if region != expected { 245 | t.Errorf("expected: %s; actual: %s", expected, profile) 246 | } 247 | } 248 | 249 | func TestParseInputVars_JSON(t *testing.T) { 250 | 251 | tf := `{ 252 | "region": "us-east-2", 253 | "aws_profile": "default", 254 | "saml_role": "devops", 255 | "app": "my-app", 256 | "environment": "qa", 257 | "container_port": "8080", 258 | "tags": { 259 | "application": "", 260 | "environment": "dev", 261 | "team": "", 262 | "customer": "", 263 | "contact-email": "" 264 | }, 265 | "internal": true 266 | } 267 | ` 268 | app, env, profile, region, containerPort, err := parseInputVars(varFormatJSON, tf) 269 | 270 | t.Log(app) 271 | t.Log(env) 272 | t.Log(profile) 273 | t.Log(region) 274 | t.Log(containerPort) 275 | if err != nil { 276 | t.Error(err) 277 | } 278 | 279 | expected := "my-app" 280 | if app != expected { 281 | t.Errorf("expected: %s; actual: %s", expected, app) 282 | } 283 | expected = "qa" 284 | if env != expected { 285 | t.Errorf("expected: %s; actual: %s", expected, env) 286 | } 287 | expected = "default" 288 | if profile != expected { 289 | t.Errorf("expected: %s; actual: %s", expected, profile) 290 | } 291 | expected = "us-east-2" 292 | if region != expected { 293 | t.Errorf("expected: %s; actual: %s", expected, profile) 294 | } 295 | expected = "8080" 296 | if containerPort != expected { 297 | t.Errorf("expected: %s; actual: %s", expected, profile) 298 | } 299 | 300 | } 301 | -------------------------------------------------------------------------------- /cmd/upgrade.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "log" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | var upgradeYes bool 18 | 19 | var upgradeCmd = &cobra.Command{ 20 | Use: "upgrade", 21 | Short: "Keep a terraform template up to date", 22 | Run: doUpgrade, 23 | Example: ` 24 | fargate-create upgrade 25 | fargate-create upgrade -t git@github.com:turnerlabs/terraform-ecs-fargate-scheduled-task 26 | fargate-create upgrade -d infrastructure 27 | `, 28 | } 29 | 30 | func init() { 31 | rootCmd.AddCommand(upgradeCmd) 32 | } 33 | 34 | func doUpgrade(cmd *cobra.Command, args []string) { 35 | 36 | //has the user done a previous install? 37 | notFound := false 38 | if _, err := os.Stat(filepath.Join(targetDir, baseDir)); err != nil { 39 | notFound = true 40 | } 41 | if _, err := os.Stat(filepath.Join(targetDir, envDir)); err != nil { 42 | notFound = true 43 | } 44 | if notFound { 45 | check(errors.New("no existing template found")) 46 | } 47 | 48 | //fetch the template from the source 49 | templateDir := downloadTerraformTemplate() 50 | debug("downloaded to:", templateDir) 51 | 52 | //process /base first, then iterate over /env 53 | srcDir := filepath.Join(templateDir, baseDir) 54 | destDir := filepath.Join(targetDir, baseDir) 55 | adds, updates := upgradeDirectory(srcDir, destDir) 56 | 57 | //process each installed environment 58 | srcDir = filepath.Join(templateDir, envDir, devDir) 59 | objects, err := ioutil.ReadDir(filepath.Join(targetDir, envDir)) 60 | check(err) 61 | for _, o := range objects { 62 | if o.IsDir() { 63 | destDir = filepath.Join(targetDir, envDir, o.Name()) 64 | debug(destDir) 65 | 66 | //look for default terraform.tfvars file for this environment 67 | tfVarsFile := filepath.Join(destDir, "terraform.tfvars") 68 | debug(tfVarsFile) 69 | if _, err = os.Stat(tfVarsFile); os.IsNotExist(err) { 70 | check(errors.New(tfVarsFile + " not found")) 71 | } 72 | 73 | fileBits, err := ioutil.ReadFile(tfVarsFile) 74 | check(err) 75 | varFormat := strings.ToLower(filepath.Ext(tfVarsFile)) 76 | app, env, profile, region, _, err := parseInputVars(varFormat, string(fileBits)) 77 | check(err) 78 | 79 | //apply env transformation in src before upgrading 80 | transformMainTFToContext(srcDir, profile, app, env, region) 81 | 82 | //upgrade env directory 83 | a, u := upgradeDirectory(srcDir, destDir) 84 | adds = append(adds, a...) 85 | updates = append(updates, u...) 86 | } 87 | } 88 | 89 | //delete download dir 90 | os.RemoveAll(templateDir) 91 | 92 | fmt.Println() 93 | fmt.Println("---------------------------------------") 94 | fmt.Printf("upgrade complete: %v add(s), %v update(s)\n", len(adds), len(updates)) 95 | if len(adds) > 0 || len(updates) > 0 { 96 | fmt.Println() 97 | fmt.Println("updated files:") 98 | fmt.Println() 99 | for _, s := range updates { 100 | fmt.Printf("\t%s\n", s) 101 | } 102 | fmt.Println() 103 | fmt.Println("added files:") 104 | fmt.Println() 105 | for _, s := range adds { 106 | fmt.Printf("\t%s\n", s) 107 | } 108 | fmt.Println() 109 | fmt.Println(`run the following commands to apply these changes: 110 | terraform init -upgrade=true 111 | terraform apply`) 112 | } 113 | } 114 | 115 | func upgradeDirectory(srcDir string, destDir string) ([]string, []string) { 116 | 117 | //prompt for updates to existing local files 118 | //add new required files 119 | //prompt to add new optional files (using fargate-create.yml) 120 | 121 | fmt.Println() 122 | fmt.Println("---------------------------------------") 123 | fmt.Println("upgrading", destDir) 124 | fmt.Println("---------------------------------------") 125 | 126 | updates := []string{} 127 | adds := []string{} 128 | 129 | //iterate src files 130 | files, err := ioutil.ReadDir(srcDir) 131 | check(err) 132 | for _, f := range files { 133 | file := f.Name() 134 | debug(file) 135 | 136 | //only process .tf or .md files 137 | if !(strings.HasSuffix(file, ".tf") || strings.HasSuffix(file, ".md") || strings.HasSuffix(file, ".tpl")) { 138 | continue 139 | } 140 | 141 | //does matching file in template exist? 142 | source := filepath.Join(srcDir, file) 143 | dest := filepath.Join(destDir, file) 144 | debug(fmt.Sprintf("source: %s | dest: %s", source, dest)) 145 | 146 | //can we access the source file? 147 | if _, err := os.Stat(source); err == nil { 148 | 149 | //does corresponding dest file exist? 150 | if _, err = os.Stat(dest); os.IsNotExist(err) { 151 | debug("new source file") 152 | 153 | //is this file required or optional? 154 | //load template config file 155 | templateConfig := loadTemplateConfig(srcDir) 156 | if templateConfig != nil { 157 | prompt := getFilePrompt(templateConfig, file) 158 | if prompt != nil { 159 | //prompt to install new optional file 160 | fmt.Println() 161 | q := fmt.Sprintf("%s (%s) ", prompt.Question, prompt.Default) 162 | response := promptAndGetResponse(q, prompt.Default) 163 | if containsString(okayResponses, response) { 164 | err = copyFile(source, dest) 165 | check(err) 166 | adds = append(adds, dest) 167 | } 168 | } else { 169 | //write new required file 170 | fmt.Println("writing", dest) 171 | copyFile(source, dest) 172 | adds = append(adds, dest) 173 | } 174 | } else { 175 | debug("no template config file found") 176 | } 177 | } else { 178 | //does dest file need updating? 179 | debug("diffing") 180 | if !deepCompare(source, dest) { 181 | fmt.Println() 182 | response := promptAndGetResponse(dest+" is out of date. Replace? (yes) ", "yes") 183 | if containsString(okayResponses, response) { 184 | err = copyFile(source, dest) 185 | check(err) 186 | updates = append(updates, dest) 187 | } 188 | } else { 189 | debug("files match") 190 | } 191 | } 192 | } 193 | } 194 | return adds, updates 195 | } 196 | 197 | func getFilePrompt(config *templateConfig, file string) *prompt { 198 | for _, p := range config.Prompts { 199 | for _, f := range p.FilesToDeleteIfNo { 200 | if f == file { 201 | return p 202 | } 203 | } 204 | } 205 | return nil 206 | } 207 | 208 | func deepCompare(file1, file2 string) bool { 209 | chunkSize := 4000 210 | 211 | f1, err := os.Open(file1) 212 | if err != nil { 213 | log.Fatal(err) 214 | } 215 | 216 | f2, err := os.Open(file2) 217 | if err != nil { 218 | log.Fatal(err) 219 | } 220 | 221 | for { 222 | b1 := make([]byte, chunkSize) 223 | _, err1 := f1.Read(b1) 224 | 225 | b2 := make([]byte, chunkSize) 226 | _, err2 := f2.Read(b2) 227 | 228 | if err1 != nil || err2 != nil { 229 | if err1 == io.EOF && err2 == io.EOF { 230 | return true 231 | } else if err1 == io.EOF || err2 == io.EOF { 232 | return false 233 | } else { 234 | log.Fatal(err1, err2) 235 | } 236 | } 237 | 238 | if !bytes.Equal(b1, b2) { 239 | return false 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /cmd/utils.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "path/filepath" 11 | "strings" 12 | "text/tabwriter" 13 | "text/template" 14 | ) 15 | 16 | var okayResponses = []string{"y", "Y", "yes", "Yes", "YES"} 17 | var nokayResponses = []string{"n", "N", "no", "No", "NO"} 18 | 19 | func check(e error) { 20 | if e != nil { 21 | 22 | //clean up before exiting 23 | os.RemoveAll(tempDir) 24 | 25 | log.Fatal("ERROR: ", e) 26 | } 27 | } 28 | 29 | func debug(a ...interface{}) { 30 | if verbose { 31 | log.Println(a...) 32 | } 33 | } 34 | 35 | // CopyDir recursively copies a directory tree, attempting to preserve permissions. 36 | // Source directory must exist, destination directory must *not* exist. 37 | // Symlinks are ignored and skipped. 38 | func copyDir(src string, dst string) (err error) { 39 | src = filepath.Clean(src) 40 | dst = filepath.Clean(dst) 41 | 42 | si, err := os.Stat(src) 43 | if err != nil { 44 | return err 45 | } 46 | if !si.IsDir() { 47 | return fmt.Errorf("source is not a directory") 48 | } 49 | 50 | _, err = os.Stat(dst) 51 | if err != nil && !os.IsNotExist(err) { 52 | return 53 | } 54 | if err == nil { 55 | return fmt.Errorf("destination already exists") 56 | } 57 | 58 | err = os.MkdirAll(dst, si.Mode()) 59 | if err != nil { 60 | return 61 | } 62 | 63 | entries, err := ioutil.ReadDir(src) 64 | if err != nil { 65 | return 66 | } 67 | 68 | for _, entry := range entries { 69 | srcPath := filepath.Join(src, entry.Name()) 70 | dstPath := filepath.Join(dst, entry.Name()) 71 | 72 | if entry.IsDir() { 73 | err = copyDir(srcPath, dstPath) 74 | if err != nil { 75 | return 76 | } 77 | } else { 78 | // Skip symlinks. 79 | if entry.Mode()&os.ModeSymlink != 0 { 80 | continue 81 | } 82 | 83 | err = copyFile(srcPath, dstPath) 84 | if err != nil { 85 | return 86 | } 87 | } 88 | } 89 | 90 | return 91 | } 92 | 93 | // askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and 94 | // then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as 95 | // confirmations. If the input is not recognized, it will ask again. The function does not return 96 | // until it gets a valid response from the user. Typically, you should use fmt to print out a question 97 | // before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)") 98 | func askForConfirmation() bool { 99 | var response string 100 | _, err := fmt.Scanln(&response) 101 | if err != nil { 102 | log.Fatal(err) 103 | } 104 | if containsString(okayResponses, response) { 105 | return true 106 | } else if containsString(nokayResponses, response) { 107 | return false 108 | } else { 109 | fmt.Println("Please type yes or no and then press enter:") 110 | return askForConfirmation() 111 | } 112 | } 113 | 114 | // containsString returns true iff slice contains element 115 | func containsString(slice []string, element string) bool { 116 | return !(posString(slice, element) == -1) 117 | } 118 | 119 | // posString returns the first index of element in slice. 120 | // If slice does not contain element, returns -1. 121 | func posString(slice []string, element string) int { 122 | for index, elem := range slice { 123 | if elem == element { 124 | return index 125 | } 126 | } 127 | return -1 128 | } 129 | 130 | func copyFile(src, dst string) (err error) { 131 | in, err := os.Open(src) 132 | if err != nil { 133 | return 134 | } 135 | defer in.Close() 136 | 137 | out, err := os.Create(dst) 138 | if err != nil { 139 | return 140 | } 141 | defer func() { 142 | if e := out.Close(); e != nil { 143 | err = e 144 | } 145 | }() 146 | 147 | _, err = io.Copy(out, in) 148 | if err != nil { 149 | return 150 | } 151 | 152 | err = out.Sync() 153 | if err != nil { 154 | return 155 | } 156 | 157 | si, err := os.Stat(src) 158 | if err != nil { 159 | return 160 | } 161 | err = os.Chmod(dst, si.Mode()) 162 | if err != nil { 163 | return 164 | } 165 | 166 | return 167 | } 168 | 169 | func applyTemplate(textTemplate string, data interface{}) string { 170 | //create a formatted template 171 | buf := new(bytes.Buffer) 172 | w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', tabwriter.DiscardEmptyColumns) 173 | tmpl, err := template.New("t").Parse(textTemplate) 174 | check(err) 175 | fmt.Fprintln(w) 176 | 177 | //execute the template with the data 178 | err = tmpl.Execute(w, data) 179 | check(err) 180 | w.Flush() 181 | return buf.String() 182 | } 183 | 184 | func ensureFileContains(file string, lines []string) { 185 | if _, err := os.Stat(file); err == nil { 186 | //update 187 | osfile, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0600) 188 | check(err) 189 | defer osfile.Close() 190 | for _, line := range lines { 191 | //only write if not exists 192 | dat, err := ioutil.ReadFile(file) 193 | check(err) 194 | if !strings.Contains(string(dat), line) { 195 | _, err = osfile.WriteString("\n" + line) 196 | check(err) 197 | } 198 | } 199 | } else { 200 | //create 201 | data := "" 202 | for _, line := range lines { 203 | data += line + "\n" 204 | } 205 | err := ioutil.WriteFile(file, []byte(data), 0644) 206 | check(err) 207 | } 208 | } 209 | 210 | func promptAndGetResponse(question string, defaultResponse string) string { 211 | fmt.Print(question) 212 | var response string 213 | _, err := fmt.Scanln(&response) 214 | if err != nil && err.Error() != "unexpected newline" { 215 | log.Fatal(err) 216 | } 217 | if response == "" { 218 | response = defaultResponse 219 | } 220 | return response 221 | } 222 | -------------------------------------------------------------------------------- /examples/fargate-create.yml: -------------------------------------------------------------------------------- 1 | # this file is used by fargate-create (https://github.com/turnerlabs/fargate-create) 2 | # if not using fargate-create, this file can be ignored/deleted 3 | 4 | # the type of template (e.g.: Service, ScheduledTask) 5 | templateType: Service 6 | 7 | # file customization 8 | prompts: 9 | 10 | - question: "Would you like HTTPS support (requires a certificate)?" 11 | default: "no" 12 | filesToDeleteIfNo: 13 | - "lb-https.tf" 14 | 15 | - question: "Would you like performance based auto-scaling?" 16 | default: "yes" 17 | filesToDeleteIfNo: 18 | - "autoscale-perf.tf" 19 | 20 | - question: "Would you like time based auto-scaling?" 21 | default: "yes" 22 | filesToDeleteIfNo: 23 | - "autoscale-time.tf" 24 | - "autoscale-time.zip" 25 | 26 | - question: "Would you like an IAM user that can be used for CI/CD pipelines?" 27 | default: "no" 28 | filesToDeleteIfNo: 29 | - "cicd.tf" 30 | 31 | - question: "Would you like to ship your container logs to logz.io (requires a key)?" 32 | default: "no" 33 | filesToDeleteIfNo: 34 | - "logs-logzio.tf" 35 | - "logs-logzio.zip" 36 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/turnerlabs/fargate-create 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.44.122 7 | github.com/hashicorp/go-getter v1.7.5 8 | github.com/spf13/cobra v1.4.0 9 | gopkg.in/yaml.v2 v2.4.0 10 | 11 | ) 12 | 13 | require ( 14 | cloud.google.com/go v0.110.0 // indirect 15 | cloud.google.com/go/compute v1.19.1 // indirect 16 | cloud.google.com/go/compute/metadata v0.2.3 // indirect 17 | cloud.google.com/go/iam v0.13.0 // indirect 18 | cloud.google.com/go/storage v1.28.1 // indirect 19 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 20 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 21 | github.com/golang/protobuf v1.5.3 // indirect 22 | github.com/google/go-cmp v0.5.9 // indirect 23 | github.com/google/uuid v1.3.0 // indirect 24 | github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect 25 | github.com/googleapis/gax-go/v2 v2.7.1 // indirect 26 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 27 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 28 | github.com/hashicorp/go-version v1.6.0 // indirect 29 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 30 | github.com/jmespath/go-jmespath v0.4.0 // indirect 31 | github.com/klauspost/compress v1.15.11 // indirect 32 | github.com/mitchellh/go-homedir v1.1.0 // indirect 33 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 34 | github.com/spf13/pflag v1.0.5 // indirect 35 | github.com/ulikunitz/xz v0.5.10 // indirect 36 | go.opencensus.io v0.24.0 // indirect 37 | golang.org/x/net v0.33.0 // indirect 38 | golang.org/x/oauth2 v0.7.0 // indirect 39 | golang.org/x/sys v0.28.0 // indirect 40 | golang.org/x/text v0.21.0 // indirect 41 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 42 | google.golang.org/api v0.114.0 // indirect 43 | google.golang.org/appengine v1.6.7 // indirect 44 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect 45 | google.golang.org/grpc v1.56.3 // indirect 46 | google.golang.org/protobuf v1.33.0 // indirect 47 | ) 48 | -------------------------------------------------------------------------------- /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.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= 22 | cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= 23 | cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= 24 | cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= 25 | cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= 26 | cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= 27 | cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 28 | cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= 29 | cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= 30 | cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= 31 | cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= 32 | cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= 33 | cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= 34 | cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= 35 | cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= 36 | cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= 37 | cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= 38 | cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= 39 | cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= 40 | cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= 41 | cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= 42 | cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= 43 | cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= 44 | cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= 45 | cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= 46 | cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= 47 | cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= 48 | cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= 49 | cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= 50 | cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= 51 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 52 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 53 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 54 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 55 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 56 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 57 | cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= 58 | cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= 59 | cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= 60 | cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= 61 | cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= 62 | cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= 63 | cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= 64 | cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= 65 | cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= 66 | cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= 67 | cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= 68 | cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= 69 | cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= 70 | cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= 71 | cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= 72 | cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= 73 | cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= 74 | cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= 75 | cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= 76 | cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= 77 | cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= 78 | cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= 79 | cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= 80 | cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= 81 | cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= 82 | cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= 83 | cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= 84 | cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= 85 | cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= 86 | cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= 87 | cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= 88 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 89 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 90 | cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= 91 | cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= 92 | cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= 93 | cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= 94 | cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= 95 | cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= 96 | cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= 97 | cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= 98 | cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= 99 | cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= 100 | cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= 101 | cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= 102 | cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= 103 | cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= 104 | cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= 105 | cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= 106 | cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= 107 | cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= 108 | cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= 109 | cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= 110 | cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= 111 | cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= 112 | cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= 113 | cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= 114 | cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= 115 | cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= 116 | cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= 117 | cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= 118 | cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= 119 | cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= 120 | cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= 121 | cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= 122 | cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= 123 | cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= 124 | cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= 125 | cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= 126 | cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= 127 | cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= 128 | cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= 129 | cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= 130 | cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= 131 | cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= 132 | cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= 133 | cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= 134 | cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= 135 | cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= 136 | cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= 137 | cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= 138 | cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= 139 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 140 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 141 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 142 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 143 | cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= 144 | cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= 145 | cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= 146 | cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= 147 | cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= 148 | cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= 149 | cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= 150 | cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= 151 | cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= 152 | cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= 153 | cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= 154 | cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= 155 | cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= 156 | cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= 157 | cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= 158 | cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= 159 | cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= 160 | cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= 161 | cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= 162 | cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= 163 | cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= 164 | cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= 165 | cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= 166 | cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= 167 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 168 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 169 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 170 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 171 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 172 | cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= 173 | cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= 174 | cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= 175 | cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= 176 | cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= 177 | cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= 178 | cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= 179 | cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= 180 | cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= 181 | cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= 182 | cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= 183 | cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= 184 | cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= 185 | cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= 186 | cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= 187 | cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= 188 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 189 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 190 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 191 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 192 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 193 | github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo= 194 | github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 195 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= 196 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 197 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 198 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 199 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 200 | github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 201 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 202 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 203 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 204 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 205 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 206 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 207 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 208 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 209 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 210 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 211 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 212 | github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 213 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 214 | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 215 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 216 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 217 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 218 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 219 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 220 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 221 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 222 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 223 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 224 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 225 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 226 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= 227 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 228 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 229 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 230 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 231 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 232 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 233 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 234 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 235 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 236 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 237 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 238 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 239 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 240 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 241 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 242 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 243 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 244 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 245 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 246 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 247 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 248 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 249 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 250 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 251 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 252 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 253 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 254 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 255 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 256 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 257 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 258 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 259 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 260 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 261 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 262 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 263 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 264 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 265 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 266 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 267 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 268 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 269 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 270 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 271 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 272 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 273 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 274 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 275 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 276 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 277 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 278 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 279 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 280 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 281 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 282 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 283 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 284 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 285 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 286 | github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 287 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 288 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 289 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 290 | github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 291 | github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= 292 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 293 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 294 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 295 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 296 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 297 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 298 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 299 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 300 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 301 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 302 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 303 | github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 304 | github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 305 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 306 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 307 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 308 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 309 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 310 | github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= 311 | github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= 312 | github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= 313 | github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= 314 | github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= 315 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 316 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 317 | github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= 318 | github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 319 | github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= 320 | github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= 321 | github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= 322 | github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= 323 | github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= 324 | github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= 325 | github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= 326 | github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= 327 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 328 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 329 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 330 | github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= 331 | github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= 332 | github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= 333 | github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= 334 | github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= 335 | github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 336 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 337 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 338 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 339 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 340 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 341 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 342 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 343 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 344 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 345 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 346 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 347 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 348 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 349 | github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= 350 | github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= 351 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 352 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 353 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 354 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 355 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 356 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 357 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 358 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 359 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 360 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 361 | github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= 362 | github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 363 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 364 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 365 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 366 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 367 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 368 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 369 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 370 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 371 | github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= 372 | github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= 373 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 374 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 375 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 376 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 377 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 378 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 379 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 380 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 381 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 382 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 383 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 384 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 385 | github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= 386 | github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 387 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 388 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 389 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 390 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 391 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 392 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 393 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 394 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 395 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 396 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 397 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 398 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 399 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 400 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 401 | go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 402 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 403 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 404 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 405 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 406 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 407 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 408 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 409 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 410 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 411 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 412 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 413 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 414 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 415 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 416 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 417 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 418 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 419 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 420 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 421 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 422 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 423 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 424 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 425 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 426 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 427 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 428 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 429 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 430 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 431 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 432 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 433 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 434 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 435 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 436 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 437 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 438 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 439 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 440 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 441 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 442 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 443 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 444 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 445 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 446 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 447 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 448 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 449 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 450 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 451 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 452 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 453 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 454 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 455 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 456 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 457 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 458 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 459 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 460 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 461 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 462 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 463 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 464 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 465 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 466 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 467 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 468 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 469 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 470 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 471 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 472 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 473 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 474 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 475 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 476 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 477 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 478 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 479 | golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 480 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 481 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 482 | golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 483 | golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 484 | golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 485 | golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 486 | golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 487 | golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 488 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 489 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 490 | golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 491 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= 492 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= 493 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 494 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 495 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 496 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 497 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 498 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 499 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 500 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 501 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 502 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 503 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 504 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 505 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 506 | golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 507 | golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 508 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 509 | golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 510 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 511 | golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 512 | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 513 | golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= 514 | golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= 515 | golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= 516 | golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= 517 | golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= 518 | golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= 519 | golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= 520 | golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= 521 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 522 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 523 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 524 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 525 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 526 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 527 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 528 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 529 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 530 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 531 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 532 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 533 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 534 | golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 535 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 536 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 537 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 538 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 539 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 540 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 541 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 542 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 543 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 544 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 545 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 546 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 547 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 548 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 549 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 550 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 551 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 552 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 553 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 554 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 555 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 556 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 557 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 558 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 559 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 560 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 561 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 562 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 563 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 564 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 565 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 566 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 567 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 568 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 569 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 570 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 571 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 572 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 573 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 574 | golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 575 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 576 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 577 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 578 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 579 | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 580 | golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 581 | golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 582 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 583 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 584 | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 585 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 586 | golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 587 | golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 588 | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 589 | golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 590 | golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 591 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 592 | golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 593 | golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 594 | golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 595 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 596 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 597 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 598 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 599 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 600 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 601 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 602 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 603 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 604 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 605 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 606 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 607 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 608 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 609 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 610 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 611 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 612 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 613 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 614 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 615 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 616 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 617 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 618 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 619 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 620 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 621 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 622 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 623 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 624 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 625 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 626 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 627 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 628 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 629 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 630 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 631 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 632 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 633 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 634 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 635 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 636 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 637 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 638 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 639 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 640 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 641 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 642 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 643 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 644 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 645 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 646 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 647 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 648 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 649 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 650 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 651 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 652 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 653 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 654 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 655 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 656 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 657 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 658 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 659 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 660 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 661 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 662 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 663 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 664 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 665 | golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 666 | golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 667 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 668 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 669 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 670 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 671 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 672 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 673 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 674 | golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 675 | golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 676 | golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 677 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= 678 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 679 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 680 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 681 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 682 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 683 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 684 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 685 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 686 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 687 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 688 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 689 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 690 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 691 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 692 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 693 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 694 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 695 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 696 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 697 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 698 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 699 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 700 | google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= 701 | google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= 702 | google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= 703 | google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= 704 | google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= 705 | google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 706 | google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 707 | google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= 708 | google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= 709 | google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= 710 | google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= 711 | google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= 712 | google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= 713 | google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= 714 | google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= 715 | google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= 716 | google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= 717 | google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= 718 | google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= 719 | google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= 720 | google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= 721 | google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= 722 | google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= 723 | google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= 724 | google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= 725 | google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= 726 | google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= 727 | google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= 728 | google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= 729 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 730 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 731 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 732 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 733 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 734 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 735 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 736 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 737 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 738 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 739 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 740 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 741 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 742 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 743 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 744 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 745 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 746 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 747 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 748 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 749 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 750 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 751 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 752 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 753 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 754 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 755 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 756 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 757 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 758 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 759 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 760 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 761 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 762 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 763 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 764 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 765 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 766 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 767 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 768 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 769 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 770 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 771 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 772 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 773 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 774 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 775 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 776 | google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 777 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 778 | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= 779 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 780 | google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 781 | google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 782 | google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= 783 | google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 784 | google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 785 | google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 786 | google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 787 | google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= 788 | google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 789 | google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 790 | google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 791 | google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 792 | google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 793 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 794 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 795 | google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 796 | google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 797 | google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 798 | google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 799 | google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 800 | google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= 801 | google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= 802 | google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= 803 | google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= 804 | google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= 805 | google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= 806 | google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= 807 | google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= 808 | google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= 809 | google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= 810 | google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= 811 | google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= 812 | google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= 813 | google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= 814 | google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 815 | google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 816 | google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 817 | google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 818 | google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 819 | google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= 820 | google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= 821 | google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= 822 | google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= 823 | google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= 824 | google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= 825 | google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= 826 | google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= 827 | google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= 828 | google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= 829 | google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= 830 | google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= 831 | google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= 832 | google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= 833 | google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= 834 | google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= 835 | google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= 836 | google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= 837 | google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= 838 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= 839 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= 840 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 841 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 842 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 843 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 844 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 845 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 846 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 847 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 848 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 849 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 850 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 851 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 852 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 853 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 854 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 855 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 856 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 857 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 858 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 859 | google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 860 | google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 861 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 862 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 863 | google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 864 | google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 865 | google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 866 | google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= 867 | google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= 868 | google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 869 | google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 870 | google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 871 | google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 872 | google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 873 | google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 874 | google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 875 | google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= 876 | google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= 877 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 878 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 879 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 880 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 881 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 882 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 883 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 884 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 885 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 886 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 887 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 888 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 889 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 890 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 891 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 892 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 893 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 894 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 895 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 896 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 897 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 898 | gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 899 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 900 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 901 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 902 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 903 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 904 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 905 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 906 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 907 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 908 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 909 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 910 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 911 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 912 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 913 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 914 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 915 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 916 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 917 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/turnerlabs/fargate-create/cmd" 5 | ) 6 | 7 | var version string 8 | 9 | func main() { 10 | cmd.Execute(version) 11 | } 12 | --------------------------------------------------------------------------------