diff --git a/.gitignore b/.gitignore index 7e0823020c..ce82d56ca3 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ site/stats/ *.tfstate.backup *.tfplan *.lock.hcl +!provisioner/terraform/testdata/resources/.terraform.lock.hcl .terraform/ !coderd/testdata/parameters/modules/.terraform/ !provisioner/terraform/testdata/modules-source-caching/.terraform/ diff --git a/Makefile b/Makefile index 11e30edb64..6d08353fb7 100644 --- a/Makefile +++ b/Makefile @@ -1260,11 +1260,21 @@ provisioner/terraform/testdata/.gen-golden: $(wildcard provisioner/terraform/tes touch "$@" provisioner/terraform/testdata/version: - if [[ "$(shell cat provisioner/terraform/testdata/version.txt)" != "$(shell terraform version -json | jq -r '.terraform_version')" ]]; then - ./provisioner/terraform/testdata/generate.sh + @tf_match=true; \ + if [[ "$$(cat provisioner/terraform/testdata/version.txt)" != \ + "$$(terraform version -json | jq -r '.terraform_version')" ]]; then \ + tf_match=false; \ + fi; \ + if ! $$tf_match || \ + ! ./provisioner/terraform/testdata/generate.sh --check; then \ + ./provisioner/terraform/testdata/generate.sh; \ fi .PHONY: provisioner/terraform/testdata/version +update-terraform-testdata: + ./provisioner/terraform/testdata/generate.sh --upgrade +.PHONY: update-terraform-testdata + # Set the retry flags if TEST_RETRIES is set ifdef TEST_RETRIES GOTESTSUM_RETRY_FLAGS := --rerun-fails=$(TEST_RETRIES) diff --git a/provisioner/terraform/testdata/generate.sh b/provisioner/terraform/testdata/generate.sh index c98f558385..6e2e5d8422 100755 --- a/provisioner/terraform/testdata/generate.sh +++ b/provisioner/terraform/testdata/generate.sh @@ -1,7 +1,12 @@ #!/usr/bin/env bash set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")/resources" + +# Resolve paths before cd so they're absolute. +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +cd "$scriptdir/resources" +canonical_lock="$(pwd)/.terraform.lock.hcl" # These environment variables influence the coder provider. for v in $(env | grep -E '^CODER_' | cut -d= -f1); do @@ -12,7 +17,11 @@ generate() { local name="$1" echo "=== BEGIN: $name" - terraform init -upgrade && + if ((upgrade)); then + terraform init -upgrade + else + terraform init + fi && terraform plan -out terraform.tfplan && terraform show -json ./terraform.tfplan | jq >"$name".tfplan.json && terraform graph -type=plan >"$name".tfplan.dot && @@ -105,7 +114,7 @@ run() { } if [[ " $* " == *" --help "* || " $* " == *" -h "* ]]; then - echo "Usage: $0 [module1 module2 ...]" + echo "Usage: $0 [--upgrade] [--check] [--no-minimize] [module1 module2 ...]" exit 0 fi @@ -114,9 +123,40 @@ if [[ " $* " == *" --no-minimize "* ]]; then minimize=0 fi +upgrade=0 +if [[ " $* " == *" --upgrade "* ]]; then + upgrade=1 +fi + +# Verify that the canonical lockfile matches provider-version.txt. +if [[ " $* " == *" --check "* ]]; then + expected="$(<"$scriptdir/provider-version.txt")" + actual="$(sed -n '/coder\/coder/,/^}/{ /version[[:space:]]*=/{ s/.*"\(.*\)"/\1/; p; q; } }' "$canonical_lock")" + if [[ "$expected" == "$actual" ]]; then + exit 0 + else + echo "ERROR: provider-version.txt ($expected) does not match lockfile ($actual)" + exit 1 + fi +fi + +# Filter flags from positional args to get directory names. +declare -a dirs=() +for arg in "$@"; do + case "$arg" in + --upgrade | --no-minimize | --check | --help | -h) ;; + *) dirs+=("$arg") ;; + esac +done + +# Seed each resource subdirectory with the canonical lockfile. +for d in */; do + cp "$canonical_lock" "$d/.terraform.lock.hcl" +done + declare -a jobs=() -if [[ $# -gt 0 ]]; then - for d in "$@"; do +if [[ ${#dirs[@]} -gt 0 ]]; then + for d in "${dirs[@]}"; do run "$d" & jobs+=($!) done @@ -138,4 +178,27 @@ if [[ $err -ne 0 ]]; then exit 1 fi +# After upgrade, promote the lockfile from a representative directory +# back to the canonical location and record the provider version. +if ((upgrade)); then + # Prefer rich-parameters since it uses all providers (coder, null, docker). + src="" + if [[ -f "rich-parameters/.terraform.lock.hcl" ]]; then + src="rich-parameters/.terraform.lock.hcl" + else + for d in */; do + if [[ -f "$d/.terraform.lock.hcl" ]]; then + src="$d/.terraform.lock.hcl" + break + fi + done + fi + if [[ -n "$src" ]]; then + cp "$src" "$canonical_lock" + version="$(sed -n '/coder\/coder/,/^}/{ /version[[:space:]]*=/{ s/.*"\(.*\)"/\1/; p; q; } }' "$canonical_lock")" + echo "$version" >"$scriptdir/provider-version.txt" + echo "== Updated canonical lockfile and provider-version.txt (coder provider $version)" + fi +fi + terraform version -json | jq -r '.terraform_version' >../version.txt diff --git a/provisioner/terraform/testdata/provider-version.txt b/provisioner/terraform/testdata/provider-version.txt new file mode 100644 index 0000000000..68e69e405e --- /dev/null +++ b/provisioner/terraform/testdata/provider-version.txt @@ -0,0 +1 @@ +2.15.0 diff --git a/provisioner/terraform/testdata/resources/.terraform.lock.hcl b/provisioner/terraform/testdata/resources/.terraform.lock.hcl new file mode 100644 index 0000000000..6820b33f4a --- /dev/null +++ b/provisioner/terraform/testdata/resources/.terraform.lock.hcl @@ -0,0 +1,72 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/coder/coder" { + version = "2.15.0" + constraints = ">= 2.0.0" + hashes = [ + "h1:F1lwaej6ZM9mTN2yVXvBpMZvute51NrBn1Mxru93OOQ=", + "h1:Wqx9ewN36IG+DyQshEnp0eoFWX0FVHJStmskyS/6JXE=", + "h1:tYNavbEhcqzlIwpSe1GMrV/726+u703m2XGbinj3LPg=", + "zh:10897edfe4ecb975ce11b6b2dfb37317f07c725404d2a60b5fa4e114808259b9", + "zh:10b1af473883a9524353011943cfab89b401fc84ed38608a798e377aaa4ecebf", + "zh:4678c3b329e47a4c3fb9683db4850470e8ef6ede570f6a2bb99701f1125b4215", + "zh:4c2df7c4d8f0fc8546536c886c0984e7173dcc2d3759218fdae3d4bf2703af14", + "zh:72e0b7297f3e20abe2a81e34fe4976caa79691857b6355a2b9492f3ddc85aa9e", + "zh:773077f4eaaf6a31154f1d8aa63b4ef3bbe34104271c4d9cf065261cba8814a9", + "zh:80b1eb2aa2d18ce2ff26e02fa179994fd137031c9c4e2cce0d547b126eadf62e", + "zh:8efdf98494ec442630efb48aabc8dbf10b03254f3f2a2247f519dbf005c5aabc", + "zh:a65d987f531bf0a41cc5d68fd46f675cb37e8570a8a42579bc30e22312b3df4d", + "zh:bb2c57695e801994604542791ff87ed4b7e0d94ffa9d4c6a0ec34260f4616a49", + "zh:be9a5086d498b941e08e9c30b4de5151b15dfab526083387dd47e9451d7bde53", + "zh:de8fe0131db31511c8d4e02b1b58aa2b2bc82ca50188f2ed1d9d731d70321fb2", + "zh:e1d95002571d9025631f9dc98f441e22cd68783a27e9e35925bda21dbd94f904", + "zh:eb0de36ba625d187dce45a24ad9e724bafff821fb466d014cc7d9a02d2d72309", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.4" + hashes = [ + "h1:127ts0CG8hFk1bHIfrBsKxcnt9bAYQCq3udWM+AACH8=", + "h1:L5V05xwp/Gto1leRryuesxjMfgZwjb7oool4WS1UEFQ=", + "h1:hkf5w5B6q8e2A42ND2CjAvgvSN3puAosDmOJb3zCVQM=", + "zh:59f6b52ab4ff35739647f9509ee6d93d7c032985d9f8c6237d1f8a59471bbbe2", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:795c897119ff082133150121d39ff26cb5f89a730a2c8c26f3a9c1abf81a9c43", + "zh:7b9c7b16f118fbc2b05a983817b8ce2f86df125857966ad356353baf4bff5c0a", + "zh:85e33ab43e0e1726e5f97a874b8e24820b6565ff8076523cc2922ba671492991", + "zh:9d32ac3619cfc93eb3c4f423492a8e0f79db05fec58e449dee9b2d5873d5f69f", + "zh:9e15c3c9dd8e0d1e3731841d44c34571b6c97f5b95e8296a45318b94e5287a6e", + "zh:b4c2ab35d1b7696c30b64bf2c0f3a62329107bd1a9121ce70683dec58af19615", + "zh:c43723e8cc65bcdf5e0c92581dcbbdcbdcf18b8d2037406a5f2033b1e22de442", + "zh:ceb5495d9c31bfb299d246ab333f08c7fb0d67a4f82681fbf47f2a21c3e11ab5", + "zh:e171026b3659305c558d9804062762d168f50ba02b88b231d20ec99578a6233f", + "zh:ed0fe2acdb61330b01841fa790be00ec6beaac91d41f311fb8254f74eb6a711f", + ] +} + +provider "registry.terraform.io/kreuzwerker/docker" { + version = "2.25.0" + constraints = "~> 2.22" + hashes = [ + "h1:7SILKY4Mjkbs/AHre2QQEaq5qUiOqOzmJwQABrUul4o=", + "h1:MO2d4iiO3G5ytlIN/5178ppdPNZbzVlsesImsbfFfY0=", + "h1:nB2atWOMNrq3tfVH216oFFCQ/TNjAXXno6ZyZhlGdQs=", + "zh:02ca00d987b2e56195d2e97d82349f680d4b94a6a0d514dc6c0031317aec4f11", + "zh:432d333412f01b7547b3b264ec85a2627869fdf5f75df9d237b0dc6a6848b292", + "zh:4709e81fea2b9132020d6c786a1d1d02c77254fc0e299ea1bb636892b6cadac6", + "zh:53c4a4ab59a1e0671d2292d74f14e060489482d430ad811016bf7cb95503c5de", + "zh:6c0865e514ceffbf19ace806fb4595bf05d0a165dd9c8664f8768da385ccc091", + "zh:6d72716d58b8c18cd0b223265b2a190648a14973223cc198a019b300ede07570", + "zh:a710ce90557c54396dfc27b282452a8f5373eb112a10e9fd77043ca05d30e72f", + "zh:e0868c7ac58af596edfa578473013bd550e40c0a1f6adc2c717445ebf9fd694e", + "zh:e2ab2c40631f100130e7b525e07be7a9b8d8fcb8f57f21dca235a3e15818636b", + "zh:e40c93b1d99660f92dd0c75611bcb9e68ae706d4c0bc6fac32f672e19e6f05bf", + "zh:e480501b2dd1399135ec7eb820e1be88f9381d32c4df093f2f4645863f8c48f4", + "zh:f1a71e90aa388d34691595883f6526543063f8e338792b7c2c003b2c8c63d108", + "zh:f346cd5d25a31991487ca5dc7a05e104776c3917482bc2a24ec6a90bb697b22e", + "zh:fa822a4eb4e6385e88fbb133fd63d3a953693712a7adeb371913a2d477c0148c", + ] +}