From 8284cf96d6db8cb3f6ca9be9077d6643bec9313e Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Thu, 19 Nov 2020 10:14:23 +0900 Subject: [PATCH 1/7] Add an example for updating .terraform.lock.hcl Terraform v0.14 will introduce a dependency lock file named `.terraform.lock.hcl`. https://discuss.hashicorp.com/t/terraform-0-14-the-dependency-lock-file/15696 The lock file is an implementation detail and it's hard to update it with the tfupdate command. Because the hash value format seems to allow future terraform versions to change the hash algorithm gradually. If tfupdate updates the lock file, it will be difficult to support multiple terraform versions without an unexpected the lock file drift. Perhaps a recommended way is to use the terraform command to update the lock file. However most CIs use linux and laptops may be mac or windows and if you run terraform on multiple platforms, it requires to generate hashed for all platforms to avoid a lock file drift. So I added an example for it, but I found it's inefficient because it requires duplicate downloads for providers on init. I tried to use a plugin cache dir or a local filesystem mirror, but I couldn't figure out a way to avoid duplicate downloads on init. If I use cache or mirror, it doesn't record zip hashes, and it records them only when download providers from origin. I think the easiest way to use Terraform v0.14 with tfupdate is adding .terraform.lock.hcl to .gitignore. --- .circleci/config.yml | 36 ++++++++++++++++++++++++++++++++++++ .gitignore | 1 + .terraform.lock.hcl | 20 ++++++++++++++++++++ dev/main.tf | 8 ++++++++ main.tf | 2 -- prod/main.tf | 8 ++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100755 .terraform.lock.hcl create mode 100644 dev/main.tf create mode 100644 prod/main.tf diff --git a/.circleci/config.yml b/.circleci/config.yml index 1303c2a..b2fa0f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -74,6 +74,10 @@ commands: provider_name: description: A name of provider type: string + terraform_version: + description: A version of terraform command for updating a lock file + type: string + default: latest steps: - run: name: Update terraform-provider-<< parameters.provider_name >> to latest @@ -87,6 +91,36 @@ commands: else git checkout -b update-terraform-provider-<< parameters.provider_name >>-to-v${VERSION} origin/<< parameters.base_branch >> tfupdate provider << parameters.provider_name >> -v ${VERSION} << parameters.args >> + + # install terraform + TERRAFORM_VERSION=<< parameters.terraform_version >> + if [ "${TERRAFORM_VERSION}" = "latest" ]; then + TERRAFORM_VERSION=$(tfupdate release latest hashicorp/terraform) + fi + wget -qO- https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip | unzip -d /bin - && chmod +x /bin/terraform + terraform version + + # create a local filesystem mirror to avoid duplicate downloads + FS_MIRROR="/tmp/terraform.d/plugins" + DOWNLOAD_DIR="${FS_MIRROR}"/registry.terraform.io/hashicorp/<< parameters.provider_name >> + DOWNLOAD_URL_PREFIX=https://releases.hashicorp.com/terraform-provider-<< parameters.provider_name >>/"${VERSION}"/terraform-provider-<< parameters.provider_name >>_"${VERSION}" + mkdir -p "${DOWNLOAD_DIR}" + wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_linux_amd64.zip" + wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_darwin_amd64.zip" + + # update the lock file + ALL_DIRS=$(find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/') + for dir in ${ALL_DIRS} + do + pushd "$dir" + # update h1 on the current platform and zh for all platforms + terraform init -upgrade -input=false -no-color -backend=false + # generate h1 for all platforms you need + terraform providers lock -fs-mirror="${FS_MIRROR}" -platform=linux_amd64 -platform=darwin_amd64 + rm -rf .terraform + popd + done + if git add . && git diff --cached --exit-code --quiet; then echo "No changes" else @@ -108,6 +142,8 @@ jobs: - tfupdate_terraform - tfupdate_provider: provider_name: 'aws' + terraform_version: '0.14.0-beta2' + base_branch: "tfupdate-test-for-v0.14" workflows: version: 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c99dc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.terraform/ diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100755 index 0000000..a89e33a --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "3.15.0" + constraints = "3.15.0" + hashes = [ + "h1:/A0Gn4jYyV3KfoxoGnwP9N9+ikpmmYq1pU4xiMUK+6w=", + "zh:0478960aece762f5a93ac48a98cf9b905a3d9472bc9774d6a1d5b88ad1ecd8ff", + "zh:0b37e4978732377f6475777301e9b2c554bde0953df5a5cf637f4781879d9655", + "zh:1abadd84b762aa0fb28a62f0941ae2aaa89e395584fbb22eb47980de41c70659", + "zh:26e885c77f744f5125716c5cc23d0465c9e343ea4a6c1097a99f3c3fa2db78f3", + "zh:3fceadf566023c68394ba44ad805cc1bb3d7000aba034ca7c57368bbe9cee6ab", + "zh:48c5b4f2c062350854a3c989a57490d92828c63fd9f22b76efc2f3e0c37e69a1", + "zh:8f2b5b89a4fc019794716878b2a9cf38b633837c21bc4b43e80ef7e5ea4cfffb", + "zh:cfab8b257d696084c3160d33b3edbeafc06fc026d09e14c4788ec07a462307ff", + "zh:e37f0673b3799693e480c342524b6e4b9387c610cb0a3de82006db58022d492f", + "zh:f4ca2b5584fc9d8b0fe68f884b48f680c4b12d4a78352b6b0d482cb88a66717d", + ] +} diff --git a/dev/main.tf b/dev/main.tf new file mode 100644 index 0000000..8ec6b96 --- /dev/null +++ b/dev/main.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "3.15.0" + } + } +} diff --git a/main.tf b/main.tf index d01c115..8ec6b96 100644 --- a/main.tf +++ b/main.tf @@ -1,6 +1,4 @@ terraform { - required_version = "0.14.0-beta2" - required_providers { aws = { source = "hashicorp/aws" diff --git a/prod/main.tf b/prod/main.tf new file mode 100644 index 0000000..8ec6b96 --- /dev/null +++ b/prod/main.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "3.15.0" + } + } +} From 5d51d2ca301cce9e91baa17433978279e202a967 Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Mon, 23 Nov 2020 00:35:28 +0900 Subject: [PATCH 2/7] Simplify updating lock files I found the terraform providers lock command doesn't require init. --- .circleci/config.yml | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b2fa0f6..5e6f0ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -100,26 +100,9 @@ commands: wget -qO- https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip | unzip -d /bin - && chmod +x /bin/terraform terraform version - # create a local filesystem mirror to avoid duplicate downloads - FS_MIRROR="/tmp/terraform.d/plugins" - DOWNLOAD_DIR="${FS_MIRROR}"/registry.terraform.io/hashicorp/<< parameters.provider_name >> - DOWNLOAD_URL_PREFIX=https://releases.hashicorp.com/terraform-provider-<< parameters.provider_name >>/"${VERSION}"/terraform-provider-<< parameters.provider_name >>_"${VERSION}" - mkdir -p "${DOWNLOAD_DIR}" - wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_linux_amd64.zip" - wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_darwin_amd64.zip" - # update the lock file - ALL_DIRS=$(find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/') - for dir in ${ALL_DIRS} - do - pushd "$dir" - # update h1 on the current platform and zh for all platforms - terraform init -upgrade -input=false -no-color -backend=false - # generate h1 for all platforms you need - terraform providers lock -fs-mirror="${FS_MIRROR}" -platform=linux_amd64 -platform=darwin_amd64 - rm -rf .terraform - popd - done + find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/' \ + | xargs -I {} sh -c "rm -f {}/.terraform.lock.hcl && terraform -chdir={} providers lock -platform=linux_amd64 -platform=darwin_amd64" if git add . && git diff --cached --exit-code --quiet; then echo "No changes" From 91eed1afc6f5a7e3fe93b6d14b217fae380e1b2e Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Mon, 23 Nov 2020 23:00:42 +0900 Subject: [PATCH 3/7] Revert "Simplify updating lock files" This reverts commit 5d51d2ca301cce9e91baa17433978279e202a967. I found using only h1 hases would avoid duplicate downloads --- .circleci/config.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5e6f0ed..b2fa0f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -100,9 +100,26 @@ commands: wget -qO- https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip | unzip -d /bin - && chmod +x /bin/terraform terraform version + # create a local filesystem mirror to avoid duplicate downloads + FS_MIRROR="/tmp/terraform.d/plugins" + DOWNLOAD_DIR="${FS_MIRROR}"/registry.terraform.io/hashicorp/<< parameters.provider_name >> + DOWNLOAD_URL_PREFIX=https://releases.hashicorp.com/terraform-provider-<< parameters.provider_name >>/"${VERSION}"/terraform-provider-<< parameters.provider_name >>_"${VERSION}" + mkdir -p "${DOWNLOAD_DIR}" + wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_linux_amd64.zip" + wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_darwin_amd64.zip" + # update the lock file - find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/' \ - | xargs -I {} sh -c "rm -f {}/.terraform.lock.hcl && terraform -chdir={} providers lock -platform=linux_amd64 -platform=darwin_amd64" + ALL_DIRS=$(find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/') + for dir in ${ALL_DIRS} + do + pushd "$dir" + # update h1 on the current platform and zh for all platforms + terraform init -upgrade -input=false -no-color -backend=false + # generate h1 for all platforms you need + terraform providers lock -fs-mirror="${FS_MIRROR}" -platform=linux_amd64 -platform=darwin_amd64 + rm -rf .terraform + popd + done if git add . && git diff --cached --exit-code --quiet; then echo "No changes" From 1442f55e9ccfd5f99507667b1335d457cc24e3b2 Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Mon, 23 Nov 2020 23:10:47 +0900 Subject: [PATCH 4/7] Ignore zh hashes to avoid duplicate downloads from origin It works fine as long as the .terraform.lock.hcl is generated on CI. Note that if you run terraform init -upgrade manually, it will add zh hases, so you should not do. --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b2fa0f6..f1e0f6c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -113,11 +113,11 @@ commands: for dir in ${ALL_DIRS} do pushd "$dir" - # update h1 on the current platform and zh for all platforms - terraform init -upgrade -input=false -no-color -backend=false - # generate h1 for all platforms you need + # always create a new lock to avoid duplicate downloads by terraoform init -upgrade + rm -f .terraform.lock.hcl + # generate h1 hashes for all platforms you need + # recording zh hashes requires to download from origin, so we intentionally ignore them. terraform providers lock -fs-mirror="${FS_MIRROR}" -platform=linux_amd64 -platform=darwin_amd64 - rm -rf .terraform popd done From c7894a9ab5a3c7f4e3f3d50abe066136e183c3c9 Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Mon, 23 Nov 2020 23:27:33 +0900 Subject: [PATCH 5/7] Use terraform providers mirror instead of wget --- .circleci/config.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f1e0f6c..c2fc29a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -102,11 +102,7 @@ commands: # create a local filesystem mirror to avoid duplicate downloads FS_MIRROR="/tmp/terraform.d/plugins" - DOWNLOAD_DIR="${FS_MIRROR}"/registry.terraform.io/hashicorp/<< parameters.provider_name >> - DOWNLOAD_URL_PREFIX=https://releases.hashicorp.com/terraform-provider-<< parameters.provider_name >>/"${VERSION}"/terraform-provider-<< parameters.provider_name >>_"${VERSION}" - mkdir -p "${DOWNLOAD_DIR}" - wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_linux_amd64.zip" - wget -P "${DOWNLOAD_DIR}" "${DOWNLOAD_URL_PREFIX}_darwin_amd64.zip" + terraform providers mirror -platform=linux_amd64 -platform=darwin_amd64 "${FS_MIRROR}" # update the lock file ALL_DIRS=$(find . -type f -name '*.tf' | xargs -I {} dirname {} | grep -v 'modules/') From e8f23da3b36d66e7ed3d0359aaad8752fa7fc91d Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Fri, 4 Dec 2020 23:32:51 +0900 Subject: [PATCH 6/7] Update Terraform to v0.14.0 --- .circleci/config.yml | 2 +- dev/main.tf | 2 ++ main.tf | 2 ++ prod/main.tf | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c2fc29a..d9196aa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -138,7 +138,7 @@ jobs: - tfupdate_terraform - tfupdate_provider: provider_name: 'aws' - terraform_version: '0.14.0-beta2' + terraform_version: '0.14.0' base_branch: "tfupdate-test-for-v0.14" workflows: diff --git a/dev/main.tf b/dev/main.tf index 8ec6b96..7b91bd1 100644 --- a/dev/main.tf +++ b/dev/main.tf @@ -1,4 +1,6 @@ terraform { + required_version = "0.14.0" + required_providers { aws = { source = "hashicorp/aws" diff --git a/main.tf b/main.tf index 8ec6b96..7b91bd1 100644 --- a/main.tf +++ b/main.tf @@ -1,4 +1,6 @@ terraform { + required_version = "0.14.0" + required_providers { aws = { source = "hashicorp/aws" diff --git a/prod/main.tf b/prod/main.tf index 8ec6b96..7b91bd1 100644 --- a/prod/main.tf +++ b/prod/main.tf @@ -1,4 +1,6 @@ terraform { + required_version = "0.14.0" + required_providers { aws = { source = "hashicorp/aws" From 6e8bf7652db136ed61ad5a2d0c921bb2bd077795 Mon Sep 17 00:00:00 2001 From: Masayuki Morita Date: Fri, 4 Dec 2020 23:44:40 +0900 Subject: [PATCH 7/7] Restore base_branch to default (master) --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d9196aa..4a41755 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -139,7 +139,6 @@ jobs: - tfupdate_provider: provider_name: 'aws' terraform_version: '0.14.0' - base_branch: "tfupdate-test-for-v0.14" workflows: version: 2