Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active May 26, 2020 06:24
Show Gist options
  • Save qoomon/d6633abe35eea297f475260478f86c8c to your computer and use it in GitHub Desktop.
Save qoomon/d6633abe35eea297f475260478f86c8c to your computer and use it in GitHub Desktop.
Watch CloudFormation Events during `aws cloudformation deploy`
#!/usr/bin/env bash
set -o errexit # exit when a command line fails
set -o pipefail # pipes exit code will be the last non-zero exit code of all pipe commands
set -o nounset # exit on read a undeclared variable
#set -o xtrace # enable debug logging
#### Source: https://gist.github.com/qoomon/d6633abe35eea297f475260478f86c8c
### Usage ###
#
# aws cloudformation deploy --stack-name "$STACK_NAME" ... \
# | ./aws-cloudformation-deploy-watcher.sh --stack-name "$STACK_NAME" ...
#
#############
WATCH_TIMEOUT=$(( 60 * 15 )) # in seconds
WATCH_INTERVAL=2 # in seconds
function echo_help {
echo "usage: $0 [options]"
echo ""
echo "example: aws cloudformation deploy ... | $0 [options]"
echo ""
echo "options:"
echo " --stack-name"
echo " --profile"
echo " --region"
echo " --help"
}
function reverse { sed '1!G;h;$!d'; }
while [[ $# -gt 0 ]]
do
case $1 in
--stack-name) opt_stack_name="$2"; shift 2;;
--profile) opt_profile="$2"; shift 2;;
--region) opt_region="$2"; shift 2;;
--help) echo_help; exit 0;;
*)
>&2 echo "[ERROR] unexpected argument: $1"
>&2 echo_help
exit 1;;
esac
done
if [[ ! "${opt_stack_name:-}" ]]
then
>&2 echo "[ERROR] '--stack-name' parameter missing"
>&2 echo_help
exit 1
fi
while read -r line
do
echo "${line}"
if [[ "${line}" = "Waiting for stack create/update to complete" ]]
then
echo
start_watch_time=$(date +%s)
while [[ $(( $(date +%s) - $start_watch_time )) -lt WATCH_TIMEOUT ]]
do
sleep $WATCH_INTERVAL
prior_deploy_events="${recent_deploy_events:-}"
# get recent stack events since last 'User Initiated' change
recent_deploy_events="$(aws cloudformation describe-stack-events --stack-name "${opt_stack_name}" \
${opt_profile:+ --profile "${opt_profile}"} \
${opt_region:+ --region "${opt_region}"} \
--query 'StackEvents[*].[Timestamp,ResourceType,LogicalResourceId,ResourceStatus,ResourceStatusReason]' --output text \
| awk "NR==1,/\tAWS::CloudFormation::Stack\t${opt_stack_name}\t.*\tUser Initiated\$/" \
| reverse)"
# determine new events
new_deploy_events="$(comm -13 <(echo "${prior_deploy_events}") <(echo "${recent_deploy_events}"))"
if [ -n "$new_deploy_events" ]
then
printf '\r'
# print new event
echo "${new_deploy_events}" \
| awk -F '\t' '{printf "%s %-32s %-32s %-24s %s\n",$1,$2,$3,$4,$5}' \
| sed 's/None$//'
TAB_CHAR=$'\t'
# check for final ERROR state
if (echo "${new_deploy_events}" | grep -q "AWS::CloudFormation::Stack${TAB_CHAR}${opt_stack_name}${TAB_CHAR}.*\(_ROLLBACK_COMPLETE|_FAILED\)${TAB_CHAR}")
then
exit_code=1
break
fi
# check for final Success state
if (echo "${new_deploy_events}" | grep -q "AWS::CloudFormation::Stack${TAB_CHAR}${opt_stack_name}${TAB_CHAR}.*\(_COMPLETE\)${TAB_CHAR}")
then
exit_code=0
break
fi
else
printf '.'
fi
done
echo
fi
done
exit ${exit_code:-0}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment