Create a gist now

Instantly share code, notes, and snippets.

Find yourself creating the same AWS CFN stack a lot during testing? Wasting too much time repeating tags? Put your tags and params in json files and use this bash wrapper script to create the cloudformation stack. Provide your own template file, and modify the stackParams and stackTags to your own needs.
# Create AWS CFN Stack - wrapper for `aws cloudformation create-stack`
#Example Usage:
[ $# -eq 0 ] && { echo -e "\nUsage `basename $0` <stack name> <CFN template file> <JSON parameters file> <JSON tags file>\n\nExample:\n`basename $0` mystackname MyCfn.template stackParams.json stackTags.json\n"; exit 1; }
#Inputs
stackName=${1?param missing - Stack Name}
templateFile=${2?param missing - Template File}
paramsFile=${3?param missing - Json Parameters file}
tagsFile=${4?param missing - Json Tags file}
if [ $# -gt 4 ]; then
echo 1>&2 "$0: too many arguments"
exit 1
fi
#Functions
#-------------------------------------------------------------------------------
# Retrieve the status of a cfn stack
#
# Args:
# $1 The name of the stack
#-------------------------------------------------------------------------------
getStackStatus() {
aws cloudformation describe-stacks \
--stack-name $1 \
--query Stacks[].StackStatus \
--output text
}
#-------------------------------------------------------------------------------
# Waits for a stack to reach a given status. If the stack ever reports any
# status other thatn *_IN_PROGRESS we will return failure status, as all other
# statuses that are not the one we are waiting for are considered terminal
#
# Args:
# $1 Stack name
# $2 The stack status to wait for
#-------------------------------------------------------------------------------
waitForState() {
local status
status=$(getStackStatus $1)
while [[ "$status" != "$2" ]]; do
echo "Waiting for stack $1 to obtain status $2 - Current status: $status"
# If the status is not one of the "_IN_PROGRESS" status' then consider
# this an error
if [[ "$status" != *"_IN_PROGRESS"* ]]; then
exitWithErrorMessage "Unexpected status '$status'"
fi
status=$(getStackStatus $1)
sleep 5
done
echo "Stack $1 obtained $2 status"
}
#-------------------------------------------------------------------------------
# Returns content of JSON file containing params or tags
# Strips out all spaces, newlines etc. for input to aws cli command
# Spaces you want in Values should be encoded. e.g.
# {"Key":"Project","Value":"My\u0020Text"}
#
# Args:
# $1 Path to json file of parameters
#-------------------------------------------------------------------------------
getJsonFileContents() {
json=$(awk -v ORS= -v OFS= '{$1=$1}1' ${1})
echo "$json"
}
#-------------------------------------------------------------------------------
# Exit the program with error status 1.
#
# Args:
# $1 Error message to display when exiting
#-------------------------------------------------------------------------------
exitWithErrorMessage() {
echo "ERROR: $1"
exit 1
}
#-------------------------------------------------------------------------------
# Returns a file URL for the given path
#
# Args:
# $1 Path
#-------------------------------------------------------------------------------
getFileUrl() {
if [[ "$(uname -s)" == "Linux"* ]]; then
# The real thing
echo "file://${1}"
elif [[ "$(uname -s)" == "MINGW"* ]]; then
# Git Bash Hack
echo "file://${1:1:1}:${1:2}"
else
# Mac OS X Hack
echo "file:///${1}"
fi
}
#Create Stack
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM \
--disable-rollback \
--parameters $(getJsonFileContents ${paramsFile}) \
--tags $(getJsonFileContents ${tagsFile}) \
--stack-name ${stackName} \
--template-body $(getFileUrl ${templateFile})
if ! [ "$?" = "0" ]; then
exitWithErrorMessage "Cannot create stack ${stackName}!"
fi
#Wait for completion
waitForState ${stackName} "CREATE_COMPLETE"
[
{"ParameterKey": "AMI", "ParameterValue": "ami-d5b59eb6"},
{"ParameterKey": "VPC", "ParameterValue": "vpc-12345678"},
{"ParameterKey": "AZaSubnet", "ParameterValue": "subnet-a1b2c3d4"},
{"ParameterKey": "AZbSubnet", "ParameterValue": "subnet-1a2b3c4d"},
{"ParameterKey": "ECSKey", "ParameterValue": "MyKey"},
{"ParameterKey": "InstanceType", "ParameterValue": "t2.micro"}
]
[
{"Key":"Project","Value":"My\u0020Project"},
{"Key":"Owner","Value":"my@email.com"}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment