From 5df0bde3f47568b985f8e70972ff2b2972707916 Mon Sep 17 00:00:00 2001 From: Hammy Date: Sat, 28 Aug 2021 17:36:55 +0100 Subject: [PATCH] Create stacks --- stacks/apply-stacks.sh | 96 +++++++++++++++++++++++++++++++++++++++++ stacks/makefile | 24 +++++++++++ stacks/requirements.txt | 4 ++ stacks/setup.cfg | 2 + stacks/src/template.py | 18 ++++++++ stacks/src/util.py | 16 +++++++ stacks/stacks.iml | 11 +++++ 7 files changed, 171 insertions(+) create mode 100644 stacks/apply-stacks.sh create mode 100644 stacks/makefile create mode 100644 stacks/requirements.txt create mode 100644 stacks/setup.cfg create mode 100644 stacks/src/template.py create mode 100644 stacks/src/util.py create mode 100644 stacks/stacks.iml diff --git a/stacks/apply-stacks.sh b/stacks/apply-stacks.sh new file mode 100644 index 0000000..455fb63 --- /dev/null +++ b/stacks/apply-stacks.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +pwd=$PWD +stack_name="Tweeter" + +export BUILD_DIR=build +export CLOUD_ID="goudham" + +template_path="C:/Users/sgoud/JavaProjects/Tweeter/stacks"/${BUILD_DIR}/${stack_name}.json +change_set_name=${CLOUD_ID}-$(date -u "+%Y-%m-%dT%H-%M-%SZ") + +change_set_params="--change-set-name $change_set_name" +stack_params="--stack-name $stack_name" +create_params="$stack_params \ +--template-body file://$template_path \ +--capabilities CAPABILITY_IAM" + +create_change_set_params="$change_set_params $create_params" + +stack_status="$(aws cloudformation list-stacks \ +| jq '.StackSummaries[]| +select(.StackName == "'${stack_name}'" +and .StackStatus != "DELETE_COMPLETE")| +.StackStatus' | \ +tr -d '"')" + +if [[ "$stack_status" =~ "FAILED" ]] || [[ "$stack_status" =~ "IN_PROGRESS" ]] || [[ "$stack_status" == "ROLLBACK_COMPLETE" ]]; then + echo "ERROR: $stack_name is in a $stack_status state, exiting..." + exit 1 +fi + +#Build the template +make STACK_NAME=${stack_name} +source stacks-venv/Scripts/activate + +if [[ "$stack_status" == "" ]] || [[ " DELETE_COMPLETE ROLLBACK_COMPLETE " =~ " $stack_status " ]]; then + # CREATE + aws cloudformation create-stack ${create_params} --capabilities CAPABILITY_IAM + aws cloudformation wait stack-create-complete ${stack_params} &> /dev/null + if [[ "$?" -ne "0" ]]; then + echo "ERROR: Failed to create $stack_name" + exit 1 + fi +else + # UPDATE + change_sets="$(aws cloudformation list-change-sets ${stack_params})" + change_set_count="$(echo ${change_sets} | jq '.Summaries|length')" + if [[ "$change_set_count" -gt "0" ]]; then + echo "ERROR: $stack_name has $change_set_count outstanding change sets, please execute or delete them." + exit 1 + fi + + create_change_set_response=$(aws cloudformation create-change-set ${create_change_set_params}) + change_set_arn="$(echo ${create_change_set_response} | jq '.Id' | tr -d '"')" + echo "Creating change set $change_set_name for stack $stack_name" + + aws cloudformation wait change-set-create-complete ${change_set_params} ${stack_params} &> /dev/null + + # Most likely failed because there are no changes to apply. + if [[ "$?" -ne "0" ]]; then + echo "No changes to apply, exiting" + aws cloudformation delete-change-set --change-set-name=${change_set_arn} &> /dev/null + exit 0 + fi + + echo "Change set $change_set_name created for stack $stack_name" + + stack_template=$(aws cloudformation get-template --stack-name ${stack_name} | jq -S .) + change_set_template=$(aws cloudformation get-template --change-set-name "${change_set_name}" --stack-name ${stack_name} | jq -S .) + template_diff=$(diff -u <(echo "${stack_template}") <(echo "${change_set_template}") | ydiff -w 0 -s --color=always) + + echo "Changes to be applied:" + + if [[ "$(echo "${template_diff}" | wc -l)" -gt 1 ]]; then + echo "${template_diff}" + fi + + echo "Are you happy with your changes? (yes/no)" + read -r input + if [ "$input" == "no" ]; then + echo "Exiting..." + exit 1 + fi + + echo "Applying changes..." + + aws cloudformation execute-change-set --change-set-name ${change_set_arn} + aws cloudformation wait stack-update-complete ${stack_params} + + if [[ "$?" -ne "0" ]]; then + echo "ERROR: Failed to update $stack_name with change set $change_set_name" + exit 1 + fi +fi + +echo "Successfully applied change set $change_set_name to stack $stack_name" \ No newline at end of file diff --git a/stacks/makefile b/stacks/makefile new file mode 100644 index 0000000..d8154e8 --- /dev/null +++ b/stacks/makefile @@ -0,0 +1,24 @@ +VENV_NAME=stacks-venv +BUILD_DIR=build +STACK_NAME=Tweeter + +all: clean-workspace json-template + +clean-workspace: + rm -rf ${VENV_NAME} + rm -fr $(BUILD_DIR) + +create-build-dir: + mkdir -p $(BUILD_DIR) + +json-template: pycodestyle create-build-dir + . ${VENV_NAME}/Scripts/activate && python src/template.py > ${BUILD_DIR}/${STACK_NAME}.json + +venv: + python -m venv ${VENV_NAME} + ${VENV_NAME}/Scripts/pip install -r requirements.txt + . ${VENV_NAME}/Scripts/activate + echo "virtualenv prepared, please run 'source ${VENV_NAME}/bin/activate' if you wish to use it in your current shell" + +pycodestyle: venv + . ${VENV_NAME}/Scripts/activate && pycodestyle --first src/template.py \ No newline at end of file diff --git a/stacks/requirements.txt b/stacks/requirements.txt new file mode 100644 index 0000000..b4976f3 --- /dev/null +++ b/stacks/requirements.txt @@ -0,0 +1,4 @@ +troposphere==3.0.2 +awacs==2.0.0 +ydiff +pycodestyle==2.7.0 diff --git a/stacks/setup.cfg b/stacks/setup.cfg new file mode 100644 index 0000000..8fbaf1e --- /dev/null +++ b/stacks/setup.cfg @@ -0,0 +1,2 @@ +[pycodestyle] +max-line-length = 160 \ No newline at end of file diff --git a/stacks/src/template.py b/stacks/src/template.py new file mode 100644 index 0000000..0ecc571 --- /dev/null +++ b/stacks/src/template.py @@ -0,0 +1,18 @@ +from troposphere import Template + +from util import Util + +PROJECT_NAME = "Tweeter" +S3_QUEUE_NAME = PROJECT_NAME + "S3Queue" +TWEETER_QUEUE_NAME = PROJECT_NAME + "Queue" +DYNAMO_DB_QUEUE_NAME = PROJECT_NAME + "DynamoDbQueue" +SHARED_CONFIG_BUCKET_NAME = PROJECT_NAME + "SharedConfig" + +template = Template(PROJECT_NAME + "Workflow") +templateUtil = Util(template) + +s3_queue = templateUtil.create_queue(S3_QUEUE_NAME) +tweeter_queue = templateUtil.create_queue(TWEETER_QUEUE_NAME) +dynamo_db_queue = templateUtil.create_queue(DYNAMO_DB_QUEUE_NAME) + +print(template.to_json()) diff --git a/stacks/src/util.py b/stacks/src/util.py new file mode 100644 index 0000000..f8fe737 --- /dev/null +++ b/stacks/src/util.py @@ -0,0 +1,16 @@ +from troposphere.sqs import Queue + + +class Util: + def __init__(self, template): + self.template = template + + def create_queue(self, queue_name): + return self.template.add_resource( + Queue( + queue_name, + MessageRetentionPeriod=345600, + VisibilityTimeout=300, + ReceiveMessageWaitTimeSeconds=20, + ) + ) diff --git a/stacks/stacks.iml b/stacks/stacks.iml new file mode 100644 index 0000000..455d0b1 --- /dev/null +++ b/stacks/stacks.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file