Skip to content

Instantly share code, notes, and snippets.

@nathanielks
Last active June 3, 2023 17:24
Show Gist options
  • Select an option

  • Save nathanielks/5bd4de708e831bbc170f to your computer and use it in GitHub Desktop.

Select an option

Save nathanielks/5bd4de708e831bbc170f to your computer and use it in GitHub Desktop.
Simple wrapper around terraform to manage multiple environments

This script will pull down an S3 remote configuration before running any terraform actions. Assumes the following structure:

main.tf
terraform.cfg
vars/dev
vars/staging
vars/production

ansible.cfg is required for the remote configuration.

You can use it like so:

./terraform-env.sh dev show
./terraform-env.sh staging plan -out plan
./terraform-env.sh production apply -var="some_var=some_value"

You can use the script just like you'd use terraform, passing whatever arguments you would before. It will only pull the latest environment if the current environment is different from the one you're requesting.

#!/bin/bash
function help {
echo "usage: ${0} <environment> <action> [<args>]"
exit 1
}
function contains_element () {
local i
for i in "${@:2}"; do
[[ "$i" == "$1" ]] && return 0
done
return 1
}
#All of the args are mandatory.
if [ $# -lt 1 ]; then
help
fi
# Let's check the existence of the config file
if [ ! -f $CFG_FILE ]; then
echo "Error: $CFG_FILE does not exist. You'll need to create a config file so we know where to set up the remote config."
exit 1
fi
source ./terraform.cfg
# Let's set up our environment
if [[ $default_environment && ${default_environment-x} ]]
then
ENVIRONMENT=$default_environment
ACTION=$1
ADDTL_PARAMS=${*:2}
else
ENVIRONMENT=$1
ACTION=$2
ADDTL_PARAMS=${*:3}
fi
# Let's set up our variables
ALLOWS_VARFILE=(apply plan push refresh destroy)
ENV_FILE=.terraform/environment
VARS_FILE=vars/$ENVIRONMENT
VARS_FILE_FLAG=
BUCKET_KEY=$bucket_prefix/state/$ENVIRONMENT
PREVIOUS_ENVIRONMENT=$([ -f $ENV_FILE ] && echo "$(<$ENV_FILE)" || echo "previous")
# Let's check to see if a vars file exists for the requested environment before proceeding
if [ ! -f $VARS_FILE ]; then
echo "Error: $VARS_FILE does not exist. You'll need to create a vars file for the requested environment before continuing."
exit 1
fi
# Checks if current action allows a varfile to be passed
contains_element "$ACTION" "${ALLOWS_VARFILE[@]}"
if [ $? -eq 0 ]; then
VARS_FILE_FLAG="-var-file=$VARS_FILE"
fi
# Let's check if the requested environment is different from the previous environment
if [ $PREVIOUS_ENVIRONMENT != $ENVIRONMENT ]; then
# Move current state out of the way to make room for the new state
mv -f .terraform/terraform.tfstate .terraform/terraform.tfstate.$PREVIOUS_ENVIRONMENT &>2
mv -f .terraform/terraform.tfstate.backup .terraform/terraform.tfstate.backup.$PREVIOUS_ENVIRONMENT &>2
# Let's log the new environment for later
echo $ENVIRONMENT > $ENV_FILE
# Set up remote configuration and pull latest version
terraform remote config -backend S3 -backend-config="bucket=$bucket" -backend-config="key=$BUCKET_KEY" -backend-config="region=$region"
fi
# Let's do work!
terraform $ACTION $VARS_FILE_FLAG $ADDTL_PARAMS
bucket=some_secret_bucket
bucket_prefix=example
region=us-east-1
default_environment=dev # This is optional. if set, specifying the environment before running commands isn't necessary
@nadnerb
Copy link

nadnerb commented Jul 23, 2015

I just had a chance to look at this. It won't work as you are using the cache located in .terraform/terraform.tfstate. All you will end up doing is changing the location on S3 and then changing the state to use the different variables. It will modify the same infrastructure unless I am missing something?

@nathanielks
Copy link
Author

@nadnerb yeah, I noticed that not too long ago. I'm trying to fix that right now, actually.

@nadnerb
Copy link

nadnerb commented Jul 23, 2015

Cool! I ended up modifying the socorro-infra aws cli S3 version for the moment.

@nathanielks
Copy link
Author

@nadnerb and fixed! Moving the existing state file out of the way allows for the remote config to set up an empty local copy and then pulls whatever is set up remotely. If there's nothing remotely, you have a clean slate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment