Skip to content

Instantly share code, notes, and snippets.

@ddepaoli3
Last active September 9, 2023 04:34
Show Gist options
  • Save ddepaoli3/c4d78779393acd0336c405632ce922b8 to your computer and use it in GitHub Desktop.
Save ddepaoli3/c4d78779393acd0336c405632ce922b8 to your computer and use it in GitHub Desktop.
Simple wrapper script to create or update multiple cloudformation script
#!/bin/bash
PROFILE=${PROFILE:-'profile-name'}
PROJECT=${PROJECT:-'project-name'}
ENV=${ENV:-'environment'}
REGION=${REGION:-'eu-west-1'}
PARAMETERS_FOLDER=${PARAMETERS_FOLDER:-'parameters'} # '.' if the same folder
TEMPLATE_EXTENSION=${TEMPLATE_EXTENSION:-'yml'} #or yml. Depends on your preference
ENVIRONMENT_PARAMETER_NAME=${ENVIRONMENT_PARAMETER_NAME:-'EnvironmentVersion'}
RESOURCE=()
OPERATION='create'
DRY_RUN=false
print_help()
{
cat << EOF
usage: $0 [-h] -o [create,update] -e [Environment] -d resourcename1 resourcename2 ...
This script create or update cloudformation script
OPTIONS:
-h Show this message
-e Environment name
-o Operation to do. Allowed values [create, update, delete]
-d Dry run. Only print aws commands
CONVENTIONS:
This script assumes that the template and parameters file name have a specific format:
Template: <resourcename>.<extension>
Parameters: <resourcename>-parameters-<environment>.json
This script create stack with this name:
<project>-<environment>-<resourcename>
Example:
I have a template that create an rds for production environment for a project called github.
Template name: rds.yaml
Parameters name: rds-parameters-production.json
After run this command: ./$0 -o create -e production rds
the stack 'github-production-rds' will be created
EOF
}
create_stack(){
for res in "${RESOURCE[@]}"
do
command="aws cloudformation \
create-stack \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--template-body file://$res.$TEMPLATE_EXTENSION \
--parameters file://$PARAMETERS_FOLDER/$res-parameters-$ENV.json \
--region $REGION \
--capabilities CAPABILITY_NAMED_IAM"
echo $command
if ! $DRY_RUN
then
$command
aws cloudformation \
wait stack-create-complete \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--region $REGION
exit 0
fi
done
}
update_stack()
{
for res in "${RESOURCE[@]}"
do
command="aws cloudformation \
update-stack \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--template-body file://$res.$TEMPLATE_EXTENSION \
--parameters file://$PARAMETERS_FOLDER/$res-parameters-$ENV.json \
--region $REGION \
--capabilities CAPABILITY_NAMED_IAM"
echo $command
if ! $DRY_RUN
then
$command
aws cloudformation \
wait stack-update-complete \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--region $REGION
exit 0
fi
done
}
delete_stack()
{
echo "Are you sure to delete stack? Type deleteme to continue"
read confirmation_string
if [[ $confirmation_string == 'deleteme' ]]
then
echo "Starting delete stack"
else
exit 1
fi
for res in "${RESOURCE[@]}"
do
command="aws cloudformation \
delete-stack \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--region $REGION"
echo $command
if ! $DRY_RUN
then
$command
aws cloudformation \
wait stack-delete-complete \
--profile $PROFILE \
--stack-name $(get_stack_name $res) \
--region $REGION
exit 0
fi
done
}
has_version()
{
version=`cat $1 | jq --arg ENVIRONMENT_PARAMETER_NAME "$ENVIRONMENT_PARAMETER_NAME" '(.[] | select(.ParameterKey == $ENVIRONMENT_PARAMETER_NAME) | .ParameterValue)'|sed s/'"'//g`
echo $version
}
get_stack_name()
{
resource=$1
version=$(has_version $PARAMETERS_FOLDER/$resource-parameters-$ENV.json)
if [ $version ]
then
name=$PROJECT-$ENV-$resource-$version
else
name=$PROJECT-$ENV-$resource
fi
echo $name
}
############
### MAIN ###
############
while getopts "he:o:d" opt
do
case $opt in
h)
print_help
exit -1
;;
e)
ENV=$OPTARG
;;
o)
OPERATION=$OPTARG
;;
d)
DRY_RUN=true
;;
?)
echo "Option/s error/s"
print_help
exit -1
;;
esac
done
shift $(( OPTIND - 1 ))
for var in "$@"
do
RESOURCE+=($var)
done
if [[ $OPERATION == 'create' ]]
then
create_stack
elif [[ $OPERATION == 'update' ]]
then
update_stack
elif [[ $OPERATION == 'delete' ]]
then
delete_stack
else
echo "Invalid operation $OPERATION: Allowed value are [create, update, delete]"
print_help
fi

Cloudformation bash wrapper

Bash script to wrap some cloudformation operation. The script simplifies the process of creation, updating and deleting cloudformation stack ensuring the respect of some name convention.

Prerequisities

  • awscli installed and configured
  • jq
  • respect the name convention

Convention

The script to work correctly needs that the template and parameters files complies a simple convention.

  • Template file name: "resource"."yaml"
  • Parameter file name: "folder"/"resource"-parameters-"environment".json

resource, folder, yaml, environment can be configured using input parameters or bash variable.

How to configure

The configuration is done setting the variable at the begining of the script or set them in console

  • PROFILE: name of the aws-cli local profile
  • PROJECT: name of the project. It is used in the stack name
  • ENV: environment to use. It is used in the stack name and it must be included in parameters file name
  • REGION: AWS region to use
  • PARAMETERS_FOLDER: name of the folder where are located the parameters file
  • TEMPLATE_EXTENSION: extension of the template file. (yaml, yml, template, json or your custom one)
  • ENVIRONMENT_PARAMETER_NAME: name of the parameters inside the parameters file. If no parameter is preset it is not used in the stack name

Example

Folder tree

There are 3 template and the parameters in the folder with parameters name

├── cfnwrapper.sh
├── rds.yaml
├── vpc.yaml
├── webapp.yaml
├── parameters
│   ├── rds-parameters-production.json
│   ├── rds-parameters-staging.json
│   ├── vpc-parameters-production.json
│   ├── vpc-parameters-staging.json
│   ├── webapp-parameters-production.json
│   └── webapp-parameters-staging.json

Run command

Launching the command ./cfnwrapper.sh -o create -d -e staging vpc rds webapp the script prints:

aws cloudformation create-stack --profile profile-name --stack-name project-name-staging-vpc --template-body file://vpc.yml --parameters file://parameters/vpc-parameters-staging.json --region eu-west-1 --capabilities CAPABILITY_NAMED_IAM
aws cloudformation create-stack --profile profile-name --stack-name project-name-staging-rds-v01 --template-body file://rds.yml --parameters file://parameters/rds-parameters-staging.json --region eu-west-1 --capabilities CAPABILITY_NAMED_IAM
aws cloudformation create-stack --profile profile-name --stack-name project-name-staging-webapp-v23 --template-body file://webapp.yml --parameters file://parameters/webapp-parameters-staging.json --region eu-west-1 --capabilities CAPABILITY_NAMED_IAM

Note the rds and webapp template have the ENVIRONMENT-PARAMETER-NAME and it is used in the stack name, vpc instead has no parameter and the stack name is without it.

Remove -d (dry run) option the script launches the command and wait the stack is completed before launches the next one.

To pass variable from cli: PROFILE=example ./cfnwrapper.sh -o create -e staging vpc rds webapp

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