Skip to content

Instantly share code, notes, and snippets.

@c4urself
Created September 28, 2016 20:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c4urself/fd30a579d8b1698317eeeb5ea87d8f9a to your computer and use it in GitHub Desktop.
Save c4urself/fd30a579d8b1698317eeeb5ea87d8f9a to your computer and use it in GitHub Desktop.
Wrapper around Terraform
#!/bin/sh
set -e
TERRAFORM_BUCKET_REGION='us-east-1'
TERRAFORM_BUCKET_NAME=''
TERRAFORM_VERSION="0.7.4"
actions="plan apply fmt plan-destroy destroy refresh graph validate"
usage() {
echo "Usage: terraform.sh [account] [region] [component] [action] [[log_level]]"
echo
echo "account:"
echo " - dr"
echo " - prod"
echo
echo "region:"
echo " - us-east-1"
echo " - us-west-2"
echo " - ..."
echo
echo "component:"
echo " - core_networking"
echo " - core_infra"
echo " - ..."
echo
echo "action:"
for a in $actions ; do
help="$(terraform help | \grep -E "^[^\w]+$a" | awk -F' ' '{ $1=""; print $0}')";
if test -z "$help" ; then
help="As the name suggests"
fi
echo " - $a -- $help";
done
echo
echo "log_level: (optional)"
echo " - trace"
echo " - debug"
echo " - info"
echo " - warn"
echo " - error"
}
do_echo() {
echo "[terraform wrapper] $(tput setaf 5)$1$(tput sgr0)"
}
do_warn() {
echo "[terraform wrapper] $(tput setaf 3)$1$(tput sgr0)"
}
original_path="$(pwd)"
cleanup() {
echo
cd $original_path
do_echo "Kbye"
}
trap cleanup 0 1
test -n "$AWS_ACCESS_KEY" || { echo 'Environment variable AWS_ACCESS_KEY not set'; exit 1; }
test -n "$AWS_SECRET_KEY" || { echo 'Environment variable AWS_SECRET_KEY not set'; exit 1; }
check_version() {
user_version="$(terraform --version | awk -F'v' '{ print $2 }')"
if test "$user_version" = "$TERRAFORM_VERSION" ; then
do_echo "Version $user_version: $(tput setaf 2)OK$(tput sgr0)"
else
do_warn "Version check failed. You're running $user_version, but $TERRAFORM_VERSION was expected"
exit 1
fi
}
# Validate the input arguments
if [ "$#" -lt 3 ] ; then
usage
exit 1
fi
# Make sure we're all on the same version
check_version
account="$1"
region="$2"
component="$3"
action="$4"
log_level="$5"
log_env=''
# Set up credentials
umbrella_account_id="0000000"
prod_account_id="1111111"
dev_account_id="222222"
credentials_file=".temp_credentials.$account"
account_id="$(eval echo "\$${account}_account_id")"
role_arn="arn:aws:iam::$account_id:role/ops-admin"
role_session="ops"
do_echo "Running \"$component\" in account: $account region: $region"
assume_role() {
test -n "$AWS_MFA_SERIAL" || { do_warn 'Environment variable AWS_MFA_SERIAL not set'; exit 1; }
read -p "Input your TOTP token: " token
aws sts assume-role --output json \
--role-arn ${role_arn} \
--role-session-name ${role_session} \
--serial-number ${AWS_MFA_SERIAL} \
--token-code ${token} > ${credentials_file}
do_echo "Got temporary credentials for $account.$region"
}
check_credentials() {
if [ -s "$credentials_file" ] ; then
old_expiration=$(cat ${credentials_file} | grep "Expiration" | awk -F'"' '{ print $4 }')
if ! python -c "from datetime import datetime; import sys; sys.exit(int(datetime.strptime(\"$old_expiration\", '%Y-%m-%dT%H:%M:%SZ') < datetime.utcnow()))" ; then
assume_role
else
do_echo "Reusing unexpired credentials."
fi
else
assume_role
fi
export AWS_REGION="${region}"
export ASSUMED_ACCESS_KEY_ID="$(cat ${credentials_file} | grep "AccessKeyId" | awk -F'"' '{ print $4 }')"
export ASSUMED_SECRET_ACCESS_KEY="$(cat ${credentials_file} | grep "SecretAccessKey" | awk -F'"' '{ print $4 }')"
export ASSUMED_SESSION_TOKEN="$(cat ${credentials_file} | grep "SessionToken" | awk -F'"' '{ print $4 }')"
access_env="env AWS_ACCESS_KEY_ID=$ASSUMED_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$ASSUMED_SECRET_ACCESS_KEY AWS_SESSION_TOKEN=$ASSUMED_SESSION_TOKEN"
expiration=$(cat ${credentials_file} | grep "Expiration" | awk -F'"' '{ print $4 }')
do_echo "Retrieved temp access key ${AWS_ACCESS_KEY} for role ${role_arn}. Key will expire at ${expiration}"
}
check_credentials
if [ -z "$log_level" ] ; then
log_level=${TF_LOG-unset} # default to env variable if set, otherwise unset so we can have regular output
fi
if ! [ "$log_level" = 'unset' ] ; then
level=$(echo $log_level | tr '[a-z]' '[A-Z]')
do_echo "Log level set to: $level"
log_env="env TF_LOG=$level"
fi
# Validate that the environment has a provider and change directory into it so that all paths in
# Terraform modules are relative to it
test -d "providers/$account/$region/$component" || { do_warn "Component directory 'providers/$account/$region/$component' missing."; exit 1; }
cd "providers/$account/$region/$component"
case "$action" in
plan) ;;
apply) ;;
refresh) ;;
fmt) ;;
validate) ;;
graph) ;;
plan-destroy) ;;
destroy) ;;
*)
do_warn 'Invalid option.'
usage
exit 1
esac
if [ "$action" = "plan-destroy" ] ; then
action="plan"
destroy="-destroy"
elif [ "$action" = "destroy" ] ; then
destroy='-destroy'
force='-force'
fi
# Clear the .terraform directory (we want to pull the state from the remote)
rm -rf "./.terraform"
# Configure remote state storage
do_echo "Configuring terraform remote config"
terraform remote config \
-backend=S3 \
-backend-config="region=$TERRAFORM_BUCKET_REGION" \
-backend-config="bucket=$TERRAFORM_BUCKET_NAME" \
-backend-config="key=$account.$region/$component.tfstate" \
-backend-config="acl=bucket-owner-full-control"
do_echo "Getting latest terraform remote config"
terraform get
if [ "$action" = "plan" ] ; then
do_echo "Creating a plan."
$log_env $access_env terraform plan \
-input=false \
-refresh=true \
-module-depth=-1 \
$destroy
exit 0
elif [ "$action" = "apply" ] ; then
read -p "Are you sure [y/N]: " do_it
if [ "$do_it" = "y" ] ; then
do_echo "Running apply"
$log_env $access_env terraform apply \
-input=false \
-refresh=true \
$force
else
do_echo "Didn't do anything."
fi
else
do_echo "Running $action"
$log_env $access_env terraform "$action"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment