Last active
November 13, 2020 17:57
-
-
Save lantrix/8269da3e93ed6196541e86c160b82a07 to your computer and use it in GitHub Desktop.
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{"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"} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have a short story for you:
This code was a lifesaver. I wrote a similar script without setting up a git remote for the repo. Deleted the source about a week back and only realized it when I was asked for a demo the other day.
My
bash
history told the sad tale of an errant tab-complete, and I frantically started to re-write the lost script before taking a moment to look for something similar/adaptable to my use-case.I'll never make that mistake again, but thought I'd share. OSS saves the day once again, even if it's just a gist.
kudos!