Add test to show random struct key sorting in backend config
what
- adding a (rough) test that demonstrates randomly changing
terraform.backend.s3key order in backend config file generation
why
- We’ve noticed that backend.tf.json constantly changes the order of the keys within the s3 element. From what I can tell it’s due to go iterating over struct keys using a random order.
references
- N/A
test output
❯ make testacc TEST=github.com/cloudposse/atmos/pkg/utils
go get
go test github.com/cloudposse/atmos/pkg/utils -v -timeout 2m
=== RUN TestBackendConfig
json_utils_test.go:65:
Error Trace: /Users/joe/git-proj/cloudposse/atmos/pkg/utils/json_utils_test.go:65
Error: Not equal:
expected: "{\"terraform\":{\"backend\":{\"s3\":{\"encrypt\":true,\"key\":\"terraform.tfstate\",\"region\":\"us-east-1\",\"role_arn\":null,\"workspace_key_prefix\":\"app\",\"acl\":\"bucket-owner-full-control\",\"bucket\":\"sts-gbl-tfstate-backend\",\"dynamodb_table\":\"sts-gbl-tfstate-backend-lock\"}}}}"
actual : "{\"terraform\":{\"backend\":{\"s3\":{\"dynamodb_table\":\"cp-ue2-root-tfstate-lock\",\"profile\":\"cp-gb2-root-tfstate\",\"role_arn\":null,\"workspace_key_prefix\":\"test-test-component\",\"region\":\"us-east-2\",\"acl\":\"bucket-owner-full-control\",\"bucket\":\"cp-ue2-root-tfstate\",\"encrypt\":true,\"key\":\"terraform.tfstate\"}}}}"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-{"terraform":{"backend":{"s3":{"encrypt":true,"key":"terraform.tfstate","region":"us-east-1","role_arn":null,"workspace_key_prefix":"app","acl":"bucket-owner-full-control","bucket":"sts-gbl-tfstate-backend","dynamodb_table":"sts-gbl-tfstate-backend-lock"}}}}
+{"terraform":{"backend":{"s3":{"dynamodb_table":"cp-ue2-root-tfstate-lock","profile":"cp-gb2-root-tfstate","role_arn":null,"workspace_key_prefix":"test-test-component","region":"us-east-2","acl":"bucket-owner-full-control","bucket":"cp-ue2-root-tfstate","encrypt":true,"key":"terraform.tfstate"}}}}
Test: TestBackendConfig
--- FAIL: TestBackendConfig (0.06s)
FAIL
FAIL github.com/cloudposse/atmos/pkg/utils 0.404s
FAIL
make: *** [testacc] Error 1
❯ make testacc TEST=github.com/cloudposse/atmos/pkg/utils
go get
go test github.com/cloudposse/atmos/pkg/utils -v -timeout 2m
=== RUN TestBackendConfig
json_utils_test.go:65:
Error Trace: /Users/joe/git-proj/cloudposse/atmos/pkg/utils/json_utils_test.go:65
Error: Not equal:
expected: "{\"terraform\":{\"backend\":{\"s3\":{\"encrypt\":true,\"key\":\"terraform.tfstate\",\"region\":\"us-east-1\",\"role_arn\":null,\"workspace_key_prefix\":\"app\",\"acl\":\"bucket-owner-full-control\",\"bucket\":\"sts-gbl-tfstate-backend\",\"dynamodb_table\":\"sts-gbl-tfstate-backend-lock\"}}}}"
actual : "{\"terraform\":{\"backend\":{\"s3\":{\"workspace_key_prefix\":\"test-test-component\",\"encrypt\":true,\"role_arn\":null,\"dynamodb_table\":\"cp-ue2-root-tfstate-lock\",\"key\":\"terraform.tfstate\",\"profile\":\"cp-gb2-root-tfstate\",\"region\":\"us-east-2\",\"acl\":\"bucket-owner-full-control\",\"bucket\":\"cp-ue2-root-tfstate\"}}}}"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-{"terraform":{"backend":{"s3":{"encrypt":true,"key":"terraform.tfstate","region":"us-east-1","role_arn":null,"workspace_key_prefix":"app","acl":"bucket-owner-full-control","bucket":"sts-gbl-tfstate-backend","dynamodb_table":"sts-gbl-tfstate-backend-lock"}}}}
+{"terraform":{"backend":{"s3":{"workspace_key_prefix":"test-test-component","encrypt":true,"role_arn":null,"dynamodb_table":"cp-ue2-root-tfstate-lock","key":"terraform.tfstate","profile":"cp-gb2-root-tfstate","region":"us-east-2","acl":"bucket-owner-full-control","bucket":"cp-ue2-root-tfstate"}}}}
Test: TestBackendConfig
--- FAIL: TestBackendConfig (0.04s)
FAIL
FAIL github.com/cloudposse/atmos/pkg/utils 0.241s
FAIL
make: *** [testacc] Error 1
We discussed this in the sweetops slack community (thread)
Here are the current options to solve this issue for you
- We make
backend.tf.jsongeneration deterministic in atmos - Workaround: You can add
backend.tf.jsonto a.gitignoreand allow atmos to do its thing (provided no one needs to run terraform without atmos) - Workaround: You can hard code the backend for all terraform modules and disable atmos from generating the
backend.tf.json
For option 1, to make this deterministic, we have some more options
- Use a library (see thread https://github.com/golang/go/issues/27179)
- https://github.com/tidwall/gjson
- https://github.com/ake-persson/mapslice-json
- Use a custom json Marshaller
- Sort the keys manually and then write them to a file
@nitrocode thanks for the great summary! Closing.
It would be nice to keep this open or at least create an issue to track this so we can fix it in the future
@nitrocode that's true. I'll rewrite it to describe the issue a bit better.
@joe-niland this was fixed in the last merged PR, atmos release 1.5.0
https://github.com/cloudposse/atmos/pull/189/files#diff-873ae70d0bd7f36db36e19041297b6a195f93676374b57ac1687eeba4b043cffR24
I'll close this PR for now, please reopen if any issues
@joe-niland this was fixed in the last merged PR,
atmosrelease 1.5.0
Thanks for letting me know @aknysh ! Glad you found a solution.