diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..2bf90e0 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,28 @@ +# GitHub Copilot Instructions + +## File Editing Rules + +- **NEVER remove license headers** from files when making edits +- Always preserve the Apache 2.0 license header at the top of all source files (`.tf`, `.go`, `.sh`, etc.) +- When editing files, include the full license header in replacements if modifying code near the top of files + +## Terminal Command Rules + +- **DO NOT use timeout flags** with terminal commands (e.g., avoid `-timeout` with go test) +- Let commands run to completion naturally +- If a command needs to be stopped, the user will cancel it manually +- For long-running tests, rely on the default behavior rather than imposing artificial time limits + +## Terraform Best Practices + +- Follow the module structure defined in the repository +- Maintain consistency with existing patterns +- Use dynamic blocks appropriately for optional nested configurations +- Always validate configurations with `terraform validate` before planning or applying + +## Testing Guidelines + +- Write comprehensive tests that verify actual AWS resource creation +- Use the AWS SDK to verify resource properties match Terraform outputs +- Test both required and optional parameters +- Include validation for resource naming, encryption, and other critical settings diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fc32262 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "terraform" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..7ff6d2b --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,49 @@ +--- +name-template: "$RESOLVED_VERSION" +tag-template: "$RESOLVED_VERSION" +template: | + # Changelog + + $CHANGES + + --- + + See details of [all code changes](https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...$RESOLVED_VERSION) since previous release. + +categories: + - title: ":warning: Breaking Changes" + labels: + - "major" + - title: "🚀 Features" + labels: + - "minor" + - title: "🔧 Fixes" + collapse-after: 3 + labels: + - "patch" + +autolabeler: + - label: "major" + branch: + - '/(patch|bug|fix|feature|chore)!\/.+/' + - label: "minor" + branch: + - '/feature\/.+/' + - label: "patch" + branch: + - '/(patch|bug|fix|chore)\/.+/' + +change-template: "- $TITLE @$AUTHOR (#$NUMBER)" + +version-resolver: + major: + labels: + - "major" + minor: + labels: + - "minor" + patch: + labels: + - "patch" + - "dependencies" + default: patch diff --git a/.github/workflows/pull-request-label.yml b/.github/workflows/pull-request-label.yml new file mode 100644 index 0000000..6a90a15 --- /dev/null +++ b/.github/workflows/pull-request-label.yml @@ -0,0 +1,15 @@ +name: Label Pull Request + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + check: + name: "Label Pull Request" + permissions: + contents: read + issues: write + pull-requests: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-pr-label-by-branch.yml@0.11.0 + secrets: inherit # pragma: allowlist secret diff --git a/.github/workflows/pull-request-terraform-check.yml b/.github/workflows/pull-request-terraform-check.yml new file mode 100644 index 0000000..b2b7d9e --- /dev/null +++ b/.github/workflows/pull-request-terraform-check.yml @@ -0,0 +1,22 @@ +name: Check AWS Terraform Code + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + branches: [main] + +permissions: + id-token: write + contents: read + +jobs: + check: + name: "Check AWS Terraform Code" + permissions: + contents: read + id-token: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check-aws.yml@0.11.0 + with: + assume_role_arn: ${{ vars.TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN }} + region: ${{ vars.TERRAFORM_CHECK_AWS_REGION }} + secrets: inherit # pragma: allowlist secret diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 0000000..fcec1f0 --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,18 @@ +name: Publish Release + +on: + push: + branches: + - main + +permissions: + contents: read + +jobs: + release-on-merge: + name: "Create and Publish Release on Merge" + permissions: + contents: write + pull-requests: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-release-on-merge.yml@0.11.0 + secrets: inherit # pragma: allowlist secret diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0393b1c --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +terraform.* +.repo/ +components/ +.semverbot.toml +vendor/ + +.idea +!examples/*.tfvars + +# We don't want to commit the test run lock files +.terraform.lock.hcl + +# Don't include the .test-data directory created by Terratest's test-structure module +**/.test-data/* + +# Local .terraform directories +**/.terraform/* + +# Local .terragrunt directories +**/.terragrunt/* + +# .tfstate files +*.tfstate +*.tfstate.* +*.tfplan +tfplan.* +tfplan + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars.json +*.auto.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json +provider.tf + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Files from common modules +azure_env.sh +.releaserc.json + +# VS Code +.vscode/ +.devcontainer/ +.context/ diff --git a/.golangci.yaml b/.golangci.yaml new file mode 120000 index 0000000..3a81054 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,5 @@ +version: "2" +run: + # Timeout for analysis, e.g. 30s, 5m. + timeout: 5m + allow-parallel-runners: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 120000 index 0000000..98b40fc --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-json + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-yaml + args: + - --allow-multiple-documents + - id: end-of-file-fixer + - id: mixed-line-ending + args: + - --fix=auto + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.99.0 + hooks: + - id: terraform_fmt + - id: terraform_validate + - id: terraform_docs + args: + - --hook-config=--path-to-file=README.md + - --hook-config=--add-to-existing-file=true + - --hook-config=--create-file-if-not-exist=true + - --args=--sort=false + - repo: https://github.com/golangci/golangci-lint + rev: v2.2.1 + hooks: + - id: golangci-lint + name: golangci-lint + description: Fast linters runner for Go. + entry: golangci-lint run --fix + types: [go] + language: golang + pass_filenames: false + - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook + rev: v9.22.0 + hooks: + - id: commitlint + stages: [commit-msg] + additional_dependencies: ["@commitlint/config-conventional"] + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + args: ["--baseline", ".secrets.baseline"] + exclude: package.lock.json diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..99c07f2 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,127 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], + "results": {}, + "generated_at": "2025-11-20T18:36:16Z" +} diff --git a/.terraform-docs.yml b/.terraform-docs.yml new file mode 100644 index 0000000..840208b --- /dev/null +++ b/.terraform-docs.yml @@ -0,0 +1,12 @@ +formatter: "markdown" + +output: + file: "README.md" + mode: "inject" + +sort: + enabled: false + +sections: + hide: + - providers diff --git a/.tflint.hcl b/.tflint.hcl new file mode 120000 index 0000000..427121c --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,4 @@ +plugin "terraform" { + enabled = true + preset = "recommended" +} diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..5911a46 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,8 @@ +conftest 0.56.0 +golang 1.24.2 +golangci-lint 2.2.1 +pre-commit 4.2.0 +regula 3.2.1 # https://github.com/launchbynttdata/asdf-regula +terraform 1.12.2 +terraform-docs 0.20.0 +tflint 0.57.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fbffcea --- /dev/null +++ b/Makefile @@ -0,0 +1,173 @@ + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Include custom values from .lcafenv. Repository root is assumed to be the working directory. +# Including overriding values in this file is preferred over modifying the contents below. +LCAF_ENV_FILE = .lcafenv +-include $(LCAF_ENV_FILE) + +# Source repository for repo manifests +REPO_MANIFESTS_URL ?= https://github.com/launchbynttdata/launch-common-automation-framework.git +# Branch of source repository for repo manifests. Other tags not currently supported. +REPO_BRANCH ?= refs/tags/1.8.1 +# Path to seed manifest in repository referenced in REPO_MANIFESTS_URL +REPO_MANIFEST ?= manifests/terraform_modules/seed/manifest.xml + +# Settings to pull in Nexient version of (google) repo utility that supports environment substitution: +REPO_URL ?= https://github.com/launchbynttdata/git-repo.git +# Branch of the repository referenced by REPO_URL to use +REPO_REV ?= main +export REPO_REV REPO_URL + +# Example variable to substituted after init, but before sync in repo manifests. +GITBASE ?= https://github.com/launchbynttdata/ +GITREV ?= main +export GITBASE GITREV + +# Set to true in a pipeline context +IS_PIPELINE ?= false + +IS_AUTHENTICATED ?= false + +JOB_NAME ?= job +JOB_EMAIL ?= job@job.job + +COMPONENTS_DIR = components +-include $(COMPONENTS_DIR)/Makefile + +MODULE_DIR ?= ${COMPONENTS_DIR}/module + +PYTHON3_INSTALLED = $(shell which python3 > /dev/null 2>&1; echo $$?) +MISE_INSTALLED = $(shell which mise > /dev/null 2>&1; echo $$?) +ASDF_INSTALLED = $(shell which asdf > /dev/null 2>&1; echo $$?) +REPO_INSTALLED = $(shell which repo > /dev/null 2>&1; echo $$?) +GIT_USER_SET = $(shell git config --get user.name > /dev/null 2>&1; echo $$?) +GIT_EMAIL_SET = $(shell git config --get user.email > /dev/null 2>&1; echo $$?) + +.PHONY: configure-git-hooks +configure-git-hooks: configure-dependencies +ifeq ($(PYTHON3_INSTALLED), 0) + @test -L /usr/bin/python || sudo ln -s /usr/bin/python3 /usr/bin/python + pre-commit install +else + $(error Missing python3, which is required for pre-commit. Install python3 and rerun.) +endif + +ifeq ($(IS_PIPELINE),true) +.PHONY: git-config +git-config: + @set -ex; \ + git config --global user.name "$(JOB_NAME)"; \ + git config --global user.email "$(JOB_EMAIL)"; \ + git config --global color.ui false + +configure: git-config +endif + +ifeq ($(IS_AUTHENTICATED),true) +.PHONY: git-auth +git-auth: + $(call config,Bearer $(GIT_TOKEN)) + +define config + @set -ex; \ + git config --global http.extraheader "AUTHORIZATION: $(1)"; \ + git config --global http.https://gerrit.googlesource.com/git-repo/.extraheader ''; \ + git config --global http.version HTTP/1.1; +endef + +configure: git-auth +endif + +.PHONY: configure-dependencies +configure-dependencies: +ifeq ($(MISE_INSTALLED), 0) + @echo "Installing dependencies using mise" + @awk -F'[ #]' '$$NF ~ /https/ {system("mise plugin install " $$1 " " $$NF " --yes")} $$1 ~ /./ {system("mise install " $$1 " " $$2 " --yes")}' ./.tool-versions +else ifeq ($(ASDF_INSTALLED), 0) + @echo "Installing dependencies using asdf-vm" + @awk -F'[ #]' '$$NF ~ /https/ {system("asdf plugin add " $$1 " " $$NF)} $$1 ~ /./ {system("asdf plugin add " $$1 "; asdf install " $$1 " " $$2)}' ./.tool-versions +else + $(error Missing supported dependency manager. Install asdf-vm (https://asdf-vm.com/) or mise (https://mise.jdx.dev/) and rerun) +endif + +.PHONY: configure +configure: configure-git-hooks +ifneq ($(and $(GIT_USER_SET), $(GIT_EMAIL_SET)), 0) + $(error Git identities are not set! Set your user.name and user.email using 'git config' and rerun) +endif +ifeq ($(REPO_INSTALLED), 0) + echo n | repo --color=never init --no-repo-verify \ + -u "$(REPO_MANIFESTS_URL)" \ + -b "$(REPO_BRANCH)" \ + -m "$(REPO_MANIFEST)" + repo envsubst + repo sync +else + $(error Missing Repo, which is required for platform sync. Install Repo (https://gerrit.googlesource.com/git-repo) and rerun.) +endif + +# The first line finds and removes all the directories pulled in by repo +# The second line finds and removes all the broken symlinks from removing things +# https://stackoverflow.com/questions/42828021/removing-files-with-rm-using-find-and-xargs +.PHONY: clean +clean: + -repo list | awk '{ print $1; }' | cut -d '/' -f1 | uniq | xargs rm -rf + find . -type l ! -exec test -e {} \; -print | xargs rm -rf + +.PHONY: init-clean +init-clean: + rm -rf .git + git init --initial-branch=main +ifneq (,$(wildcard ./TEMPLATED_README.md)) + mv TEMPLATED_README.md README.MD +endif + + +.PHONY: init-module +init-module: + @echo "Initializing module from template..." + @REPO_URL=$$(git config --get remote.origin.url); \ + if [ -z "$$REPO_URL" ]; then \ + echo "Error: Could not determine git repository URL. Make sure this is a git repository with a remote origin."; \ + exit 1; \ + fi; \ + echo "Repository URL: $$REPO_URL"; \ + REPO_PATH=$$(echo $$REPO_URL | sed -E 's#(https://|git@)##' | sed -E 's#:#/#' | sed -E 's#\.git$$##'); \ + echo "Repository Path: $$REPO_PATH"; \ + MODULE_NAME=$$(basename $$REPO_URL .git); \ + echo "Module Name: $$MODULE_NAME"; \ + echo "Updating go.mod..."; \ + sed -i.bak "s#github.com/launchbynttdata/tf-aws-module-template#$$REPO_PATH#g" go.mod && rm go.mod.bak; \ + echo "Updating test files..."; \ + find tests -type f -name "*.go" -exec sed -i.bak "s#github.com/launchbynttdata/tf-aws-module-template#$$REPO_PATH#g" {} \; -exec rm {}.bak \;; \ + echo "Running go mod tidy..."; \ + go mod tidy; \ + echo ""; \ + echo "Removing detect-secrets baseline..."; \ + rm -f .secrets.baseline; \ + echo "✅ Module initialization complete!"; \ + echo ""; \ + echo "Next steps:"; \ + echo " 1. Review and update the module files (main.tf, variables.tf, outputs.tf)"; \ + echo " 2. Update the examples in the examples/ directory"; \ + echo " 3. Update test implementations in tests/testimpl/"; \ + echo " 4. Run 'make configure' to set up your development environment"; \ + echo " 5. Run 'make check' to validate your changes" + +.PHONY: secrets-baseline +secrets-baseline: + @echo "Creating new detect-secrets baseline..." + detect-secrets scan > .secrets.baseline + @echo "✅ Secrets baseline created successfully!" + @echo "Review .secrets.baseline to ensure no false positives are included." diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..bb7f5ca --- /dev/null +++ b/NOTICE @@ -0,0 +1,7 @@ +Copyright 2025 NTT DATA, Inc. + +Software, source files, and snippets are licensed under the Apache 2.0 license. + +All other content (e.g. documentation), unless otherwise specified, is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0) License (). + +If you discover a file that does not specify its license that should be licensed, please contact the repository owners as soon as possible to resolve the issue. diff --git a/README.md b/README.md index c0c0ec4..76532a3 100644 --- a/README.md +++ b/README.md @@ -1 +1,550 @@ -# tf-aws-module_primitive-efs_file_system \ No newline at end of file +# tf-aws-module_primitive-efs_file_system + +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC_BY--NC--ND_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-nd/4.0/) + +## Overview + +A Terraform primitive module for creating and managing AWS Elastic File System (EFS) file systems. This module provides a standardized way to create EFS file systems with configurable encryption, performance modes, throughput settings, and lifecycle policies for cost optimization. + +## Features + +- **Encryption at Rest**: Supports both AWS managed and customer managed KMS keys +- **Flexible Storage Options**: Multi-AZ (high availability) or One Zone (cost optimized) storage classes +- **Performance Modes**: Choose between General Purpose (lower latency) or Max I/O (higher throughput) +- **Throughput Modes**: Bursting, Elastic (auto-scaling), or Provisioned throughput +- **Lifecycle Management**: Automated transitions between storage classes (Standard, IA, Archive) for cost optimization +- **Protection Controls**: Configurable replication overwrite protection +- **Comprehensive Tagging**: Support for custom tags with automatic ManagedBy tag and optional Name tag +- **Input Validation**: Built-in validation for performance mode and throughput mode values + +## Usage + +### Basic Example + +```hcl +module "efs" { + source = "github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system?ref=1.0.0" + + creation_token = "my-app-efs" + name = "My Application EFS" + encrypted = true + + tags = { + Environment = "production" + Application = "my-app" + } +} +``` + +### Complete Example with All Features + +```hcl +module "efs" { + source = "github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system?ref=1.0.0" + + creation_token = "my-app-efs" + name = "Production EFS" + encrypted = true + kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + performance_mode = "generalPurpose" + throughput_mode = "elastic" + + # Cost optimization with lifecycle policies + lifecycle_policy = { + transition_to_ia = "AFTER_30_DAYS" + transition_to_primary_storage_class = "AFTER_1_ACCESS" + transition_to_archive = "AFTER_90_DAYS" + } + + protection = { + replication_overwrite = "DISABLED" + } + + tags = { + Environment = "production" + Application = "my-app" + CostCenter = "engineering" + } +} +``` + +### One Zone Storage Example + +```hcl +module "efs_one_zone" { + source = "github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system?ref=1.0.0" + + creation_token = "my-dev-efs" + name = "Development EFS" + availability_zone_name = "us-east-1a" # Creates One Zone storage + encrypted = true + throughput_mode = "bursting" + + tags = { + Environment = "development" + } +} +``` + +## Important Notes + +### Lifecycle Policy Implementation + +This module uses **separate `lifecycle_policy` blocks** for each transition type as required by AWS Provider version 5.100.0. Each transition rule (to IA, to Archive, to Primary Storage) must be defined in its own block. See the [main.tf](main.tf) file for detailed implementation comments. + +### Mount Targets + +This module creates only the EFS file system resource itself. To mount the file system to EC2 instances or other compute resources, you'll need to create EFS mount targets separately using a mount target module or resource. Mount targets require: +- VPC subnet IDs +- Security groups for access control +- Network connectivity to your compute resources + +### Storage Classes and Cost Optimization + +- **Standard**: Default storage class for frequently accessed files +- **Infrequent Access (IA)**: Lower cost for files accessed less frequently +- **Archive**: Lowest cost for long-term storage, rarely accessed files +- Use lifecycle policies to automatically transition files between storage classes based on access patterns + +### Throughput Modes + +- **Bursting**: Throughput scales with file system size (good for baseline workloads) +- **Elastic**: Automatically scales throughput up/down based on workload (recommended for variable workloads) +- **Provisioned**: Fixed throughput independent of storage size (use when you need guaranteed throughput) + +Install required development dependencies: + +```bash +make configure-dependencies +make configure-git-hooks +``` + +This installs: + +- Terraform +- Go +- Pre-commit hooks +- Other development tools specified in `.tool-versions` + +--- + +## HOWTO: Developing a Primitive Module + +### Step 1: Define Your Resource + +1. **Identify the AWS resource** you're wrapping (e.g., `aws_eks_cluster`) +2. **Review AWS documentation** for the resource to understand all available parameters +3. **Study similar primitive modules** for patterns and best practices + +### Step 2: Create the Module Structure + +Your primitive module should include these core files: + +#### `main.tf` + +- Contains the primary resource declaration +- Should be clean and focused on the single resource +- Example: + +```hcl +resource "aws_eks_cluster" "this" { + name = var.name + role_arn = var.role_arn + version = var.kubernetes_version + + vpc_config { + subnet_ids = var.vpc_config.subnet_ids + security_group_ids = var.vpc_config.security_group_ids + endpoint_private_access = var.vpc_config.endpoint_private_access + endpoint_public_access = var.vpc_config.endpoint_public_access + public_access_cidrs = var.vpc_config.public_access_cidrs + } + + tags = merge( + var.tags, + local.default_tags + ) +} +``` + +#### `variables.tf` + +- Define all configurable parameters +- Include clear descriptions for each variable +- Set sensible defaults where appropriate +- Use validation rules to enforce constraints, but only when the validations can be made precise. +- Alternatively, use [`check`](https://developer.hashicorp.com/terraform/language/block/check) blocks to create more complicated validations. (Requires terraform ~> 1.12) +- Example: + +```hcl +variable "name" { + description = "Name of the EKS cluster" + type = string + + validation { + condition = length(var.name) <= 100 + error_message = "Cluster name must be 100 characters or less" + } +} + +variable "kubernetes_version" { + description = "Kubernetes version to use for the EKS cluster" + type = string + default = null + + validation { + condition = var.kubernetes_version == null || can(regex("^1\\.(2[89]|[3-9][0-9])$", var.kubernetes_version)) + error_message = "Kubernetes version must be 1.28 or higher" + } +} +``` + +#### `outputs.tf` + +- Export all useful attributes of the resource +- Include comprehensive outputs for downstream consumption +- Document what each output provides +- Example: + +```hcl +output "id" { + description = "The ID of the EKS cluster" + value = aws_eks_cluster.this.id +} + +output "arn" { + description = "The ARN of the EKS cluster" + value = aws_eks_cluster.this.arn +} + +output "endpoint" { + description = "The endpoint for the EKS cluster API server" + value = aws_eks_cluster.this.endpoint +} +``` + +#### `locals.tf` + +- Define local values and transformations +- Include standard tags (e.g., `provisioner = "Terraform"`) +- Example: + +```hcl +locals { + default_tags = { + provisioner = "Terraform" + } +} +``` + +#### `versions.tf` + +- Specify required Terraform and provider versions +- Example: + +```hcl +terraform { + required_version = "~> 1.5" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.100" + } + } +} +``` + +### Step 3: Create Examples + +Create example configurations in the `examples/` directory: + +#### `examples/simple/` + +- Minimal, working configuration +- Uses only required variables +- Good for quick starts and basic testing + +#### `examples/complete/` + +- Comprehensive configuration showing all features +- Demonstrates advanced options +- Includes comments explaining choices + +Each example should include: + +- `main.tf` - The module invocation +- `variables.tf` - Example variables +- `outputs.tf` - Pass-through outputs +- `test.tfvars` - Test values for automated testing +- `README.md` - Documentation for the example + +### Step 4: Write Tests + +Update the test files in `tests/`: + +#### `tests/testimpl/test_impl.go` + +Write functional tests that verify: + +- The resource is created successfully +- Resource properties match expectations +- Outputs are correct +- Integration with AWS SDK to verify actual state + +#### `tests/testimpl/types.go` + +Define the configuration structure for your tests: + +```go +type ThisTFModuleConfig struct { + Name string `json:"name"` + KubernetesVersion string `json:"kubernetes_version"` + // ... other fields +} +``` + +#### `tests/post_deploy_functional/main_test.go` + +- Update test names to match your module +- Configure test flags (e.g., idempotency settings) +- Adjust test context as needed + +### Step 5: Update Documentation + +1. **Update README.md** with: + - Overview of the module + - Feature list + - Usage examples + - Input/output documentation + - Validation rules + +2. **Document validation rules** clearly so users understand constraints. + +### Step 6: Test Your Module + +1. **Run local validation**: + +```bash +make check +``` + +This runs: + +- Terraform fmt, validate, and plan +- Go tests with Terratest +- Pre-commit hooks +- Security scans + +1. **Test with real infrastructure**: + +```bash +cd examples/simple +terraform init +terraform plan -var-file=test.tfvars -out=the.tfplan +terraform apply the.tfplan +``` + +1. **Verify outputs**: + +```bash +terraform output +``` + +1. **Clean up**: + +```bash +terraform destroy -var-file=test.tfvars +``` + +### Step 7: Document and Release + +1. **Write a comprehensive README** following the pattern in the example modules +1. **Add files to commit** `git add .` +1. **Run pre-commit hooks manually** `pre-commit run` +1. **Resolve any pre-commit issues** +1. **Push branch to github** + +--- + +## Module Best Practices + +### Naming Conventions + +- Repository: `tf-aws-module_primitive-` +- Resource identifier: Use `this` for the primary resource. +- Variables: Use snake_case. +- Match AWS resource parameter names where possible. + +### Input Variables + +- Provide sensible defaults when safe to do so. +- Use `null` as default for optional complex objects. +- Include validation rules with clear error messages. +- Group related parameters using object types. +- Document expected formats and constraints. + +### Outputs + +- Export all significant resource attributes. +- Use clear, descriptive output names. +- Include descriptions for all outputs. +- Consider downstream module needs. + +### Tags + +- Always include a `tags` variable, unless the resource does not support tags. +- Merge with `local.default_tags` including `provisioner = "Terraform"`. +- Use provider default tags when appropriate. + +### Validation + +- Validate input constraints at the variable level. +- Provide helpful error messages. +- Check for common misconfigurations. +- Validate relationships between variables. + +### Testing + +- Test the minimal example (required parameters only). +- Test the complete example (all features). +- Verify resource creation and properties. +- Test idempotency where applicable. +- Test validation rules by expecting failures. + +### Documentation + +- Clear overview of the module's purpose. +- Feature list highlighting key capabilities. +- Multiple usage examples (minimal and complete). +- Comprehensive input/output tables. +- Document validation rules and constraints. +- Include links to relevant AWS documentation. + +--- + +## File Structure + +After initialization, your module should have this structure: + +``` +tf-aws-module_primitive-/ +├── .github/ +│ └── workflows/ # CI/CD workflows +├── examples/ +│ ├── simple/ # Minimal example +│ │ ├── main.tf +│ │ ├── variables.tf +│ │ ├── outputs.tf +│ │ ├── test.tfvars +│ │ └── README.md +│ └── complete/ # Comprehensive example +│ ├── main.tf +│ ├── variables.tf +│ ├── outputs.tf +│ ├── test.tfvars +│ └── README.md +├── tests/ +│ ├── post_deploy_functional/ +│ │ └── main_test.go +│ ├── testimpl/ +│ │ ├── test_impl.go +│ │ └── types.go +├── .gitignore +├── .pre-commit-config.yaml +├── .tool-versions +├── go.mod +├── go.sum +├── LICENSE +├── locals.tf +├── main.tf +├── Makefile +├── outputs.tf +├── README.md +├── variables.tf +└── versions.tf +``` + +--- + +## Common Makefile Targets + +| Target | Description | +|--------|-------------| +| `make init-module` | Initialize new module from template (run once after creating from template) | +| `make configure-dependencies` | Install required development tools | +| `make configure-git-hooks` | Set up pre-commit hooks | +| `make check` | Run all validation and tests | +| `make configure` | Full setup (dependencies + hooks + repo sync) | +| `make clean` | Remove downloaded components | + +--- + +## Getting Help + +- Review example modules: [EKS Cluster](https://github.com/launchbynttdata/tf-aws-module_primitive-eks_cluster), [KMS Key](https://github.com/launchbynttdata/tf-aws-module_primitive-kms_key) +- Check the Launch Common Automation Framework documentation. +- Reach out to the platform team for guidance. + +--- + +## Contributing + +Follow the established patterns in existing primitive modules. All modules should: + +- Pass `make check` validation. +- Include comprehensive tests. +- Follow naming conventions. +- Include clear documentation. +- Use semantic versioning. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.5 | +| [aws](#requirement\_aws) | ~> 5.100 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_efs_file_system.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [creation\_token](#input\_creation\_token) | Required unique identifier for the EFS file system. Must be unique within your AWS account and region and cannot be empty | `string` | n/a | yes | +| [name](#input\_name) | Required friendly name for the EFS file system. Will be added as a 'Name' tag and cannot be empty | `string` | n/a | yes | +| [availability\_zone\_name](#input\_availability\_zone\_name) | The AWS Availability Zone in which to create the file system. Used to create a file system that uses One Zone storage classes. If omitted, Multi-AZ storage will be used | `string` | `null` | no | +| [encrypted](#input\_encrypted) | If true, the disk will be encrypted | `bool` | `true` | no | +| [kms\_key\_id](#input\_kms\_key\_id) | ARN for the KMS encryption key. If set, the EFS file system will be encrypted at rest using this key | `string` | `null` | no | +| [performance\_mode](#input\_performance\_mode) | The file system performance mode. Valid values: 'generalPurpose' (default, lower latency for most workloads) or 'maxIO' (higher aggregate throughput for highly parallelized workloads) | `string` | `"generalPurpose"` | no | +| [throughput\_mode](#input\_throughput\_mode) | Throughput mode for the file system. Valid values: 'bursting' (scales with file system size), 'elastic' (automatically scales based on workload), or 'provisioned' (fixed throughput - requires provisioned\_throughput\_in\_mibps to be set) | `string` | `"bursting"` | no | +| [provisioned\_throughput\_in\_mibps](#input\_provisioned\_throughput\_in\_mibps) | The throughput, measured in MiB/s, that you want to provision for the file system. Only applicable when throughput\_mode is set to 'provisioned' | `number` | `null` | no | +| [lifecycle\_policy](#input\_lifecycle\_policy) | Lifecycle policy for the file system. Supports transition\_to\_ia (AFTER\_7\_DAYS, AFTER\_14\_DAYS, AFTER\_30\_DAYS, AFTER\_60\_DAYS, AFTER\_90\_DAYS, AFTER\_1\_DAY, AFTER\_180\_DAYS, AFTER\_270\_DAYS, AFTER\_365\_DAYS), transition\_to\_primary\_storage\_class (AFTER\_1\_ACCESS), and transition\_to\_archive (AFTER\_1\_DAY, AFTER\_7\_DAYS, AFTER\_14\_DAYS, AFTER\_30\_DAYS, AFTER\_60\_DAYS, AFTER\_90\_DAYS, AFTER\_180\_DAYS, AFTER\_270\_DAYS, AFTER\_365\_DAYS) |
object({
transition_to_ia = optional(string)
transition_to_primary_storage_class = optional(string)
transition_to_archive = optional(string)
})
| `null` | no | +| [protection](#input\_protection) | Protection configuration for the file system. Supports replication\_overwrite (ENABLED, DISABLED, REPLICATING) |
object({
replication_overwrite = optional(string)
})
| `null` | no | +| [tags](#input\_tags) | A map of tags to assign to the EFS file system | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [file\_system\_id](#output\_file\_system\_id) | The ID of the EFS file system | +| [file\_system\_arn](#output\_file\_system\_arn) | Amazon Resource Name of the file system | +| [file\_system\_dns\_name](#output\_file\_system\_dns\_name) | The DNS name for the filesystem | +| [file\_system\_creation\_token](#output\_file\_system\_creation\_token) | The creation token of the EFS file system | +| [file\_system\_availability\_zone\_id](#output\_file\_system\_availability\_zone\_id) | The identifier of the Availability Zone in which the file system's One Zone storage classes exist | +| [file\_system\_availability\_zone\_name](#output\_file\_system\_availability\_zone\_name) | The Availability Zone name in which the file system's One Zone storage classes exist | +| [file\_system\_number\_of\_mount\_targets](#output\_file\_system\_number\_of\_mount\_targets) | The current number of mount targets that the file system has | +| [file\_system\_owner\_id](#output\_file\_system\_owner\_id) | The AWS account that created the file system | +| [file\_system\_size\_in\_bytes](#output\_file\_system\_size\_in\_bytes) | The latest known metered size (in bytes) of data stored in the file system | +| [file\_system\_name](#output\_file\_system\_name) | The value of the file system's Name tag | + diff --git a/examples/complete/README.md b/examples/complete/README.md new file mode 100644 index 0000000..ca06c03 --- /dev/null +++ b/examples/complete/README.md @@ -0,0 +1,324 @@ +# Complete Example + +This example demonstrates **all available features** and configurations of the `tf-aws-module_primitive-efs_file_system` module. It showcases a production-ready setup with advanced cost optimization, performance tuning, and protection features suitable for enterprise workloads. + +## Purpose + +This example is designed for: +- **Production deployments** requiring cost optimization and performance tuning +- **Understanding all module capabilities** and configuration options +- **Learning best practices** for EFS lifecycle management +- **Reference implementation** for enterprise use cases + +## What This Example Demonstrates + +### Cost Optimization Features +- ✅ **Lifecycle Policies**: Automatic transitions between storage classes + - Standard → Infrequent Access (IA) after 30 days + - IA → Archive after 90 days for long-term retention + - Automatic return to Standard on first access +- ✅ **Elastic Throughput**: Pay only for actual throughput used +- ✅ **Storage Class Intelligence**: Can save up to 95% on storage costs + +### Performance Features +- ✅ **Elastic Throughput Mode**: Automatic performance scaling +- ✅ **General Purpose Performance**: Optimized for latency-sensitive workloads +- ✅ **Multi-AZ Storage**: High availability across multiple zones + +### Security & Protection +- ✅ **Encryption at Rest**: AWS or customer managed KMS keys +- ✅ **Protection Configuration**: Replication overwrite controls +- ✅ **Comprehensive Tagging**: Cost allocation and compliance tracking + +### Additional Capabilities +- ✅ **One Zone Storage Option**: Cost-optimized single-AZ deployment +- ✅ **Provisioned Throughput**: Fixed performance for predictable workloads +- ✅ **All Available Outputs**: Complete observability and integration + +## Architecture + +``` +┌───────────────────────────────────────────────────────────┐ +│ AWS Elastic File System (EFS) │ +│ │ +│ Storage Tiers (Automatic Lifecycle Transitions): │ +│ ┌─────────────┐ 30 days ┌────────────────┐ │ +│ │ Standard │────────────→│ Infrequent │ │ +│ │ Storage │←────────────│ Access (IA) │ │ +│ │ ($0.30/GB) │ 1st access │ ($0.025/GB) │ │ +│ └─────────────┘ └────────┬───────┘ │ +│ 90 days│ │ +│ ┌───────▼────────┐ │ +│ │ Archive │ │ +│ │ ($0.016/GB) │ │ +│ └────────────────┘ │ +│ │ +│ Performance: │ +│ • Elastic Throughput (Auto-scaling) │ +│ • General Purpose Mode │ +│ • Multi-AZ High Availability │ +└───────────────────────────────────────────────────────────┘ +``` + +## Cost Optimization Strategy + +This example implements a **three-tier storage strategy** that can reduce storage costs by up to **95%**: + +| Storage Class | Cost/GB-Month | Use Case | Transition | +|--------------|---------------|----------|------------| +| **Standard** | ~$0.30 | Active files | Default | +| **Infrequent Access** | ~$0.025 | Files not accessed for 30 days | Automatic | +| **Archive** | ~$0.016 | Long-term retention (90+ days) | Automatic | + +### Example Savings + +For a 1TB file system where: +- 20% (200GB) files are actively used → Standard: $60/month +- 30% (300GB) files accessed occasionally → IA: $7.50/month +- 50% (500GB) files are archived → Archive: $8/month + +**Total: $75.50/month vs $300/month (75% savings)** + +## Configuration Options Demonstrated + +### 1. Storage Classes and Lifecycle Management + +Automatic cost optimization through intelligent data tiering: + +```hcl +lifecycle_policy = { + transition_to_ia = "AFTER_30_DAYS" # 92% cost reduction + transition_to_primary_storage_class = "AFTER_1_ACCESS" # Performance on demand + transition_to_archive = "AFTER_90_DAYS" # 95% cost reduction +} +``` + +### 2. Throughput Modes Comparison + +| Mode | Best For | Cost Model | Configuration | +|------|----------|------------|---------------| +| **Elastic** | Variable workloads | Pay for actual use | Default (recommended) | +| **Bursting** | Predictable baseline | Scales with size | Set `throughput_mode = "bursting"` | +| **Provisioned** | Guaranteed performance | Fixed cost | Set `throughput_mode = "provisioned"` + `provisioned_throughput_in_mibps` | + +### 3. Storage Deployment Options + +**Multi-AZ (Default - High Availability)** +```hcl +# availability_zone_name = null # Default, creates Multi-AZ +``` +- ✅ High availability across multiple zones +- ✅ Recommended for production +- ❌ Higher cost + +**One Zone (Cost Optimized)** +```hcl +availability_zone_name = "us-east-1a" +``` +- ✅ ~47% lower storage costs +- ✅ Good for non-critical workloads +- ❌ Single AZ availability + +## Usage + +### Prerequisites +- AWS credentials configured +- Terraform ~> 1.0 installed +- Understanding of your workload's access patterns + +### Deploy + +```bash +cd examples/complete + +# Initialize Terraform +terraform init + +# Review the comprehensive plan +terraform plan -var-file=test.tfvars + +# Apply with all features +terraform apply -var-file=test.tfvars +``` + +### Monitor Lifecycle Transitions + +After deployment, monitor storage class transitions: + +```bash +# View file system details +aws efs describe-file-systems --file-system-id $(terraform output -raw file_system_id) + +# Check lifecycle policy status +aws efs describe-lifecycle-configuration --file-system-id $(terraform output -raw file_system_id) +``` + +### View All Outputs + +```bash +terraform output + +# Example outputs: +# file_system_id = "fs-03cee4f754a47d6e5" +# file_system_dns_name = "fs-03cee4f754a47d6e5.efs.us-west-2.amazonaws.com" +# file_system_size_in_bytes = {...} +``` + +### Clean Up + +```bash +terraform destroy -var-file=test.tfvars +``` + +## Customization Guide + +### Adjust Lifecycle Policy Timings + +Modify transition periods based on your data access patterns: + +```hcl +lifecycle_policy = { + transition_to_ia = "AFTER_7_DAYS" # More aggressive savings + transition_to_archive = "AFTER_30_DAYS" # Faster archival +} +``` + +### Enable Customer Managed Encryption + +```hcl +kms_key_id = "arn:aws:kms:region:account:key/key-id" +``` + +### Use One Zone Storage + +```hcl +availability_zone_name = "us-east-1a" # Choose your preferred AZ +``` + +### Switch to Provisioned Throughput + +```hcl +throughput_mode = "provisioned" +provisioned_throughput_in_mibps = 100 # MiB/s +``` + +## Best Practices Implemented + +1. ✅ **Cost Optimization**: Lifecycle policies reduce storage costs by up to 95% +2. ✅ **Performance**: Elastic throughput automatically scales with workload +3. ✅ **Security**: Encryption at rest enabled by default +4. ✅ **Reliability**: Multi-AZ storage for high availability +5. ✅ **Observability**: Comprehensive outputs for monitoring +6. ✅ **Compliance**: Tagging strategy for cost allocation and governance + +## Production Considerations + +### After Deployment + +1. **Create Mount Targets**: Deploy in private subnets across AZs +2. **Configure Security Groups**: Allow NFS traffic (port 2049) from compute resources +3. **Set Up Monitoring**: Enable CloudWatch metrics and alarms +4. **Configure Backups**: Use AWS Backup for point-in-time recovery +5. **Test Restore Procedures**: Validate backup and recovery processes + +### Mount the File System + +```bash +# On Amazon Linux 2 +sudo yum install -y amazon-efs-utils +sudo mount -t efs -o tls fs-xxxxx:/ /mnt/efs + +# On other Linux distributions +sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 \ + fs-xxxxx.efs.region.amazonaws.com:/ /mnt/efs +``` + +## Resources Created + +- **1 EFS File System** with: + - ✅ Encryption enabled (AWS managed key, customer key supported) + - ✅ Elastic throughput mode (automatic scaling) + - ✅ Three-tier lifecycle policy (Standard → IA → Archive) + - ✅ Protection configuration (replication controls) + - ✅ Comprehensive tagging (cost allocation, compliance) + - ✅ All outputs exposed (monitoring, integration) + +## Comparison with Simple Example + +| Feature | Simple Example | Complete Example | +|---------|----------------|------------------| +| Encryption | ✅ AWS managed | ✅ AWS or customer managed | +| Throughput Mode | Bursting | **Elastic** (recommended) | +| Lifecycle Policies | ❌ None | ✅ Full optimization | +| Storage Classes | Standard only | **Standard + IA + Archive** | +| Cost Optimization | None | **Up to 95% savings** | +| Production Ready | Development use | ✅ Production ready | + +## Additional Resources + +- [AWS EFS Documentation](https://docs.aws.amazon.com/efs/) +- [EFS Lifecycle Management](https://docs.aws.amazon.com/efs/latest/ug/lifecycle-management-efs.html) +- [EFS Performance Guide](https://docs.aws.amazon.com/efs/latest/ug/performance.html) +- [Module Source Code](../../main.tf) + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [aws](#requirement\_aws) | ~> 5.100 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [resource\_names](#module\_resource\_names) | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 2.0 | +| [efs\_complete](#module\_efs\_complete) | ../../ | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [logical\_product\_family](#input\_logical\_product\_family) | (Required) Name of the product family for which the resource is created.
Example: org\_name, department\_name. | `string` | `"launch"` | no | +| [logical\_product\_service](#input\_logical\_product\_service) | (Required) Name of the product service for which the resource is created.
For example, backend, frontend, middleware etc. | `string` | `"backend"` | no | +| [instance\_resource](#input\_instance\_resource) | Number that represents the instance of the resource. | `number` | `0` | no | +| [instance\_env](#input\_instance\_env) | Number that represents the instance of the environment. | `number` | `0` | no | +| [class\_env](#input\_class\_env) | (Required) Environment where resource is going to be deployed. For example. dev, qa, uat | `string` | `"dev"` | no | +| [resource\_names\_map](#input\_resource\_names\_map) | A map of key to resource\_name that will be used by tf-launch-module\_library-resource\_name to generate resource names |
map(object(
{
name = string
max_length = optional(number, 60)
}
))
| `{}` | no | +| [region](#input\_region) | (Required) The location where the resource will be created. Must not have spaces
For example, us-east-1, us-west-2, eu-west-1, etc. | `string` | `"us-east-2"` | no | +| [creation\_token](#input\_creation\_token) | Optional unique identifier for the EFS file system. If not provided, will use the generated or provided name value | `string` | `null` | no | +| [name](#input\_name) | Optional name for the EFS file system. If not provided, a generated name from resource\_names module will be used | `string` | `null` | no | +| [availability\_zone\_name](#input\_availability\_zone\_name) | The AWS Availability Zone in which to create the file system. Used to create a file system that uses One Zone storage classes | `string` | `null` | no | +| [encrypted](#input\_encrypted) | If true, the disk will be encrypted | `bool` | `true` | no | +| [kms\_key\_id](#input\_kms\_key\_id) | ARN for the KMS encryption key. If set, the EFS file system will be encrypted at rest using this key | `string` | `null` | no | +| [performance\_mode](#input\_performance\_mode) | The file system performance mode. Valid values: 'generalPurpose' (default, lower latency) or 'maxIO' (higher aggregate throughput) | `string` | `"generalPurpose"` | no | +| [throughput\_mode](#input\_throughput\_mode) | Throughput mode for the file system. Valid values: 'bursting', 'provisioned', or 'elastic' | `string` | `"elastic"` | no | +| [provisioned\_throughput\_in\_mibps](#input\_provisioned\_throughput\_in\_mibps) | The throughput, measured in MiB/s, that you want to provision for the file system. Only applicable when throughput\_mode is set to 'provisioned' | `number` | `null` | no | +| [lifecycle\_policy](#input\_lifecycle\_policy) | Lifecycle policy for the file system |
object({
transition_to_ia = optional(string)
transition_to_primary_storage_class = optional(string)
transition_to_archive = optional(string)
})
|
{
"transition_to_archive": "AFTER_90_DAYS",
"transition_to_ia": "AFTER_30_DAYS",
"transition_to_primary_storage_class": "AFTER_1_ACCESS"
}
| no | +| [protection](#input\_protection) | Protection configuration for the file system |
object({
replication_overwrite = optional(string)
})
|
{
"replication_overwrite": "DISABLED"
}
| no | +| [tags](#input\_tags) | A map of tags to assign to the EFS file system | `map(string)` |
{
"Application": "web-app",
"CostCenter": "engineering",
"Environment": "production",
"Example": "complete",
"ManagedBy": "Terraform"
}
| no | + +## Outputs + +| Name | Description | +|------|-------------| +| [file\_system\_id](#output\_file\_system\_id) | The ID of the EFS file system | +| [file\_system\_arn](#output\_file\_system\_arn) | Amazon Resource Name of the file system | +| [file\_system\_dns\_name](#output\_file\_system\_dns\_name) | The DNS name for the filesystem | +| [file\_system\_creation\_token](#output\_file\_system\_creation\_token) | The creation token of the EFS file system | +| [file\_system\_availability\_zone\_id](#output\_file\_system\_availability\_zone\_id) | The identifier of the Availability Zone in which the file system's One Zone storage classes exist | +| [file\_system\_availability\_zone\_name](#output\_file\_system\_availability\_zone\_name) | The Availability Zone name in which the file system's One Zone storage classes exist | +| [file\_system\_number\_of\_mount\_targets](#output\_file\_system\_number\_of\_mount\_targets) | The current number of mount targets that the file system has | +| [file\_system\_owner\_id](#output\_file\_system\_owner\_id) | The AWS account that created the file system | +| [file\_system\_size\_in\_bytes](#output\_file\_system\_size\_in\_bytes) | The latest known metered size (in bytes) of data stored in the file system | +| [file\_system\_name](#output\_file\_system\_name) | The value of the file system's Name tag | + diff --git a/examples/complete/main.tf b/examples/complete/main.tf new file mode 100644 index 0000000..655971e --- /dev/null +++ b/examples/complete/main.tf @@ -0,0 +1,108 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Complete Example - Full-Featured EFS File System Configuration +// +// This example demonstrates all available configuration options for creating an EFS file system. +// It showcases advanced features suitable for production environments including: +// - Lifecycle policies for automatic cost optimization +// - Elastic throughput mode for automatic performance scaling +// - Protection configuration for replication control +// - Comprehensive tagging strategy +// +// Cost Optimization Strategy: +// This example implements a three-tier storage strategy: +// 1. Files are automatically moved to Infrequent Access (IA) storage after 30 days of inactivity +// 2. Files are moved to Archive storage after 90 days for long-term retention +// 3. Files are automatically moved back to Standard storage on first access for optimal performance +// +// Performance Configuration: +// - Elastic throughput mode automatically scales based on workload +// - No need to provision or manage throughput capacity +// - Pay only for actual throughput used +// +// This configuration is ideal for: +// - Production workloads with variable access patterns +// - Applications requiring cost optimization +// - Workloads with predictable lifecycle patterns (e.g., logs, archives, backups) + +module "resource_names" { + # checkov:skip=CKV_TF_1: trusted module source + source = "terraform.registry.launch.nttdata.com/module_library/resource_name/launch" + version = "~> 2.0" + + for_each = var.resource_names_map + + logical_product_family = var.logical_product_family + logical_product_service = var.logical_product_service + region = join("", split("-", var.region)) + class_env = var.class_env + cloud_resource_type = each.value.name + instance_env = var.instance_env + instance_resource = var.instance_resource + maximum_length = each.value.max_length +} + + +module "efs_complete" { + source = "../../" + + # Unique identifier for the EFS file system within AWS account and region + # Uses var.creation_token if provided, otherwise uses the EFS name + creation_token = var.creation_token != null ? var.creation_token : module.resource_names["efs"].standard + + # Friendly name for AWS Console identification + # Automatically creates a 'Name' tag + # Uses var.name if provided, otherwise uses generated name from resource_names module + name = var.name != null ? var.name : module.resource_names["efs"].standard + + # Optional: Specify an Availability Zone for One Zone storage class + # Leave null (default) for Multi-AZ storage with high availability + # One Zone storage reduces costs but provides lower availability + availability_zone_name = var.availability_zone_name + + # Encryption configuration + # Always enable encryption for production workloads + encrypted = var.encrypted + + # Optional: Customer managed KMS key ARN for encryption + # Leave null to use AWS managed key (aws/elasticfilesystem) + kms_key_id = var.kms_key_id + + # Performance mode configuration + # - generalPurpose: Lower latency, suitable for most workloads (recommended) + # - maxIO: Higher aggregate throughput for highly parallelized workloads + performance_mode = var.performance_mode + + # Throughput mode configuration + # - elastic: Automatically scales throughput based on workload (recommended for production) + # - bursting: Throughput scales with file system size + # - provisioned: Fixed throughput, requires provisioned_throughput_in_mibps + throughput_mode = var.throughput_mode + + # Required only when throughput_mode = "provisioned" + # Specifies the throughput in MiB/s to provision + provisioned_throughput_in_mibps = var.provisioned_throughput_in_mibps + + # Lifecycle policy for automatic storage class transitions + # Reduces costs by moving infrequently accessed files to lower-cost storage tiers + # Note: Archive transitions require Elastic throughput and General Purpose performance mode + lifecycle_policy = var.lifecycle_policy + + # Protection configuration for replication behavior + # Controls whether replication can overwrite data in this file system + protection = var.protection + + # Resource tags for organization, cost allocation, and compliance + # Module automatically adds 'ManagedBy = Terraform' tag + tags = var.tags +} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf new file mode 100644 index 0000000..9e46527 --- /dev/null +++ b/examples/complete/outputs.tf @@ -0,0 +1,61 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +output "file_system_id" { + description = "The ID of the EFS file system" + value = module.efs_complete.file_system_id +} + +output "file_system_arn" { + description = "Amazon Resource Name of the file system" + value = module.efs_complete.file_system_arn +} + +output "file_system_dns_name" { + description = "The DNS name for the filesystem" + value = module.efs_complete.file_system_dns_name +} + +output "file_system_creation_token" { + description = "The creation token of the EFS file system" + value = module.efs_complete.file_system_creation_token +} + +output "file_system_availability_zone_id" { + description = "The identifier of the Availability Zone in which the file system's One Zone storage classes exist" + value = module.efs_complete.file_system_availability_zone_id +} + +output "file_system_availability_zone_name" { + description = "The Availability Zone name in which the file system's One Zone storage classes exist" + value = module.efs_complete.file_system_availability_zone_name +} + +output "file_system_number_of_mount_targets" { + description = "The current number of mount targets that the file system has" + value = module.efs_complete.file_system_number_of_mount_targets +} + +output "file_system_owner_id" { + description = "The AWS account that created the file system" + value = module.efs_complete.file_system_owner_id +} + +output "file_system_size_in_bytes" { + description = "The latest known metered size (in bytes) of data stored in the file system" + value = module.efs_complete.file_system_size_in_bytes +} + +output "file_system_name" { + description = "The value of the file system's Name tag" + value = module.efs_complete.file_system_name +} diff --git a/examples/complete/test.tfvars b/examples/complete/test.tfvars new file mode 100644 index 0000000..22d33ce --- /dev/null +++ b/examples/complete/test.tfvars @@ -0,0 +1,91 @@ +# Complete example configuration for EFS File System +# This example demonstrates all available features and configurations +# Copy this file to test.tfvars and customize the values as needed + +# Naming Module Configuration +logical_product_family = "launch" +logical_product_service = "efs" +class_env = "sandbox" +instance_env = 0 +instance_resource = 0 +region = "us-west-2" + +# Resource names map for generating standardized names +resource_names_map = { + efs = { + name = "fs" + max_length = 60 + } +} + +# Unique identifier for the EFS file system +# Commented out to use generated name from resource_names module +# creation_token = "my-complete-efs" + +# (Optional) Friendly name for the EFS file system +# Will be added as a 'Name' tag for easier identification in the AWS console +# Commented out to use generated name from resource_names module +# name = "Complete EFS Example" + +# (Optional) Specify an Availability Zone for One Zone storage class +# Leave null for Multi-AZ storage (recommended for production) +# Uncomment to use One Zone storage (lower cost, single AZ): +# availability_zone_name = "us-east-1a" + +# Enable encryption at rest (recommended for production) +encrypted = true + +# (Optional) KMS Key ARN for customer-managed encryption +# Leave null to use AWS managed key (aws/elasticfilesystem) +# Uncomment and provide your KMS key ARN: +# kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + +# Performance mode +# - generalPurpose: Lower latency, suitable for most workloads +# - maxIO: Higher throughput, suitable for highly parallelized workloads +performance_mode = "generalPurpose" + +# Throughput mode +# - bursting: Scales with file system size (default) +# - elastic: Automatically scales up/down based on workload (recommended) +# - provisioned: Fixed throughput (requires provisioned_throughput_in_mibps) +throughput_mode = "elastic" + +# (Optional) Provisioned throughput in MiB/s +# Only used when throughput_mode = "provisioned" +# Uncomment if using provisioned mode: +# provisioned_throughput_in_mibps = 100 + +# Lifecycle policy configuration +# Automatically transitions files between storage classes based on access patterns +lifecycle_policy = { + # Move files to Infrequent Access (IA) after specified period + # Options: AFTER_1_DAY, AFTER_7_DAYS, AFTER_14_DAYS, AFTER_30_DAYS, AFTER_60_DAYS, + # AFTER_90_DAYS, AFTER_180_DAYS, AFTER_270_DAYS, AFTER_365_DAYS + transition_to_ia = "AFTER_30_DAYS" + + # Move files back to primary storage after first access + # Options: AFTER_1_ACCESS (or null to disable) + transition_to_primary_storage_class = "AFTER_1_ACCESS" + + # Move files to Archive storage after specified period + # Options: Same as transition_to_ia (or null to disable) + transition_to_archive = "AFTER_90_DAYS" +} + +# Protection configuration +# Controls replication behavior +protection = { + # Replication overwrite protection + # Options: ENABLED, DISABLED, REPLICATING + replication_overwrite = "DISABLED" +} + +# Tags to apply to the EFS file system +tags = { + Environment = "production" + Example = "complete" + Application = "web-app" + ManagedBy = "Terraform" + CostCenter = "engineering" +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf new file mode 100644 index 0000000..ef27475 --- /dev/null +++ b/examples/complete/variables.tf @@ -0,0 +1,187 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +# Naming Module Variables +variable "logical_product_family" { + type = string + description = <= 0 && var.instance_resource <= 100 + error_message = "Instance number should be between 1 to 100." + } +} + +variable "instance_env" { + type = number + description = "Number that represents the instance of the environment." + default = 0 + + validation { + condition = var.instance_env >= 0 && var.instance_env <= 999 + error_message = "Instance number should be between 1 to 999." + } +} + +variable "class_env" { + type = string + default = "dev" + description = "(Required) Environment where resource is going to be deployed. For example. dev, qa, uat" + nullable = false + + validation { + condition = length(regexall("\\b \\b", var.class_env)) == 0 + error_message = "Spaces between the words are not allowed." + } +} + +variable "resource_names_map" { + description = "A map of key to resource_name that will be used by tf-launch-module_library-resource_name to generate resource names" + type = map(object( + { + name = string + max_length = optional(number, 60) + } + )) + default = {} +} + +variable "region" { + type = string + description = < 1.0 installed + +### Deploy + +```bash +# Initialize Terraform +terraform init + +# Review the plan +terraform plan -var-file=test.tfvars + +# Apply the configuration +terraform apply -var-file=test.tfvars + +# View outputs +terraform output +``` + +### Clean Up + +```bash +terraform destroy -var-file=test.tfvars +``` + +## Configuration + +The example uses default values for most parameters. To customize: + +1. **Update `test.tfvars`** with your values: + ```hcl + creation_token = "my-unique-efs-name" + name = "My Development EFS" + ``` + +2. **Optionally modify `variables.tf`** to change defaults + +3. **Review and apply** the changes + +## Expected Outputs + +After successful deployment, you'll receive: + +- `file_system_id`: EFS file system ID (e.g., `fs-12345678`) +- `file_system_arn`: Full ARN of the file system +- `file_system_dns_name`: DNS name for mounting (e.g., `fs-12345678.efs.us-east-1.amazonaws.com`) +- `file_system_creation_token`: The unique creation token +- Additional outputs for availability zones, mount targets, size, etc. + +## Next Steps + +After creating the EFS file system: + +1. **Create mount targets** in your VPC subnets (not included in this module) +2. **Configure security groups** to allow NFS traffic (port 2049) +3. **Mount the file system** to your EC2 instances or containers +4. **Consider the complete example** for production use with cost optimization + +## Cost Estimation + +This simple configuration will incur: +- **Storage costs**: ~$0.30/GB-month (Standard storage class) +- **No throughput costs** with bursting mode +- **No data transfer costs** within the same AZ + +For cost optimization with lifecycle policies, see the [complete example](../complete/). + +## Resources Created + +- **1 EFS File System** with: + - Encryption enabled (AWS managed key) + - Multi-AZ storage for high availability + - General Purpose performance mode + - Bursting throughput mode + - Name tag for easy identification + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [aws](#requirement\_aws) | ~> 5.100 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [resource\_names](#module\_resource\_names) | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 2.0 | +| [efs](#module\_efs) | ../../ | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [logical\_product\_family](#input\_logical\_product\_family) | Logical product family name for naming convention | `string` | n/a | yes | +| [logical\_product\_service](#input\_logical\_product\_service) | Logical product service name for naming convention | `string` | n/a | yes | +| [class\_env](#input\_class\_env) | Environment class for naming convention (e.g., sandbox, dev, prod) | `string` | n/a | yes | +| [instance\_env](#input\_instance\_env) | Environment instance number for naming convention | `number` | n/a | yes | +| [instance\_resource](#input\_instance\_resource) | Resource instance number for naming convention | `number` | n/a | yes | +| [region](#input\_region) | AWS region for naming convention | `string` | n/a | yes | +| [resource\_names\_map](#input\_resource\_names\_map) | Map of resource types to their configurations for name generation |
map(object({
name = string
max_length = optional(number, 60)
}))
| `{}` | no | +| [creation\_token](#input\_creation\_token) | Optional unique identifier for the EFS file system. If not provided, will use the generated or provided name value | `string` | `null` | no | +| [name](#input\_name) | Optional name for the EFS file system. If not provided, a generated name from resource\_names module will be used | `string` | `null` | no | +| [encrypted](#input\_encrypted) | If true, the disk will be encrypted | `bool` | `true` | no | +| [kms\_key\_id](#input\_kms\_key\_id) | ARN for the KMS encryption key. Required if encrypted is true | `string` | `null` | no | +| [performance\_mode](#input\_performance\_mode) | The file system performance mode. Valid values: 'generalPurpose' (default, lower latency) or 'maxIO' (higher aggregate throughput) | `string` | `"generalPurpose"` | no | +| [throughput\_mode](#input\_throughput\_mode) | Throughput mode for the file system. Valid values: 'bursting' (scales with file system size), 'elastic' (auto-scaling), or 'provisioned' (fixed throughput) | `string` | `"bursting"` | no | +| [tags](#input\_tags) | A map of tags to assign to the EFS file system | `map(string)` |
{
"Environment": "dev",
"Example": "simple"
}
| no | + +## Outputs + +| Name | Description | +|------|-------------| +| [file\_system\_id](#output\_file\_system\_id) | The ID of the EFS file system | +| [file\_system\_arn](#output\_file\_system\_arn) | Amazon Resource Name of the file system | +| [file\_system\_dns\_name](#output\_file\_system\_dns\_name) | The DNS name for the filesystem | +| [file\_system\_creation\_token](#output\_file\_system\_creation\_token) | The creation token of the EFS file system | +| [file\_system\_availability\_zone\_id](#output\_file\_system\_availability\_zone\_id) | The identifier of the Availability Zone in which the file system's One Zone storage classes exist | +| [file\_system\_availability\_zone\_name](#output\_file\_system\_availability\_zone\_name) | The Availability Zone name in which the file system's One Zone storage classes exist | +| [file\_system\_number\_of\_mount\_targets](#output\_file\_system\_number\_of\_mount\_targets) | The current number of mount targets that the file system has | +| [file\_system\_owner\_id](#output\_file\_system\_owner\_id) | The AWS account that created the file system | +| [file\_system\_size\_in\_bytes](#output\_file\_system\_size\_in\_bytes) | The latest known metered size (in bytes) of data stored in the file system | +| [file\_system\_name](#output\_file\_system\_name) | The value of the file system's Name tag | + diff --git a/examples/simple/main.tf b/examples/simple/main.tf new file mode 100644 index 0000000..9c817c9 --- /dev/null +++ b/examples/simple/main.tf @@ -0,0 +1,82 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Simple Example - Basic EFS File System Configuration +// +// This example demonstrates the minimal configuration needed to create an EFS file system +// with encryption enabled and default performance settings. It's suitable for: +// - Development and testing environments +// - Getting started with EFS +// - Understanding the basic required parameters +// +// Features demonstrated: +// - Encrypted EFS file system (AWS managed key) +// - General Purpose performance mode (default) +// - Bursting throughput mode (scales with file system size) +// - Basic tagging for resource identification +// +// Not included (but available in complete example): +// - Customer managed KMS key +// - Lifecycle policies for cost optimization +// - One Zone storage class +// - Elastic or provisioned throughput modes +// - Protection configuration + +module "resource_names" { + # checkov:skip=CKV_TF_1: trusted module source + source = "terraform.registry.launch.nttdata.com/module_library/resource_name/launch" + version = "~> 2.0" + + for_each = var.resource_names_map + + logical_product_family = var.logical_product_family + logical_product_service = var.logical_product_service + region = var.region + class_env = var.class_env + cloud_resource_type = each.value.name + instance_env = var.instance_env + maximum_length = each.value.max_length + instance_resource = var.instance_resource +} + +module "efs" { + source = "../../" + + # Unique identifier for the EFS file system within AWS account and region + # Uses var.creation_token if provided, otherwise uses the EFS name + creation_token = var.creation_token != null ? var.creation_token : module.resource_names["efs"].standard + + # Friendly name for AWS Console identification + # Automatically creates a 'Name' tag + # Uses var.name if provided, otherwise uses generated name from resource_names module + name = var.name != null ? var.name : module.resource_names["efs"].standard + + # Enable encryption at rest using AWS managed key + # Set to false only if encryption is not required (not recommended) + encrypted = var.encrypted + + # KMS key for encryption (null = use AWS managed key) + # Uncomment and provide ARN to use customer managed key + kms_key_id = var.kms_key_id + + # Performance mode: generalPurpose (default, lower latency) or maxIO (higher throughput) + # General Purpose is suitable for most workloads + performance_mode = var.performance_mode + + # Throughput mode: bursting (scales with size), elastic (auto-scaling), or provisioned (fixed) + # Bursting is cost-effective for workloads with baseline throughput needs + throughput_mode = var.throughput_mode + + # Custom tags for resource management and cost allocation + # Module automatically adds 'ManagedBy = Terraform' tag + tags = var.tags +} diff --git a/examples/simple/outputs.tf b/examples/simple/outputs.tf new file mode 100644 index 0000000..e35463d --- /dev/null +++ b/examples/simple/outputs.tf @@ -0,0 +1,61 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +output "file_system_id" { + description = "The ID of the EFS file system" + value = module.efs.file_system_id +} + +output "file_system_arn" { + description = "Amazon Resource Name of the file system" + value = module.efs.file_system_arn +} + +output "file_system_dns_name" { + description = "The DNS name for the filesystem" + value = module.efs.file_system_dns_name +} + +output "file_system_creation_token" { + description = "The creation token of the EFS file system" + value = module.efs.file_system_creation_token +} + +output "file_system_availability_zone_id" { + description = "The identifier of the Availability Zone in which the file system's One Zone storage classes exist" + value = module.efs.file_system_availability_zone_id +} + +output "file_system_availability_zone_name" { + description = "The Availability Zone name in which the file system's One Zone storage classes exist" + value = module.efs.file_system_availability_zone_name +} + +output "file_system_number_of_mount_targets" { + description = "The current number of mount targets that the file system has" + value = module.efs.file_system_number_of_mount_targets +} + +output "file_system_owner_id" { + description = "The AWS account that created the file system" + value = module.efs.file_system_owner_id +} + +output "file_system_size_in_bytes" { + description = "The latest known metered size (in bytes) of data stored in the file system" + value = module.efs.file_system_size_in_bytes +} + +output "file_system_name" { + description = "The value of the file system's Name tag" + value = module.efs.file_system_name +} diff --git a/examples/simple/test.tfvars b/examples/simple/test.tfvars new file mode 100644 index 0000000..1693c52 --- /dev/null +++ b/examples/simple/test.tfvars @@ -0,0 +1,53 @@ +# Example configuration for EFS File System +# Copy this file to test.tfvars and customize the values as needed + +# Naming Module Configuration +logical_product_family = "launch" +logical_product_service = "efs" +class_env = "sandbox" +instance_env = 1 +instance_resource = 0 +region = "us-west-2" + +# Resource names map for generating standardized names +resource_names_map = { + efs = { + name = "fs" + max_length = 60 + } +} + +# Unique identifier for the EFS file system +# This should be unique within your AWS account and region +# Commented out to use generated name from resource_names module +creation_token = "simple-efs-example" + +# (Optional) Friendly name for the EFS file system +# Will be added as a 'Name' tag for easier identification in the AWS console +# Commented out to use generated name from resource_names module +name = "Simple EFS Example" + +# Enable encryption at rest for the EFS file system +# Set to false if encryption is not required (not recommended for production) +encrypted = true + +# (Optional) KMS Key ARN for encryption +# Leave commented out to use AWS managed key (aws/elasticfilesystem) +# Uncomment and provide your KMS key ARN if using customer managed keys +# kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + +# Performance mode for the file system +# Options: "generalPurpose" (default, recommended for most workloads) or "maxIO" (for high throughput) +performance_mode = "generalPurpose" + +# Throughput mode for the file system +# Options: "bursting" (scales with file system size) or "provisioned" (fixed throughput) +throughput_mode = "bursting" + +# Tags to apply to the EFS file system +# These will be merged with default tags (ManagedBy = "Terraform") +tags = { + Environment = "test" + Example = "simple" + Purpose = "testing" +} diff --git a/examples/simple/variables.tf b/examples/simple/variables.tf new file mode 100644 index 0000000..464f445 --- /dev/null +++ b/examples/simple/variables.tf @@ -0,0 +1,96 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +# Naming Module Variables +variable "logical_product_family" { + description = "Logical product family name for naming convention" + type = string +} + +variable "logical_product_service" { + description = "Logical product service name for naming convention" + type = string +} + +variable "class_env" { + description = "Environment class for naming convention (e.g., sandbox, dev, prod)" + type = string +} + +variable "instance_env" { + description = "Environment instance number for naming convention" + type = number +} + +variable "instance_resource" { + description = "Resource instance number for naming convention" + type = number +} + +variable "region" { + description = "AWS region for naming convention" + type = string +} + +variable "resource_names_map" { + description = "Map of resource types to their configurations for name generation" + type = map(object({ + name = string + max_length = optional(number, 60) + })) + default = {} +} + +variable "creation_token" { + description = "Optional unique identifier for the EFS file system. If not provided, will use the generated or provided name value" + type = string + default = null +} + +variable "name" { + description = "Optional name for the EFS file system. If not provided, a generated name from resource_names module will be used" + type = string + default = null +} + +variable "encrypted" { + description = "If true, the disk will be encrypted" + type = bool + default = true +} + +variable "kms_key_id" { + description = "ARN for the KMS encryption key. Required if encrypted is true" + type = string + default = null +} + +variable "performance_mode" { + description = "The file system performance mode. Valid values: 'generalPurpose' (default, lower latency) or 'maxIO' (higher aggregate throughput)" + type = string + default = "generalPurpose" +} + +variable "throughput_mode" { + description = "Throughput mode for the file system. Valid values: 'bursting' (scales with file system size), 'elastic' (auto-scaling), or 'provisioned' (fixed throughput)" + type = string + default = "bursting" +} + +variable "tags" { + description = "A map of tags to assign to the EFS file system" + type = map(string) + default = { + Environment = "dev" + Example = "simple" + } +} diff --git a/examples/simple/versions.tf b/examples/simple/versions.tf new file mode 100644 index 0000000..d2ef75a --- /dev/null +++ b/examples/simple/versions.tf @@ -0,0 +1,22 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +terraform { + required_version = "~> 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.100" + } + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..09e3951 --- /dev/null +++ b/go.mod @@ -0,0 +1,112 @@ +module github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system + +go 1.24 + +require ( + github.com/aws/aws-sdk-go-v2 v1.40.0 + github.com/aws/aws-sdk-go-v2/config v1.26.6 + github.com/aws/aws-sdk-go-v2/service/efs v1.41.5 + github.com/gruntwork-io/terratest v0.46.8 + github.com/launchbynttdata/lcaf-component-terratest v1.0.4 + github.com/stretchr/testify v1.8.4 +) + +require ( + cloud.google.com/go v0.110.0 // indirect + cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.13.0 // indirect + cloud.google.com/go/storage v1.28.1 // indirect + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/aws/aws-sdk-go v1.44.122 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect + github.com/aws/smithy-go v1.23.2 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/gruntwork-io/go-commons v0.8.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.1 // indirect + github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/hcl/v2 v2.9.1 // indirect + github.com/hashicorp/terraform-json v0.13.0 // indirect + github.com/imdario/mergo v0.3.11 // indirect + github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pquerna/otp v1.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/tmccombs/hcl2json v0.3.3 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/urfave/cli v1.22.2 // indirect + github.com/zclconf/go-cty v1.9.1 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.114.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.56.3 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.28.4 // indirect + k8s.io/apimachinery v0.28.4 // indirect + k8s.io/client-go v0.28.4 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..57dcbde --- /dev/null +++ b/go.sum @@ -0,0 +1,1114 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= +github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo= +github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.5 h1:rDc7Vz41BIR4ju1V386OZ8ozzncWfzRk+ZMqemg8OXQ= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.5/go.mod h1:SZ37SpJcrcW0J8EwoCkUWbz4eZ1+qCNCyu6e+0+8Oto= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= +github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= +github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= +github.com/gruntwork-io/terratest v0.46.8 h1:rgK7z6Dy/eMGFaclKR0WVG9Z54tR+Ehl7S09+8Y25j0= +github.com/gruntwork-io/terratest v0.46.8/go.mod h1:6MxfmOFQQEpQZjpuWRwuAK8qm836hYgAOCzSIZIWTmg= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= +github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl/v2 v2.9.1 h1:eOy4gREY0/ZQHNItlfuEZqtcQbXIxzojlP301hDpnac= +github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= +github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY= +github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/launchbynttdata/lcaf-component-terratest v1.0.4 h1:uSnkCKT30Ua5ySJIusNDYsG2sHa71nVn+3N8mV9e5fc= +github.com/launchbynttdata/lcaf-component-terratest v1.0.4/go.mod h1:olva1OkdJd+5ToVT+lLP05kYln6aFu7rSosPVep29sw= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 h1:ofNAzWCcyTALn2Zv40+8XitdzCgXY6e9qvXwN9W0YXg= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= +github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tmccombs/hcl2json v0.3.3 h1:+DLNYqpWE0CsOQiEZu+OZm5ZBImake3wtITYxQ8uLFQ= +github.com/tmccombs/hcl2json v0.3.3/go.mod h1:Y2chtz2x9bAeRTvSibVRVgbLJhLJXKlUeIvjeVdnm4w= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.9.1 h1:viqrgQwFl5UpSxc046qblj78wZXVDFnSOufaOTER+cc= +github.com/zclconf/go-cty v1.9.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= +k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= +k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/local.tf b/local.tf new file mode 100644 index 0000000..41e4195 --- /dev/null +++ b/local.tf @@ -0,0 +1,9 @@ +locals { + tags = merge( + { + "ManagedBy" = "Terraform" + "Name" = var.name + }, + var.tags, + ) +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..f50e027 --- /dev/null +++ b/main.tf @@ -0,0 +1,74 @@ +# AWS EFS File System Resource +# This module creates an AWS Elastic File System (EFS) with configurable options for encryption, +# performance, throughput, and lifecycle policies. +# +# Key Features: +# - Encryption at rest (AWS managed or customer managed KMS key) +# - Multi-AZ or One Zone storage classes +# - Configurable performance modes (generalPurpose or maxIO) +# - Flexible throughput modes (bursting, elastic, or provisioned) +# - Automated lifecycle management for cost optimization +# - Replication protection controls +resource "aws_efs_file_system" "this" { + # Required unique identifier for the file system within the AWS account and region + creation_token = var.creation_token + + # Optional: Specify an Availability Zone for One Zone storage (lower cost, single AZ) + # If omitted, the file system uses Multi-AZ storage for high availability + availability_zone_name = var.availability_zone_name + + # Encryption configuration + encrypted = var.encrypted + kms_key_id = var.kms_key_id # Optional: Use customer managed KMS key, otherwise uses AWS managed key + + # Performance and throughput configuration + performance_mode = var.performance_mode # generalPurpose (default) or maxIO + throughput_mode = var.throughput_mode # bursting, elastic, or provisioned + provisioned_throughput_in_mibps = var.provisioned_throughput_in_mibps # Required only for provisioned mode + + # Lifecycle Policies - Important Implementation Note: + # AWS Provider 5.100.0 requires SEPARATE lifecycle_policy blocks for each transition type. + # Each transition (to IA, to Archive, to Primary) must be in its own block. + # This is different from some other AWS resources that accept all options in a single block. + # Reference: https://registry.terraform.io/providers/hashicorp/aws/5.100.0/docs/resources/efs_file_system + + # Transition files to Infrequent Access (IA) storage class after specified period + # Reduces storage costs for files that are not accessed frequently + dynamic "lifecycle_policy" { + for_each = var.lifecycle_policy != null && var.lifecycle_policy.transition_to_ia != null ? [var.lifecycle_policy.transition_to_ia] : [] + content { + transition_to_ia = lifecycle_policy.value + } + } + + # Transition files back to primary storage class after first access + # Optimizes for files that become active again after being moved to IA + dynamic "lifecycle_policy" { + for_each = var.lifecycle_policy != null && var.lifecycle_policy.transition_to_primary_storage_class != null ? [var.lifecycle_policy.transition_to_primary_storage_class] : [] + content { + transition_to_primary_storage_class = lifecycle_policy.value + } + } + + # Transition files to Archive storage class for long-term, rarely accessed data + # Provides the lowest cost storage option, requires transition_to_ia to be set + # Requires Elastic throughput mode and General Purpose performance mode + dynamic "lifecycle_policy" { + for_each = var.lifecycle_policy != null && var.lifecycle_policy.transition_to_archive != null ? [var.lifecycle_policy.transition_to_archive] : [] + content { + transition_to_archive = lifecycle_policy.value + } + } + + # Protection configuration for replication behavior + dynamic "protection" { + for_each = var.protection != null ? [var.protection] : [] + content { + replication_overwrite = lookup(protection.value, "replication_overwrite", null) + } + } + + # Merge default tags with user-provided tags + # Default tags include ManagedBy=Terraform and optional Name tag + tags = local.tags +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..c86d631 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,49 @@ +output "file_system_id" { + description = "The ID of the EFS file system" + value = aws_efs_file_system.this.id +} + +output "file_system_arn" { + description = "Amazon Resource Name of the file system" + value = aws_efs_file_system.this.arn +} + +output "file_system_dns_name" { + description = "The DNS name for the filesystem" + value = aws_efs_file_system.this.dns_name +} + +output "file_system_creation_token" { + description = "The creation token of the EFS file system" + value = aws_efs_file_system.this.creation_token +} + +output "file_system_availability_zone_id" { + description = "The identifier of the Availability Zone in which the file system's One Zone storage classes exist" + value = aws_efs_file_system.this.availability_zone_id +} + +output "file_system_availability_zone_name" { + description = "The Availability Zone name in which the file system's One Zone storage classes exist" + value = aws_efs_file_system.this.availability_zone_name +} + +output "file_system_number_of_mount_targets" { + description = "The current number of mount targets that the file system has" + value = aws_efs_file_system.this.number_of_mount_targets +} + +output "file_system_owner_id" { + description = "The AWS account that created the file system" + value = aws_efs_file_system.this.owner_id +} + +output "file_system_size_in_bytes" { + description = "The latest known metered size (in bytes) of data stored in the file system" + value = aws_efs_file_system.this.size_in_bytes +} + +output "file_system_name" { + description = "The value of the file system's Name tag" + value = aws_efs_file_system.this.name +} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..08a6ba7 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,276 @@ +# Tests Directory + +This directory contains the automated test suite for the `tf-aws-module_primitive-efs_file_system` module. Tests are implemented using [Terratest](https://terratest.gruntwork.io/) and the Launch Common Automation Framework (LCAF) testing library. + +## Directory Structure + +``` +tests/ +├── README.md # This file +├── post_deploy_functional/ # Full lifecycle tests (deploy, test, destroy) +│ ├── README.md +│ └── main_test.go +├── post_deploy_functional_readonly/ # Read-only tests (no deploy/destroy) +│ ├── README.md +│ └── main_test.go +└── testimpl/ # Shared test implementation + ├── README.md + ├── test_impl.go # Test logic and assertions + └── types.go # Test configuration types +``` + +## Test Types + +### Post-Deploy Functional Tests +Located in `post_deploy_functional/`, these tests: +- ✅ Deploy the Terraform examples +- ✅ Validate resource creation and configuration +- ✅ Verify outputs match expected values +- ✅ Destroy resources after testing + +### Post-Deploy Functional Read-Only Tests +Located in `post_deploy_functional_readonly/`, these tests: +- ✅ Assume resources are already deployed +- ✅ Run validation and assertions only +- ✅ Do not create or destroy resources +- ✅ Useful for CI/CD when resources persist between stages + +### Test Implementation +Located in `testimpl/`, this package contains: +- Shared test logic and assertion functions +- AWS SDK integration for resource verification +- Reusable test utilities +- Configuration type definitions + +## Running Tests + +### ⚠️ Important: Run from Repository Root + +**Do NOT run tests from this directory.** Always execute tests from the repository root: + +```bash +# Correct - run from repository root +cd /workspace +go test -v ./tests/post_deploy_functional/... + +# Incorrect - do not run from tests directory +cd /workspace/tests +go test -v ./post_deploy_functional/... # ❌ Wrong +``` + +### Prerequisites + +1. **AWS Credentials**: Configure AWS credentials with permissions to create/delete EFS resources + ```bash + export AWS_REGION=us-west-2 + export AWS_ACCESS_KEY_ID=your_access_key + export AWS_SECRET_ACCESS_KEY=your_secret_key + ``` + +2. **Go Installation**: Go 1.24 or later + ```bash + go version + ``` + +3. **Dependencies**: Install Go modules + ```bash + cd /workspace + go mod download + ``` + +### Running All Tests + +```bash +# From repository root +cd /workspace + +# Run all post-deploy functional tests +go test -v ./tests/post_deploy_functional/... + +# Run with timeout (recommended) +go test -v ./tests/post_deploy_functional/... + +# Run with verbose output +go test -v -count=1 ./tests/post_deploy_functional/... +``` + +### Running Specific Test Suites + +```bash +# Run only post_deploy_functional tests +go test -v ./tests/post_deploy_functional + +# Run only post_deploy_functional_readonly tests +go test -v ./tests/post_deploy_functional_readonly + +# Run specific test function +go test -v ./tests/post_deploy_functional -run TestModule +``` + +### Test Environment Variables + +Control test behavior with environment variables: + +```bash +# Skip teardown (leave resources for inspection) +export SKIP_teardown_test_simple=true +go test -v ./tests/post_deploy_functional/... + +# Skip setup (use existing infrastructure) +export SKIP_setup_test_simple=true +go test -v ./tests/post_deploy_functional/... + +# Disable test parallelization +export DISABLE_PARALLEL=true +go test -v ./tests/post_deploy_functional/... +``` + +## Test Coverage + +The test suite validates: + +### EFS File System Properties +- ✅ File system ID format and uniqueness +- ✅ ARN format and correctness +- ✅ DNS name format and reachability +- ✅ Creation token matches configuration +- ✅ Encryption is enabled as configured +- ✅ Name tag is set correctly + +### AWS Resource Verification +- ✅ Resources exist in AWS (via SDK) +- ✅ Resource properties match Terraform outputs +- ✅ Throughput mode is configured correctly +- ✅ Performance mode matches expectations + +### Output Validation +- ✅ All outputs are populated +- ✅ Output values match AWS API responses +- ✅ Outputs use correct formats + +## Test Execution Flow + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 1. Setup Phase │ +│ • Initialize Terraform │ +│ • Read test.tfvars configuration │ +│ • Run terraform apply │ +└────────────────────────────┬────────────────────────────────┘ + │ +┌────────────────────────────▼────────────────────────────────┐ +│ 2. Test Phase │ +│ • Retrieve Terraform outputs │ +│ • Query AWS API for resource details │ +│ • Run assertion tests: │ +│ - TestFileSystemId │ +│ - TestFileSystemArn │ +│ - TestFileSystemDnsName │ +│ - TestFileSystemCreationToken │ +│ - TestFileSystemEncryption │ +│ - TestFileSystemName │ +│ - TestFileSystemThroughputMode │ +└────────────────────────────┬────────────────────────────────┘ + │ +┌────────────────────────────▼────────────────────────────────┐ +│ 3. Teardown Phase │ +│ • Run terraform destroy │ +│ • Clean up test resources │ +│ • Verify resources are deleted │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Troubleshooting + +### Common Issues + +**Tests fail with "timeout"** +- EFS resources can take time to create/delete +- Tests run to completion naturally without timeout flags +- If a test hangs, cancel it manually (Ctrl+C) + +**Tests fail with "permission denied"** +- Verify AWS credentials are configured +- Ensure IAM permissions include EFS actions: + - `elasticfilesystem:CreateFileSystem` + - `elasticfilesystem:DescribeFileSystems` + - `elasticfilesystem:DeleteFileSystem` + - `elasticfilesystem:PutLifecycleConfiguration` + +**Tests fail with "resource already exists"** +- Change `creation_token` in test.tfvars to a unique value +- Clean up existing resources manually +- Check for orphaned resources in AWS Console + +**Tests fail but resources remain** +- Set `SKIP_teardown_test_simple=true` to debug +- Manually destroy with: `cd examples/simple && terraform destroy` +- Check AWS Console for lingering resources + +### Debug Mode + +Enable detailed test output: + +```bash +# Maximum verbosity +TF_LOG=DEBUG go test -v ./tests/post_deploy_functional/... + +# Show Terraform output +go test -v ./tests/post_deploy_functional/... 2>&1 | tee test.log +``` + +## Adding New Tests + +To add additional test coverage: + +1. **Add test functions** to `testimpl/test_impl.go` + ```go + func testNewFeature(t *testing.T, awsFileSystem *types.FileSystemDescription) { + // Your assertions here + } + ``` + +2. **Call from TestComposableComplete** in `testimpl/test_impl.go` + ```go + t.Run("TestNewFeature", func(t *testing.T) { + testNewFeature(t, &awsFileSystem) + }) + ``` + +3. **Run tests** to verify + ```bash + go test -v ./tests/post_deploy_functional/... + ``` + +## Best Practices + +1. ✅ Always run tests from repository root +2. ✅ Use unique `creation_token` values to avoid conflicts +3. ✅ Let tests run to completion naturally (no timeout flags) +4. ✅ Clean up resources after testing +5. ✅ Use environment variables to control test behavior +6. ✅ Review test output for failures and warnings +7. ✅ Verify resources are deleted after teardown + +## Continuous Integration + +These tests are designed to run in CI/CD pipelines: + +```yaml +# Example GitHub Actions workflow +- name: Run Tests + run: | + cd /workspace + go test -v ./tests/post_deploy_functional/... + env: + AWS_REGION: us-west-2 + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} +``` + +## Related Documentation + +- [Terratest Documentation](https://terratest.gruntwork.io/) +- [LCAF Testing Library](https://github.com/launchbynttdata/lcaf-component-terratest) +- [AWS EFS API Reference](https://docs.aws.amazon.com/efs/latest/ug/api-reference.html) +- [Root README](../README.md) diff --git a/tests/post_deploy_functional/README.md b/tests/post_deploy_functional/README.md new file mode 100644 index 0000000..3103d3a --- /dev/null +++ b/tests/post_deploy_functional/README.md @@ -0,0 +1,189 @@ +# Post-Deploy Functional Tests + +This directory contains **full lifecycle tests** for the EFS file system module. These tests deploy infrastructure, validate it, and tear it down automatically. + +## Purpose + +These tests perform complete end-to-end validation: +1. ✅ **Setup**: Deploy Terraform examples to AWS +2. ✅ **Test**: Validate resources and outputs +3. ✅ **Teardown**: Destroy all created resources + +## Test Scope + +This test suite validates: +- EFS file system creation and configuration +- Encryption settings +- Performance and throughput modes +- Lifecycle policies (complete example) +- Resource tagging +- Terraform outputs accuracy +- AWS API consistency + +## Running Tests + +### ⚠️ Run from Repository Root + +**Do NOT run tests from this directory.** Always execute from the repository root: + +```bash +# Correct ✅ +cd /workspace +go test -v ./tests/post_deploy_functional/... + +# Incorrect ❌ +cd /workspace/tests/post_deploy_functional +go test -v . +``` + +### Prerequisites + +1. **AWS Credentials** with EFS permissions +2. **Go 1.24+** installed +3. **Unique creation tokens** in test.tfvars to avoid conflicts + +### Run All Tests + +```bash +# From repository root +cd /workspace +go test -v ./tests/post_deploy_functional/... +``` + +### Run Specific Example + +The test framework automatically discovers and tests all examples in the `examples/` directory: +- `examples/simple/` - Basic configuration +- `examples/complete/` - Full-featured configuration + +## Test Configuration + +Tests use configuration files from each example: +- `examples/simple/test.tfvars` +- `examples/complete/test.tfvars` + +To customize test parameters, edit the appropriate `test.tfvars` file. + +## Test Flow + +``` +┌──────────────────────────────────────┐ +│ 1. SETUP PHASE │ +│ • cd examples/simple │ +│ • terraform init │ +│ • terraform apply -var-file=... │ +└─────────────┬────────────────────────┘ + │ +┌─────────────▼────────────────────────┐ +│ 2. TEST PHASE │ +│ • Retrieve outputs │ +│ • Query AWS API │ +│ • Run assertions: │ +│ - File system exists │ +│ - Encryption enabled │ +│ - Outputs match AWS │ +│ - Tags are correct │ +│ - Name is set │ +└─────────────┬────────────────────────┘ + │ +┌─────────────▼────────────────────────┐ +│ 3. TEARDOWN PHASE │ +│ • terraform destroy │ +│ • Verify cleanup │ +└──────────────────────────────────────┘ +``` + +## Environment Variables + +Control test behavior: + +```bash +# Skip teardown (leave resources for debugging) +export SKIP_teardown_test_simple=true +go test -v ./tests/post_deploy_functional/... + +# Skip setup (use existing resources) +export SKIP_setup_test_simple=true +go test -v ./tests/post_deploy_functional/... +``` + +## Test Implementation + +Test logic is implemented in `../testimpl/test_impl.go`: +- `TestComposableComplete()` - Main test function +- Individual assertion functions for each validation + +## Expected Output + +Successful test run: + +``` +=== RUN TestModule +=== RUN TestModule/TestFileSystemId +=== RUN TestModule/TestFileSystemArn +=== RUN TestModule/TestFileSystemDnsName +=== RUN TestModule/TestFileSystemCreationToken +=== RUN TestModule/TestFileSystemEncryption +=== RUN TestModule/TestFileSystemName +=== RUN TestModule/TestFileSystemThroughputMode +--- PASS: TestModule (45.23s) + --- PASS: TestModule/TestFileSystemId (0.00s) + --- PASS: TestModule/TestFileSystemArn (0.00s) + --- PASS: TestModule/TestFileSystemDnsName (0.00s) + --- PASS: TestModule/TestFileSystemCreationToken (0.00s) + --- PASS: TestModule/TestFileSystemEncryption (0.00s) + --- PASS: TestModule/TestFileSystemName (0.00s) + --- PASS: TestModule/TestFileSystemThroughputMode (0.00s) +PASS +ok github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system/tests/post_deploy_functional 45.234s +``` + +## Cost Warning + +⚠️ **These tests create real AWS resources** that incur costs: +- EFS file systems (charged per GB-month) +- Data transfer (if applicable) + +Resources are automatically cleaned up after tests, but failures may leave orphaned resources. Always verify cleanup in the AWS Console. + +## Troubleshooting + +### Test Hangs During Apply +- EFS creation typically takes 10-30 seconds +- Tests complete naturally without timeout flags +- If hung, cancel with Ctrl+C and check AWS Console + +### Resource Already Exists Error +- Change `creation_token` in test.tfvars to a unique value +- Clean up existing resources: `cd examples/simple && terraform destroy` + +### Permission Denied +- Verify AWS credentials are configured +- Required IAM permissions: + - `elasticfilesystem:CreateFileSystem` + - `elasticfilesystem:DescribeFileSystems` + - `elasticfilesystem:DeleteFileSystem` + - `elasticfilesystem:PutLifecycleConfiguration` + - `elasticfilesystem:TagResource` + +### Resources Not Cleaned Up +- Manually destroy: `cd examples/simple && terraform destroy -var-file=test.tfvars` +- Check AWS Console for orphaned file systems +- Note the creation token for identification + +## Related Files + +- `main_test.go` - Test entry point +- `../testimpl/test_impl.go` - Test implementation and assertions +- `../../examples/simple/test.tfvars` - Simple example test configuration +- `../../examples/complete/test.tfvars` - Complete example test configuration + +## Next Steps + +After tests pass: +1. ✅ Review test output for any warnings +2. ✅ Verify resources were cleaned up in AWS Console +3. ✅ Update test.tfvars for different scenarios +4. ✅ Add additional test cases in `../testimpl/test_impl.go` + +For more information, see the [main tests README](../README.md). diff --git a/tests/post_deploy_functional/main_test.go b/tests/post_deploy_functional/main_test.go new file mode 100644 index 0000000..fc0e6d4 --- /dev/null +++ b/tests/post_deploy_functional/main_test.go @@ -0,0 +1,37 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package test + +import ( + "testing" + + "github.com/launchbynttdata/lcaf-component-terratest/lib" + "github.com/launchbynttdata/lcaf-component-terratest/types" + "github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system/tests/testimpl" +) + +const ( + testConfigsExamplesFolderDefault = "../../examples" + infraTFVarFileNameDefault = "test.tfvars" +) + +func TestModule(t *testing.T) { + + ctx := types.CreateTestContextBuilder(). + SetTestConfig(&testimpl.ThisTFModuleConfig{}). + SetTestConfigFolderName(testConfigsExamplesFolderDefault). + SetTestConfigFileName(infraTFVarFileNameDefault). + Build() + + lib.RunSetupTestTeardown(t, *ctx, testimpl.TestComposableComplete) +} diff --git a/tests/post_deploy_functional_readonly/README.md b/tests/post_deploy_functional_readonly/README.md new file mode 100644 index 0000000..315cd35 --- /dev/null +++ b/tests/post_deploy_functional_readonly/README.md @@ -0,0 +1,282 @@ +# Post-Deploy Functional Read-Only Tests + +This directory contains **read-only validation tests** for the EFS file system module. These tests assume resources are already deployed and only perform validation without creating or destroying infrastructure. + +## Purpose + +These tests are designed for scenarios where: +- ✅ Infrastructure is pre-deployed and persistent +- ✅ Multiple test runs against the same resources +- ✅ CI/CD pipelines with separate deploy/test/destroy stages +- ✅ Manual verification without modifying infrastructure + +## Key Difference from Standard Tests + +| Feature | post_deploy_functional | post_deploy_functional_readonly | +|---------|------------------------|--------------------------------| +| Deploy resources | ✅ Yes | ❌ No | +| Run validations | ✅ Yes | ✅ Yes | +| Destroy resources | ✅ Yes | ❌ No | +| Use case | Full lifecycle testing | Validation only | + +## When to Use + +Use these tests when: +1. **Resources already exist** and should not be modified +2. **CI/CD has separate stages** for deploy, test, and destroy +3. **Testing production** or long-lived environments +4. **Debugging** infrastructure without recreating it +5. **Cost optimization** - avoid repeated create/destroy cycles + +## Running Tests + +### ⚠️ Run from Repository Root + +**Do NOT run tests from this directory.** Always execute from the repository root: + +```bash +# Correct ✅ +cd /workspace +go test -v ./tests/post_deploy_functional_readonly/... + +# Incorrect ❌ +cd /workspace/tests/post_deploy_functional_readonly +go test -v . +``` + +### Prerequisites + +1. **Pre-deployed EFS infrastructure** + ```bash + cd /workspace/examples/simple + terraform init + terraform apply -var-file=test.tfvars + ``` + +2. **AWS credentials** with read permissions + +3. **Terraform state** must exist in the example directory + +### Run Read-Only Tests + +```bash +# From repository root +cd /workspace + +# Run against pre-deployed infrastructure +go test -v ./tests/post_deploy_functional_readonly/... +``` + +## Test Flow + +``` +┌──────────────────────────────────────┐ +│ PREREQUISITES (Manual) │ +│ • Resources already deployed │ +│ • Terraform state exists │ +│ • AWS credentials configured │ +└─────────────┬────────────────────────┘ + │ +┌─────────────▼────────────────────────┐ +│ 1. READ PHASE │ +│ • Read existing Terraform state │ +│ • Retrieve outputs │ +│ • No terraform apply/destroy │ +└─────────────┬────────────────────────┘ + │ +┌─────────────▼────────────────────────┐ +│ 2. TEST PHASE │ +│ • Query AWS API │ +│ • Run all validation tests │ +│ • Verify resource properties │ +│ • Assert outputs are correct │ +└─────────────┬────────────────────────┘ + │ +┌─────────────▼────────────────────────┐ +│ 3. NO TEARDOWN │ +│ • Resources remain deployed │ +│ • State unchanged │ +│ • Manual cleanup required │ +└──────────────────────────────────────┘ +``` + +## Usage Scenarios + +### Scenario 1: CI/CD Pipeline with Stages + +```yaml +# GitHub Actions example +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Deploy Infrastructure + run: | + cd examples/simple + terraform init + terraform apply -var-file=test.tfvars -auto-approve + + test: + needs: deploy + runs-on: ubuntu-latest + steps: + - name: Run Read-Only Tests + run: go test -v ./tests/post_deploy_functional_readonly/... + + destroy: + needs: test + if: always() + runs-on: ubuntu-latest + steps: + - name: Destroy Infrastructure + run: | + cd examples/simple + terraform destroy -var-file=test.tfvars -auto-approve +``` + +### Scenario 2: Manual Testing + +```bash +# 1. Deploy infrastructure once +cd /workspace/examples/simple +terraform init +terraform apply -var-file=test.tfvars + +# 2. Run tests multiple times (no redeploy) +cd /workspace +go test -v ./tests/post_deploy_functional_readonly/... +go test -v ./tests/post_deploy_functional_readonly/... +go test -v ./tests/post_deploy_functional_readonly/... + +# 3. Clean up when done +cd /workspace/examples/simple +terraform destroy -var-file=test.tfvars +``` + +### Scenario 3: Production Validation + +```bash +# Test against existing production EFS +# (Assumes Terraform state is accessible) +cd /workspace +export ENVIRONMENT=production +go test -v ./tests/post_deploy_functional_readonly/... +``` + +## Environment Variables + +Control test behavior: + +```bash +# Force skip of setup phase (already default for readonly) +export SKIP_setup_test_simple=true + +# Force skip of teardown phase (already default for readonly) +export SKIP_teardown_test_simple=true + +# Run tests +go test -v ./tests/post_deploy_functional_readonly/... +``` + +## Test Implementation + +Test logic is shared with full lifecycle tests: +- Main test file: `main_test.go` +- Shared implementation: `../testimpl/test_impl.go` +- Same validation tests as `post_deploy_functional` + +The only difference is the test execution strategy - no setup or teardown phases. + +## Expected Output + +Successful test run: + +``` +=== RUN TestLambdaLayerModule +=== RUN TestLambdaLayerModule/TestFileSystemId +=== RUN TestLambdaLayerModule/TestFileSystemArn +=== RUN TestLambdaLayerModule/TestFileSystemDnsName +=== RUN TestLambdaLayerModule/TestFileSystemCreationToken +=== RUN TestLambdaLayerModule/TestFileSystemEncryption +=== RUN TestLambdaLayerModule/TestFileSystemName +=== RUN TestLambdaLayerModule/TestFileSystemThroughputMode +--- PASS: TestLambdaLayerModule (2.45s) + --- PASS: TestLambdaLayerModule/TestFileSystemId (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemArn (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemDnsName (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemCreationToken (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemEncryption (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemName (0.00s) + --- PASS: TestLambdaLayerModule/TestFileSystemThroughputMode (0.00s) +PASS +ok github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system/tests/post_deploy_functional_readonly 2.456s +``` + +Note: Tests run much faster (~2s vs ~45s) since no deployment occurs. + +## Advantages + +1. ✅ **Faster execution** - No deployment or teardown overhead +2. ✅ **Cost effective** - Reuse existing infrastructure for multiple test runs +3. ✅ **Non-destructive** - Safe to run against persistent environments +4. ✅ **CI/CD friendly** - Fits well into staged pipelines +5. ✅ **Debugging** - Test validation logic without recreating resources + +## Limitations + +1. ❌ **Requires pre-deployment** - Infrastructure must exist before running +2. ❌ **No cleanup** - Resources must be manually destroyed +3. ❌ **State dependency** - Requires access to Terraform state +4. ❌ **Not fully isolated** - Tests share the same infrastructure + +## Troubleshooting + +### Test Fails: "No Terraform State" +- Ensure resources are deployed: `cd examples/simple && terraform apply -var-file=test.tfvars` +- Verify Terraform state file exists: `ls examples/simple/terraform.tfstate` + +### Test Fails: "File System Not Found" +- Resources may have been destroyed +- Redeploy: `cd examples/simple && terraform apply -var-file=test.tfvars` + +### Test Fails: "Output Not Found" +- Terraform state may be out of sync +- Refresh state: `cd examples/simple && terraform refresh -var-file=test.tfvars` + +### Wrong Resources Tested +- Ensure you're in the correct example directory +- Verify Terraform state points to the expected resources +- Check creation token in outputs matches expected value + +## Cleanup + +After testing, manually destroy resources: + +```bash +# Destroy simple example +cd /workspace/examples/simple +terraform destroy -var-file=test.tfvars + +# Destroy complete example +cd /workspace/examples/complete +terraform destroy -var-file=test.tfvars + +# Verify cleanup in AWS Console +aws efs describe-file-systems +``` + +## Related Files + +- `main_test.go` - Test entry point (readonly mode) +- `../post_deploy_functional/main_test.go` - Full lifecycle version +- `../testimpl/test_impl.go` - Shared test implementation +- `../../examples/simple/` - Example to test against + +## Next Steps + +1. ✅ Deploy infrastructure before running these tests +2. ✅ Run tests to validate existing resources +3. ✅ Use in CI/CD pipelines with separate stages +4. ✅ Remember to clean up resources when done + +For more information, see the [main tests README](../README.md). diff --git a/tests/post_deploy_functional_readonly/main_test.go b/tests/post_deploy_functional_readonly/main_test.go new file mode 100644 index 0000000..3eb2db1 --- /dev/null +++ b/tests/post_deploy_functional_readonly/main_test.go @@ -0,0 +1,37 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package test + +import ( + "testing" + + "github.com/launchbynttdata/lcaf-component-terratest/lib" + "github.com/launchbynttdata/lcaf-component-terratest/types" + "github.com/launchbynttdata/tf-aws-module_primitive-efs_file_system/tests/testimpl" +) + +const ( + testConfigsExamplesFolderDefault = "../../examples" + infraTFVarFileNameDefault = "test.tfvars" +) + +func TestLambdaLayerModule(t *testing.T) { + + ctx := types.CreateTestContextBuilder(). + SetTestConfig(&testimpl.ThisTFModuleConfig{}). + SetTestConfigFolderName(testConfigsExamplesFolderDefault). + SetTestConfigFileName(infraTFVarFileNameDefault). + Build() + + lib.RunSetupTestTeardown(t, *ctx, testimpl.TestComposableComplete) +} diff --git a/tests/testimpl/README.md b/tests/testimpl/README.md new file mode 100644 index 0000000..1fb4e08 --- /dev/null +++ b/tests/testimpl/README.md @@ -0,0 +1,281 @@ +# Test Implementation Package + +This package (`testimpl`) contains the **shared test implementation logic** for the EFS file system module tests. It provides reusable test functions, AWS SDK integrations, and assertion utilities used by both full lifecycle and read-only test suites. + +## Purpose + +This package serves as the central location for: +- ✅ Test logic and validation functions +- ✅ AWS SDK client configuration +- ✅ Resource verification using AWS APIs +- ✅ Reusable assertion utilities +- ✅ Test configuration type definitions + +## Package Contents + +### `test_impl.go` +Main test implementation file containing: + +#### Core Test Function +- `TestComposableComplete()` - Main test orchestration function + - Retrieves Terraform outputs + - Queries AWS EFS API for actual resource details + - Executes all validation test cases + - Coordinates test execution flow + +#### Validation Functions +Individual test functions for specific validations: +- `testFileSystemId()` - Validates EFS file system ID format and correctness +- `testFileSystemArn()` - Validates ARN format and matches AWS +- `testFileSystemDnsName()` - Validates DNS name format and content +- `testFileSystemCreationToken()` - Validates creation token matches +- `testFileSystemEncryption()` - Validates encryption is enabled +- `testFileSystemName()` - Validates Name tag is set correctly +- `testFileSystemThroughputMode()` - Validates throughput mode configuration + +#### AWS Client Functions +Utility functions for AWS SDK integration: +- `GetAWSEFSClient()` - Creates authenticated EFS client +- `GetAWSConfig()` - Loads AWS configuration from environment + +### `types.go` +Type definitions for test configuration: +- `ThisTFModuleConfig` - Module-specific test configuration structure +- Extends generic LCAF test configuration types + +## Architecture + +``` +┌────────────────────────────────────────────────────┐ +│ Test Entry Point │ +│ (post_deploy_functional/main_test.go) │ +└──────────────────┬─────────────────────────────────┘ + │ calls +┌──────────────────▼─────────────────────────────────┐ +│ testimpl.TestComposableComplete() │ +│ │ +│ 1. Retrieve Terraform outputs │ +│ 2. Query AWS EFS API │ +│ 3. Execute validation tests │ +└──────────────────┬─────────────────────────────────┘ + │ calls +┌──────────────────▼─────────────────────────────────┐ +│ Individual Test Functions │ +│ │ +│ • testFileSystemId() │ +│ • testFileSystemArn() │ +│ • testFileSystemDnsName() │ +│ • testFileSystemCreationToken() │ +│ • testFileSystemEncryption() │ +│ • testFileSystemName() │ +│ • testFileSystemThroughputMode() │ +└────────────────────────────────────────────────────┘ +``` + +## How Tests Work + +### 1. Terraform Output Retrieval +```go +fileSystemId := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_id") +``` +- Reads outputs from Terraform state +- Used as expected values for validation + +### 2. AWS API Query +```go +fileSystem, err := efsClient.DescribeFileSystems(context.TODO(), &efs.DescribeFileSystemsInput{ + FileSystemId: aws.String(fileSystemId), +}) +``` +- Queries actual AWS resources using SDK +- Retrieves real-world resource state + +### 3. Assertion and Validation +```go +assert.Equal(t, *awsFileSystem.FileSystemId, fileSystemId, "File system ID should match") +assert.True(t, *awsFileSystem.Encrypted, "File system should be encrypted") +``` +- Compares Terraform outputs with AWS reality +- Validates resource configuration + +## Not Intended for Direct Execution + +⚠️ **This package is not meant to be run directly.** It contains shared code used by test suites in: +- `../post_deploy_functional/` +- `../post_deploy_functional_readonly/` + +To run tests, use the test suite directories from the repository root: + +```bash +# Correct ✅ +cd /workspace +go test -v ./tests/post_deploy_functional/... + +# Incorrect ❌ +cd /workspace/tests/testimpl +go test -v . # This won't work - no test files with main() here +``` + +## Adding New Test Functions + +To add additional validation tests: + +### Step 1: Add Test Function + +Add a new test function in `test_impl.go`: + +```go +func testNewFeature(t *testing.T, awsFileSystem *types.FileSystemDescription) { + // Your test logic here + assert.NotNil(t, awsFileSystem.NewField, "New field should be set") + assert.Equal(t, expectedValue, *awsFileSystem.NewField, "New field should match expected value") +} +``` + +### Step 2: Add Test Case + +Call the new test function from `TestComposableComplete()`: + +```go +func TestComposableComplete(t *testing.T, ctx testTypes.TestContext) { + // ... existing code ... + + t.Run("TestNewFeature", func(t *testing.T) { + testNewFeature(t, &awsFileSystem) + }) +} +``` + +### Step 3: Run Tests + +```bash +cd /workspace +go test -v ./tests/post_deploy_functional/... +``` + +## Dependencies + +This package depends on: + +### Testing Frameworks +- `testing` - Go standard library testing +- `github.com/stretchr/testify` - Enhanced assertions +- `github.com/gruntwork-io/terratest` - Terraform testing utilities +- `github.com/launchbynttdata/lcaf-component-terratest` - LCAF test framework + +### AWS SDK +- `github.com/aws/aws-sdk-go-v2/aws` - AWS SDK core +- `github.com/aws/aws-sdk-go-v2/config` - AWS configuration +- `github.com/aws/aws-sdk-go-v2/service/efs` - EFS service client +- `github.com/aws/aws-sdk-go-v2/service/efs/types` - EFS types + +## Test Function Patterns + +### Pattern 1: Value Comparison +```go +func testExample(t *testing.T, awsFileSystem *types.FileSystemDescription, expectedValue string) { + assert.Equal(t, expectedValue, *awsFileSystem.Field, "Field should match expected value") +} +``` + +### Pattern 2: Format Validation +```go +func testExample(t *testing.T, value string) { + matched, _ := regexp.MatchString(`^pattern$`, value) + assert.True(t, matched, "Value should match expected pattern") +} +``` + +### Pattern 3: Existence Check +```go +func testExample(t *testing.T, awsFileSystem *types.FileSystemDescription) { + assert.NotNil(t, awsFileSystem.Field, "Field should not be nil") + assert.NotEmpty(t, *awsFileSystem.Field, "Field should not be empty") +} +``` + +### Pattern 4: Boolean Assertion +```go +func testExample(t *testing.T, awsFileSystem *types.FileSystemDescription) { + assert.NotNil(t, awsFileSystem.BoolField, "Bool field should not be nil") + assert.True(t, *awsFileSystem.BoolField, "Bool field should be true") +} +``` + +## Assertion Library + +Using `testify/assert`: + +```go +// Equality +assert.Equal(t, expected, actual, "message") + +// Truthiness +assert.True(t, condition, "message") +assert.False(t, condition, "message") + +// Nil checks +assert.Nil(t, value, "message") +assert.NotNil(t, value, "message") + +// Empty checks +assert.Empty(t, value, "message") +assert.NotEmpty(t, value, "message") + +// Contains +assert.Contains(t, haystack, needle, "message") + +// Error handling +assert.NoError(t, err, "message") +assert.Error(t, err, "message") +``` + +## Best Practices + +1. ✅ **Descriptive test names** - Use clear, specific names for test functions +2. ✅ **Meaningful messages** - Provide helpful assertion messages +3. ✅ **Nil checks** - Always check for nil before dereferencing pointers +4. ✅ **Error handling** - Use `require.NoError()` for critical operations +5. ✅ **Granular tests** - One test function per validation concern +6. ✅ **Reusable utilities** - Extract common logic to helper functions + +## Debugging Tests + +### Enable Verbose Output +```bash +go test -v ./tests/post_deploy_functional/... +``` + +### Run Single Test Case +```bash +go test -v ./tests/post_deploy_functional/... -run TestModule/TestFileSystemId +``` + +### Print Variable Values +```go +t.Logf("File System ID: %s", fileSystemId) +t.Logf("AWS Response: %+v", awsFileSystem) +``` + +## Related Files + +- `../post_deploy_functional/main_test.go` - Full lifecycle test entry +- `../post_deploy_functional_readonly/main_test.go` - Read-only test entry +- `../../main.tf` - Module implementation being tested +- `../../examples/simple/test.tfvars` - Test configuration + +## Contributing + +When adding new features to the EFS module: + +1. ✅ Add corresponding test functions in `test_impl.go` +2. ✅ Update test cases in `TestComposableComplete()` +3. ✅ Run tests to verify: `go test -v ./tests/post_deploy_functional/...` +4. ✅ Document new test functions in this README + +## Next Steps + +For actual test execution: +- See [post_deploy_functional README](../post_deploy_functional/README.md) +- See [post_deploy_functional_readonly README](../post_deploy_functional_readonly/README.md) +- See [main tests README](../README.md) diff --git a/tests/testimpl/test_impl.go b/tests/testimpl/test_impl.go new file mode 100644 index 0000000..d16e3e6 --- /dev/null +++ b/tests/testimpl/test_impl.go @@ -0,0 +1,127 @@ +package testimpl + +import ( + "context" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/efs" + "github.com/aws/aws-sdk-go-v2/service/efs/types" + "github.com/gruntwork-io/terratest/modules/terraform" + testTypes "github.com/launchbynttdata/lcaf-component-terratest/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestComposableComplete(t *testing.T, ctx testTypes.TestContext) { + // Get AWS EFS client + efsClient := GetAWSEFSClient(t) + + // Get outputs from Terraform + fileSystemId := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_id") + fileSystemArn := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_arn") + fileSystemDnsName := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_dns_name") + fileSystemCreationToken := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_creation_token") + fileSystemName := terraform.Output(t, ctx.TerratestTerraformOptions(), "file_system_name") + + // Get the actual file system from AWS + fileSystem, err := efsClient.DescribeFileSystems(context.TODO(), &efs.DescribeFileSystemsInput{ + FileSystemId: aws.String(fileSystemId), + }) + require.NoError(t, err, "Failed to describe EFS file system") + require.NotEmpty(t, fileSystem.FileSystems, "No file systems returned from AWS") + + awsFileSystem := fileSystem.FileSystems[0] + + t.Run("TestFileSystemId", func(t *testing.T) { + testFileSystemId(t, &awsFileSystem, fileSystemId) + }) + + t.Run("TestFileSystemArn", func(t *testing.T) { + testFileSystemArn(t, &awsFileSystem, fileSystemArn) + }) + + t.Run("TestFileSystemDnsName", func(t *testing.T) { + testFileSystemDnsName(t, fileSystemId, fileSystemDnsName) + }) + + t.Run("TestFileSystemCreationToken", func(t *testing.T) { + testFileSystemCreationToken(t, &awsFileSystem, fileSystemCreationToken) + }) + + t.Run("TestFileSystemEncryption", func(t *testing.T) { + testFileSystemEncryption(t, &awsFileSystem) + }) + + t.Run("TestFileSystemName", func(t *testing.T) { + testFileSystemName(t, &awsFileSystem, fileSystemName) + }) + + t.Run("TestFileSystemThroughputMode", func(t *testing.T) { + testFileSystemThroughputMode(t, &awsFileSystem) + }) +} + +func testFileSystemId(t *testing.T, awsFileSystem *types.FileSystemDescription, fileSystemId string) { + assert.Equal(t, *awsFileSystem.FileSystemId, fileSystemId, "File system ID from Terraform should match AWS") + assert.NotEmpty(t, fileSystemId, "File system ID should not be empty") + + // Verify it's a valid EFS ID format + matched, _ := regexp.MatchString(`^fs-[a-f0-9]+$`, fileSystemId) + assert.True(t, matched, "File system ID should match format 'fs-xxxxxxxxx'") +} + +func testFileSystemArn(t *testing.T, awsFileSystem *types.FileSystemDescription, fileSystemArn string) { + assert.Equal(t, *awsFileSystem.FileSystemArn, fileSystemArn, "File system ARN from Terraform should match AWS") + assert.NotEmpty(t, fileSystemArn, "File system ARN should not be empty") + + // Verify it's a valid ARN format + matched, _ := regexp.MatchString(`^arn:aws:elasticfilesystem:`, fileSystemArn) + assert.True(t, matched, "ARN should start with 'arn:aws:elasticfilesystem:'") +} + +func testFileSystemDnsName(t *testing.T, fileSystemId string, fileSystemDnsName string) { + assert.NotEmpty(t, fileSystemDnsName, "DNS name should not be empty") + assert.Contains(t, fileSystemDnsName, fileSystemId, "DNS name should contain the file system ID") + assert.Contains(t, fileSystemDnsName, ".efs.", "DNS name should contain '.efs.'") + assert.Contains(t, fileSystemDnsName, ".amazonaws.com", "DNS name should end with '.amazonaws.com'") +} + +func testFileSystemCreationToken(t *testing.T, awsFileSystem *types.FileSystemDescription, fileSystemCreationToken string) { + assert.Equal(t, *awsFileSystem.CreationToken, fileSystemCreationToken, "Creation token from Terraform should match AWS") + assert.NotEmpty(t, fileSystemCreationToken, "Creation token should not be empty") +} + +func testFileSystemEncryption(t *testing.T, awsFileSystem *types.FileSystemDescription) { + assert.NotNil(t, awsFileSystem.Encrypted, "Encrypted field should not be nil") + assert.True(t, *awsFileSystem.Encrypted, "File system should be encrypted") +} + +func testFileSystemName(t *testing.T, awsFileSystem *types.FileSystemDescription, fileSystemName string) { + assert.NotEmpty(t, fileSystemName, "File system name should not be empty") + + // Verify the Name tag exists in AWS + if awsFileSystem.Name != nil { + assert.Equal(t, *awsFileSystem.Name, fileSystemName, "File system name from Terraform should match AWS Name tag") + } +} + +func testFileSystemThroughputMode(t *testing.T, awsFileSystem *types.FileSystemDescription) { + assert.NotNil(t, awsFileSystem.ThroughputMode, "Throughput mode should be set") + // Valid values are bursting, provisioned, or elastic + validModes := []string{"bursting", "provisioned", "elastic"} + assert.Contains(t, validModes, string(awsFileSystem.ThroughputMode), "Throughput mode should be valid") +} + +func GetAWSEFSClient(t *testing.T) *efs.Client { + awsEFSClient := efs.NewFromConfig(GetAWSConfig(t)) + return awsEFSClient +} + +func GetAWSConfig(t *testing.T) (cfg aws.Config) { + cfg, err := config.LoadDefaultConfig(context.TODO()) + require.NoErrorf(t, err, "unable to load SDK config, %v", err) + return cfg +} diff --git a/tests/testimpl/types.go b/tests/testimpl/types.go new file mode 100644 index 0000000..c9fdd9d --- /dev/null +++ b/tests/testimpl/types.go @@ -0,0 +1,7 @@ +package testimpl + +import "github.com/launchbynttdata/lcaf-component-terratest/types" + +type ThisTFModuleConfig struct { + types.GenericTFModuleConfig +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..3536b6a --- /dev/null +++ b/variables.tf @@ -0,0 +1,85 @@ +variable "creation_token" { + description = "Required unique identifier for the EFS file system. Must be unique within your AWS account and region and cannot be empty" + type = string + validation { + condition = var.creation_token != null && var.creation_token != "" + error_message = "Creation token is required and cannot be empty." + } +} + +variable "name" { + description = "Required friendly name for the EFS file system. Will be added as a 'Name' tag and cannot be empty" + type = string + validation { + condition = var.name != null && var.name != "" + error_message = "Name is required and cannot be empty." + } +} + +variable "availability_zone_name" { + description = "The AWS Availability Zone in which to create the file system. Used to create a file system that uses One Zone storage classes. If omitted, Multi-AZ storage will be used" + type = string + default = null +} + +variable "encrypted" { + description = "If true, the disk will be encrypted" + type = bool + default = true +} + +variable "kms_key_id" { + description = "ARN for the KMS encryption key. If set, the EFS file system will be encrypted at rest using this key" + type = string + default = null +} + +variable "performance_mode" { + description = "The file system performance mode. Valid values: 'generalPurpose' (default, lower latency for most workloads) or 'maxIO' (higher aggregate throughput for highly parallelized workloads)" + type = string + default = "generalPurpose" + validation { + condition = contains(["generalPurpose", "maxIO"], var.performance_mode) + error_message = "Performance mode must be either 'generalPurpose' or 'maxIO'." + } +} + +variable "throughput_mode" { + description = "Throughput mode for the file system. Valid values: 'bursting' (scales with file system size), 'elastic' (automatically scales based on workload), or 'provisioned' (fixed throughput - requires provisioned_throughput_in_mibps to be set)" + type = string + default = "bursting" + validation { + condition = contains(["bursting", "provisioned", "elastic"], var.throughput_mode) + error_message = "Throughput mode must be 'bursting', 'provisioned', or 'elastic'." + } +} + +variable "provisioned_throughput_in_mibps" { + description = "The throughput, measured in MiB/s, that you want to provision for the file system. Only applicable when throughput_mode is set to 'provisioned'" + type = number + default = null +} + +variable "lifecycle_policy" { + description = "Lifecycle policy for the file system. Supports transition_to_ia (AFTER_7_DAYS, AFTER_14_DAYS, AFTER_30_DAYS, AFTER_60_DAYS, AFTER_90_DAYS, AFTER_1_DAY, AFTER_180_DAYS, AFTER_270_DAYS, AFTER_365_DAYS), transition_to_primary_storage_class (AFTER_1_ACCESS), and transition_to_archive (AFTER_1_DAY, AFTER_7_DAYS, AFTER_14_DAYS, AFTER_30_DAYS, AFTER_60_DAYS, AFTER_90_DAYS, AFTER_180_DAYS, AFTER_270_DAYS, AFTER_365_DAYS)" + type = object({ + transition_to_ia = optional(string) + transition_to_primary_storage_class = optional(string) + transition_to_archive = optional(string) + }) + default = null +} + +variable "protection" { + description = "Protection configuration for the file system. Supports replication_overwrite (ENABLED, DISABLED, REPLICATING)" + type = object({ + replication_overwrite = optional(string) + }) + default = null +} + +variable "tags" { + description = "A map of tags to assign to the EFS file system" + type = map(string) + default = {} +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..bae16a1 --- /dev/null +++ b/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = "~> 1.5" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.100" + } + } +}