diff --git a/README.md b/README.md index 60bde80..239d644 100644 --- a/README.md +++ b/README.md @@ -56,65 +56,46 @@ module. ## Renaming the tfstates bucket -It may happen that the backends bucket name needs changing, eg following some naming policy -changes in your organization. AWS does not provide a means of doing this directly. -Here is the procedure that I use: - -1. set `this_tfstate_in_s3` to false and comment out the items in `stacks_map` -2. run `terraform apply` in your root module that calls the `multi_stack_backends` module. This will - delete all the `backend.tf` files that had been created by this root module. -3. run `terraform init -migrate-state` (optionally with the `-force-copy` arg) to migrate the - manager's tfstate out of s3 -4. run that same command for all the sub-stacks (ie root modules) that you commented out. I use a - loop - like `for ss in paths-to-substacks; do echo $ss; cd $ss; terraform init ...; cd - > /dev/null; done` -5. create a local backup of the bucket: `aws s3 cp s3://BACKENDS_BUCKET_NAME . --recursive` -6. now that all tfstates have been copied from the bucket to localhost, and the bucket has been - backed up just in case, you can change the value of `backends_bucket_name` given to this module - and run `terraform apply` -7. undo step 1: set `this_tfstate_in_s3` to true -8. undo step 2: uncomment the items from that step -9. undo step 3 by re-running that exact same command `terraform init -migrate-state` -10. undo step 4 by re-running that exact same command for all sub-stacks -11. If you had any `terraform_remote_state`, point them to the new location -12. running `terraform apply` in any of the sub-stacks should show no init and no changes needed - -Here is a different procedure that has fewer steps, some are simpler than previous procedure, and -you don't need to delete the original bucket until the very end. It will be especially useful if you -have many sub-stacks. HOWEVER I have not tested yet, so please test it first. - -1. WARN your team that no one can use terraform on this code, and ENSURE THAT TERRAFORM PLAN SHOWS - NO CHANGES NEEDED +It may happen that the backends bucket (and therefore its replica) need to be renamed, eg following +some naming policy changes in your organization. AWS does not provide a means of doing this +directly. The following procedure is one that I use. + +1. WARN your team that no one can use terraform on this terraform module, and ENSURE THAT + TERRAFORM PLAN SHOWS NO CHANGES NEEDED 2. change the value of `backends_bucket_name` (this new value is referred to here as `NEW_BACKENDS_BUCKET_NAME`) -3. determine the path to the manager module in your tfstate (look at your code or output of +3. determine the path to the manager module in your tfstate. The easiest is to run `terraform state list | grep aws_s3_bucket look at your code or output of terraform state list) -4. run `script/rename-backends-manager-bucket.sh NEW_BUCKET_NAME MODULE_PATH` -5. If you had any `terraform_remote_state` in your sub-stacks, point them to the new location -6. running `terraform apply` in any of the sub-stacks should show no init and no changes needed -7. manually delete the 2 old buckets +4. run `script/rename-backends-manager-bucket.sh NEW_BUCKET_NAME MODULE_PATH` (per the license + terms, this is provided as-is without any warranty - you assume all responsibility!) +5. If you had any `terraform_remote_state` in your sub-stacks, point them to the new bucket name +6. run `terraform apply` in any of the sub-stacks, this should show no init and no changes needed +7. manually delete the 2 old buckets when you are satisfied ## Upgrades ### 0.6.x to 1.0 -- The module no longer assumes that IAM policies for the tfstate access are required. These policies - are not needed by the module, they are merely a convenience (making it easy for you to control - access to the tfstates stored in the backend bucket). To generate the policies as in 0.6, set one - or both `create_tfstate_access_polic*` variables to true, depending on your needs. -- The module no longer assumes a default set of tags. Only `var.extra_tags` is used, and - by default it is empty. The terraform plan will clearly say what the old values were, if you - need some of them. -- The module now requires a value for `backends_bucket_name`. This won't likely affect you because - you almost certainly had to specify a name anyway, due - to [AWS uniqueness constraints on S3 bucket names](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html). - But if you were able to not specify it (indicating you were probably the first to use that default - name in yours AWS partition), you must now add `backends_bucket_name = "tfstate-s3-backends"`. - However, I highly recommend that you rename your backends bucket to something unique to you or - your organization / employer. Eg `ORG_NAME-GROUP_NAME-tfstate-backends`. The procedure to do this - is in a separate section of this readme. -- The module no longer defines providers, as recommended in the terraform documentation. Therefore, - before applying, +1. (Optional) The module no longer assumes that IAM policies for the tfstate access are required. + These policies are not needed by the module, they are merely a convenience (making it easy for + you to control access to the tfstates stored in the backend bucket). To generate the policies as + in 0.6, set one or both `create_tfstate_access_polic*` variables to true, depending on your + needs. +2. (Optional) The module no longer assumes a default set of tags. Only `var.extra_tags` is used, and + by default it is empty. The terraform plan will clearly say what the old values were, if you + need some of them. +3. Rename variable `this_tfstate_in_s3` to `manager_tfstate_in_s3` +4. The module now requires a value for `backends_bucket_name` (it no longer provides a default). + This won't likely affect you because you almost certainly had to specify a bucket name anyway, + due + to [AWS uniqueness constraints on S3 bucket names](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html). + But if you were able to not specify it (eg if you were the first to use that default bucket name + in yours AWS partition), you must now add `backends_bucket_name = "tfstate-s3-backends"`. + However, I highly recommend that you rename your backends bucket to something unique to you or + your organization / employer. Eg `ORG_NAME-GROUP_NAME-tfstate-backends`. The procedure to do this + is in a separate section of this readme. +5. The module itself no longer defines providers, as recommended in the terraform documentation. + Rather, it requires they be passed in to the module. Therefore, before applying, - ensure you have these two blocks (as done in `examples/simple/tfstate-s3-manager/terraform.tf`): ```hcl @@ -136,12 +117,12 @@ have many sub-stacks. HOWEVER I have not tested yet, so please test it first. aws.replica = aws.tfstate_backends_replica } ``` -- The module now uses the `aws_s3_bucket_*` resources instead of the inline blocks that the AWS - provider has deprecated, like acl, server-side encryption, etc. This will cause terraform to - plan generating those resources, unless you import them into your tfstate. I use the bash script - `scripts/upgrade-to-1.0.sh`. I recommend echoing the terraform command that will be run to - verify that it makes sense, as there are too many possibilities to say for sure that the - script will work as-is. +6. (Optional) The module now uses the `aws_s3_bucket_*` resources instead of the inline blocks that + the AWS provider has deprecated, like acl, server-side encryption, etc. This will cause terraform + to plan generating those resources, unless you import them into your tfstate. I use the bash + script `scripts/upgrade-to-1.0.sh`. I recommend testing it first: open the script in an editor + and add an "echo" in front of the terraform commands to verify that it makes sense, as there are + too many possibilities to say for sure that the script will work as-is. ## Acknowledgements diff --git a/scripts/rename-backends-manager-bucket.sh b/scripts/rename-backends-manager-bucket.sh index 7a8c817..ccb6f93 100755 --- a/scripts/rename-backends-manager-bucket.sh +++ b/scripts/rename-backends-manager-bucket.sh @@ -6,18 +6,16 @@ usage() { echo echo "ERROR: missing command line arguments" echo - echo "Usage: $(basename $0) NEW_BUCKET_NAME BACKENDS_MODULE_PATH [CURRENT_BUCKET]" + echo "Usage: $(basename "$0") NEW_BUCKET_NAME [CURRENT_BUCKET]" echo - echo "- BACKENDS_MODULE_PATH: can be determined by looking at the terraform state list" - echo "- CURRENT_BUCKET: only needed if there is no backend.tf (eg it has already been deleted)" + echo "- NEW_BUCKET_NAME: name for new backends bucket (must match 'backends_bucket_name'" + echo " that you specified in your tf code)" + echo "- CURRENT_BUCKET: current name of backends bucket (only needed if there is " + echo " no backend.tf, eg it has already been deleted)" echo echo "Example:" echo - echo " $(basename $0) new_bucket module.tfstate_manager" - echo - echo "which assumes you have a 'module \"tfstate_manager\"' block in your" - echo "root module, with its 'source' pointing to schollii/multi-stack-backends/aws" - echo "(or its equivalent github URL)" + echo " $(basename "$0") new_bucket" echo } @@ -26,38 +24,42 @@ if [[ -z $new_bucket_name ]]; then usage exit 1 fi -manager_state_prefix=$2 # ex: "module.tfstate_backends.module.multi_stack_backends" -if [[ -z $manager_state_prefix ]]; then - usage - exit 2 -fi -current_bucket=$3 -if [[ -z $current_bucket ]]; then +current_bucket_name=$2 +if [[ -z $current_bucket_name ]]; then if [[ ! -f ./backend.tf ]]; then echo "ERROR: No ./backend.tf file found. You must specify the bucket name as third arg." exit 8 fi - current_bucket=$(sed -En 's/ *bucket *= *"([a-z0-9][a-z0-9.-]+[a-z0-9])"/\1/p' backend.tf) - if [[ -z $current_bucket ]]; then + current_bucket_name=$(sed -En 's/ *bucket *= *"([a-z0-9][a-z0-9.-]+[a-z0-9])"/\1/p' backend.tf) + if [[ -z $current_bucket_name ]]; then echo "ERROR: Could not determine current bucket from ./backend.tf." exit 10 fi - - echo "Current bucket is: $current_bucket" - read -p "Is this correct (y/n)? " -n 1 -r - echo - if [[ ! $REPLY =~ ^(y|Y)$ ]]; then - exit 0 - fi fi -if [[ $current_bucket == $new_bucket_name ]]; then +if [[ $current_bucket_name == "$new_bucket_name" ]]; then echo "ERROR: current and new bucket names are the same!!" exit 5 fi +manager_state_prefix=$(terraform state list | sed -En 's/(.*)\.aws_s3_bucket\.tfstate_backends/\1/p') +if [[ -z $manager_state_prefix ]]; then + echo "ERROR: could not determine which tf resource is backends bucket" + exit 2 +fi + +# Confirm: +echo "Current bucket: $current_bucket_name" +echo "New bucket: $new_bucket_name" +echo "Manager tfstate prefix: $manager_state_prefix" +read -p "Is this correct (y/n)? " -n 1 -r +echo +if [[ ! $REPLY =~ ^(y|Y)$ ]]; then + exit 0 +fi + echo echo "Moving manager tfstate to local host, without confirmation from user" rm -f backend.tf @@ -65,8 +67,8 @@ terraform init -migrate-state -force-copy echo echo "Making terraform forget about the 2 current buckets:" -terraform state rm $manager_state_prefix.aws_s3_bucket.tfstate_backends -terraform state rm $manager_state_prefix.aws_s3_bucket.replica +terraform state rm "$manager_state_prefix.aws_s3_bucket.tfstate_backends" +terraform state rm "$manager_state_prefix.aws_s3_bucket.replica" echo echo "Running terraform apply" @@ -78,16 +80,16 @@ terraform apply # copy tfstates to the new bucket just created, except the old manager state: echo "Copying the stacks tfstates" -aws s3 cp "s3://$current_bucket" "s3://$new_bucket_name" --recursive -aws s3 rm "s3://$new_bucket_name/_manager_" --recursive +aws s3 cp "s3://$current_bucket_name/" "s3://$new_bucket_name/" --recursive +aws s3 rm "s3://$new_bucket_name/_manager_/" --recursive # move the manager's tfstate back into s3 terraform init -migrate-state -force-copy echo echo "DONE!" -echo "NOTE: VERIFY that all tfstates have been properly transfered. Eg, run 'terraform apply'" -echo "in all substacks: no changes should be planned." +echo "NOTE: VERIFY that all tfstates have been properly transfered. Eg, run" +echo "'terraform plan' in all substacks: no changes should be planned." echo "ONCE YOU ARE SATISFIED, YOU CAN MANUALLY DELETE THE TWO PREVIOUS BUCKETS." -echo "Example: aws s3 rb \"s3://$current_bucket\" --force" -echo "Example: aws s3 rb \"s3://${current_bucket}-replica\" --force" +echo "Example: aws s3 rb \"s3://$current_bucket_name\" --force" +echo "Example: aws s3 rb \"s3://${current_bucket_name}-replica\" --force" diff --git a/test/basic_test.go b/test/basic_test.go index f1426f8..207001d 100644 --- a/test/basic_test.go +++ b/test/basic_test.go @@ -65,4 +65,5 @@ func TestTerraformBasicExample(t *testing.T) { // website::tag::3::Check the output against expected values. // Verify we're getting back the outputs we expect assert.Equal(t, "us-east-1", outputs.Tfstate_backends_bucket.Region) + assert.Equal(t, "us-west-1", outputs.Replica_bucket.Region) }