diff --git a/README.md b/README.md index ba9a488..e524c7c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,13 @@ This container is used to assist deployments to ECS using CodeDeploy. +## Parameters +Variables must be set in the environment system level. + +|Variable|Type|Description|Default| +|---|---|---|---| +|DEPLOY_TIMEOUT|Integer|Timeout in seconds for deployment|900| +|AWS_CODE_DEPLOY_OUTPUT_STATUS_LIVE|Boolean|If the environment supports live reloading use carriage returns for a single line|True| ## Usage Inside your application repository, create the following files: @@ -82,4 +89,10 @@ docker-compose run --rm deploy This container is made to be used with our terraform modules: - -- \ No newline at end of file +- + +## NOTES - Old Versions + +### 1.x.x +The 1.x.x branch is responsible for the old version, if you have any updates or want to fix a bug, please use this branch. +Be aware when creating a new version, if you change something in 1.x.x, make sure the release must be under the same umbrella. \ No newline at end of file diff --git a/src/deploy-old.sh b/src/deploy-old.sh new file mode 100755 index 0000000..8e0b96f --- /dev/null +++ b/src/deploy-old.sh @@ -0,0 +1,158 @@ +#!/bin/bash -e + +# if [[ ! -f "task-definition.tpl.json" ]]; then +# echo "---> ERROR: task-definition.tpl.json not found" +# exit 0 +# fi + +# ERROR=0 +# if [[ -z "$AWS_DEFAULT_REGION" ]]; then echo "---> ERROR: Missing variable AWS_DEFAULT_REGION"; ERROR=1; fi +# if [[ -z "$APP_NAME" ]]; then echo "---> ERROR: Missing variable APP_NAME"; ERROR=1; fi +# if [[ -z "$CLUSTER_NAME" ]]; then echo "---> ERROR: Missing variable CLUSTER_NAME"; ERROR=1; fi +# if [[ -z "$CONTAINER_PORT" ]]; then echo "---> ERROR: Missing variable CONTAINER_PORT"; ERROR=1; fi +# if [[ -z "$IMAGE_NAME" ]]; then echo "---> ERROR: Missing variable IMAGE_NAME"; ERROR=1; fi +# if [[ "$ERROR" == "1" ]]; then exit 1; fi + +if [[ -z "$DEPLOY_TIMEOUT" ]]; then + echo "---> INFO: Deploy timeout set to default of 900 seconds" +else + echo "---> INFO: Deploy timeout set to ${DEPLOY_TIMEOUT} seconds"; +fi + +DEPLOY_CONCURRENCY_MODE=${DEPLOY_CONCURRENCY_MODE:-fail} +if [[ "$DEPLOY_CONCURRENCY_MODE" == "wait" ]] +then + echo "---> INFO: Deploy concurrency mode set to 'wait' a previous deployment to finish before continuing" +else + echo "---> INFO: Deploy concurrency mode set to 'fail'" +fi + +envsubst < task-definition.tpl.json > task-definition.json +echo "---> Task Definition" +cat task-definition.json + +export TASK_ARN=$(aws ecs register-task-definition --cli-input-json file://./task-definition.json | jq --raw-output '.taskDefinition.taskDefinitionArn') + +envsubst < app-spec.tpl.json > app-spec.json +echo "---> App-spec for CodeDeploy" +cat app-spec.json +echo +echo "---> Creating deployment with CodeDeploy" + +set +e # disable bash exit on error + +DEPLOY_TIMEOUT_PERIOD=0 + +while [ "${DEPLOYMENT_ID}" == "" ] +do + if [ "$DEPLOY_TIMEOUT_PERIOD" -ge "${DEPLOY_TIMEOUT:-900}" ]; then + echo "===> Timeout reached trying to create deployment. Exiting" + exit 1 + fi + + DEPLOYMENT_ID=$(aws deploy create-deployment \ + --application-name $CLUSTER_NAME-$APP_NAME \ + --deployment-config-name CodeDeployDefault.ECSAllAtOnce \ + --deployment-group-name $CLUSTER_NAME-$APP_NAME \ + --description Deployment \ + --revision file://app-spec.json \ + --query="deploymentId" --output text) + + if [ $? -eq 255 ] && [ "${DEPLOY_CONCURRENCY_MODE}" == "fail" ] + then + # In case there is already a deployment in progress, script will fail + echo + echo + echo "===> Deployment already in progress for this application environment. Please approve or rollback current deployment before performing a new deployment" + echo + echo + exit 1 + fi + + sleep 10 # Wait until deployment is created + DEPLOY_TIMEOUT_PERIOD=$((DEPLOY_TIMEOUT_PERIOD + 10)) +done + +echo "---> For more info: https://$AWS_DEFAULT_REGION.console.aws.amazon.com/codesuite/codedeploy/deployments/$DEPLOYMENT_ID" + +/work/tail-ecs-events.py & +TAIL_ECS_EVENTS_PID=$! + +RET=0 + +while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "Created" ] +do + sleep 1 +done + +echo "---> Deployment created!" + +DEPLOY_TIMEOUT_PERIOD=0 +DEPLOY_TIMEOUT_REACHED=0 + +while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "InProgress" ] +do + if [ "$DEPLOY_TIMEOUT_PERIOD" -ge "${DEPLOY_TIMEOUT:-900}" ]; then + echo "---> WARNING: Timeout reached. Rolling back deployment..." + aws deploy stop-deployment --deployment-id $DEPLOYMENT_ID --auto-rollback-enabled + DEPLOY_TIMEOUT_REACHED=1 + fi + sleep 1 + DEPLOY_TIMEOUT_PERIOD=$((DEPLOY_TIMEOUT_PERIOD + 1)) +done + +TASK_SET_ID=$(aws ecs describe-services --cluster $CLUSTER_NAME --service $APP_NAME --query "services[0].taskSets[?status == 'ACTIVE'].id" --output text) +if [ "${TASK_SET_ID}" != "" ]; then + echo "---> Task Set ID: $TASK_SET_ID" +fi + +# Due the known issue on Codedeploy, CodeDeploy will fail the deployment if the ECS service is unhealthy/unstable for 5mins for replacement +# taskset during the wait status, this 5mins is a non-configurable value as today. +# For the reason above we wait for 10 minutes before consider the deployment in ready status as successful + +WAIT_PERIOD=0 +MAX_WAIT=300 #$(aws ecs describe-services --cluster $CLUSTER_NAME --service $APP_NAME --query services[0].healthCheckGracePeriodSeconds --output text) +MAX_WAIT_BUFFER=60 + +echo "---> Waiting $((MAX_WAIT + MAX_WAIT_BUFFER)) seconds for tasks to stabilise" + +while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "Ready" ] +do + if [ "$WAIT_PERIOD" -ge "$((MAX_WAIT + MAX_WAIT_BUFFER))" ]; then + break + fi + sleep 10 + WAIT_PERIOD=$((WAIT_PERIOD + 10)) +done + +DEPLOYMENT_STATUS=$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text) +echo "---> Deployment status: $DEPLOYMENT_STATUS" + +if [ "$DEPLOYMENT_STATUS" == "Failed" ] || [ "$DEPLOYMENT_STATUS" == "Stopped" ] +then + if [ "$TASK_SET_ID" != "" ] + then + TASK_ARN=$(aws ecs list-tasks --cluster $CLUSTER_NAME --desired-status STOPPED --started-by $TASK_SET_ID --query taskArns[0] --output text) + if [ "${TASK_ARN}" != "None" ]; then + echo "---> Displaying logs of STOPPED task: $TASK_ARN" + /work/tail-task-logs.py $TASK_ARN + fi + fi + RET=1 +elif [ "$DEPLOYMENT_STATUS" == "Succeeded" ] +then + RET=0 +fi + +if [ $RET -eq 0 ]; then + echo "---> Completed!" +else + if [ $DEPLOY_TIMEOUT_REACHED -eq 1 ]; then + echo "---> Deploy timeout reached and rollback triggered." + fi + echo "---> ERROR: Deployment FAILED!" +fi + +kill $TAIL_ECS_EVENTS_PID + +exit $RET \ No newline at end of file diff --git a/src/deploy.sh b/src/deploy.sh index 987c8fe..8076813 100755 --- a/src/deploy.sh +++ b/src/deploy.sh @@ -1,158 +1,332 @@ -#!/bin/bash -e +#!/usr/bin/env bash + +set +e +set -o noglob + + +# +# Set Colors +# + +bold="\e[1m" +dim="\e[2m" +underline="\e[4m" +blink="\e[5m" +reset="\e[0m" +red="\e[31m" +green="\e[32m" +blue="\e[34m" + + +# +# Common Output Styles +# + +h1() { + printf "\n${bold}${underline}%s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +h2() { + printf "\n${bold}%s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +info() { + printf "${dim}➜ %s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +success() { + printf "${green}✔ %s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +error() { + printf "${red}${bold}✖ %s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +warnError() { + printf "${red}✖ %s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +warnNotice() { + printf "${blue}✖ %s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} +note() { + printf "\n${bold}${blue}Note:${reset} ${blue}%s${reset}\n" "$(echo "$@" | sed '/./,$!d')" +} + +# Runs the specified command and logs it appropriately. +# $1 = command +# $2 = (optional) error message +# $3 = (optional) success message +# $4 = (optional) global variable to assign the output to +runCommand() { + command="$1" + info "$1" + output="$(eval $command 2>&1)" + ret_code=$? + + if [ $ret_code != 0 ]; then + warnError "$output" + if [ ! -z "$2" ]; then + error "$2" + fi + exit $ret_code + fi + + if [ ! -z "$3" ]; then + success "$3" + fi + + if [ ! -z "$4" ]; then + eval "$4='$output'" + fi +} + +typeExists() { + if [ $(type -P $1) ]; then + return 0 + fi + return 1 +} + +jsonValue() { + key=$1 + num=$2 + awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$key'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p +} + +vercomp() { + if [[ $1 == $2 ]] + then + return 0 + fi + local IFS=. + local i ver1=($1) ver2=($2) + + # fill empty fields in ver1 with zeros + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) + do + ver1[i]=0 + done + + for ((i=0; i<${#ver1[@]}; i++)) + do + if [[ -z ${ver2[i]} ]] + then + # fill empty fields in ver2 with zeros + ver2[i]=0 + fi + if ((10#${ver1[i]} > 10#${ver2[i]})) + then + return 1 + fi + if ((10#${ver1[i]} < 10#${ver2[i]})) + then + return 2 + fi + done + return 0 +} + +isjsonValid() { + file=$1 + info "Verifying if file $file is a valid JSON" + if [ $(cat $file | jq empty > /dev/null 2>&1; echo $?) -eq 0 ]; then + success "File $file is a valid JSON file" + else + error "File $file is not a valid JSON file" + fi + return $? +} + +# ----- Check variables ----- +h1 "Step 1: Checking environment variables" if [[ ! -f "task-definition.tpl.json" ]]; then - echo "---> ERROR: task-definition.tpl.json not found" - exit 0 + error "File: task-definition.tpl.json not found" + exit 1 fi -ERROR=0 -if [[ -z "$AWS_DEFAULT_REGION" ]]; then echo "---> ERROR: Missing variable AWS_DEFAULT_REGION"; ERROR=1; fi -if [[ -z "$APP_NAME" ]]; then echo "---> ERROR: Missing variable APP_NAME"; ERROR=1; fi -if [[ -z "$CLUSTER_NAME" ]]; then echo "---> ERROR: Missing variable CLUSTER_NAME"; ERROR=1; fi -if [[ -z "$CONTAINER_PORT" ]]; then echo "---> ERROR: Missing variable CONTAINER_PORT"; ERROR=1; fi -if [[ -z "$IMAGE_NAME" ]]; then echo "---> ERROR: Missing variable IMAGE_NAME"; ERROR=1; fi -if [[ "$ERROR" == "1" ]]; then exit 1; fi +if [ -z "$AWS_DEFAULT_REGION" ]; then + error "Please set the \"\$AWS_DEFAULT_REGION\" variable" + exit 1 +fi -if [[ -z "$DEPLOY_TIMEOUT" ]]; then - echo "---> INFO: Deploy timeout set to default of 900 seconds" -else - echo "---> INFO: Deploy timeout set to ${DEPLOY_TIMEOUT} seconds"; +if [ -z "$APP_NAME" ]; then + error "Please set the \"\$APP_NAME\" variable" + exit 1 fi -DEPLOY_CONCURRENCY_MODE=${DEPLOY_CONCURRENCY_MODE:-fail} -if [[ "$DEPLOY_CONCURRENCY_MODE" == "wait" ]] -then - echo "---> INFO: Deploy concurrency mode set to 'wait' a previous deployment to finish before continuing" -else - echo "---> INFO: Deploy concurrency mode set to 'fail'" +if [ -z "$CLUSTER_NAME" ]; then + error "Please set the \"\$CLUSTER_NAME\" variable" + exit 1 fi -envsubst < task-definition.tpl.json > task-definition.json -echo "---> Task Definition" -cat task-definition.json +if [ -z "$CONTAINER_PORT" ]; then + error "Please set the \"\$CONTAINER_PORT\" variable" + exit 1 +fi -export TASK_ARN=$(aws ecs register-task-definition --cli-input-json file://./task-definition.json | jq --raw-output '.taskDefinition.taskDefinitionArn') +if [ -z "$IMAGE_NAME" ]; then + error "Please set the \"\$IMAGE_NAME\" variable" + exit 1 +fi -envsubst < app-spec.tpl.json > app-spec.json -echo "---> App-spec for CodeDeploy" -cat app-spec.json -echo -echo "---> Creating deployment with CodeDeploy" +success "Variables ok" -set +e # disable bash exit on error +# ----- Create task definition file ----- +h1 "Step 2: Replace variables inside of task-definition.tpl.json" +runCommand "envsubst < task-definition.tpl.json > task-definition.json" \ + "Create task definition file failed" \ + "Create task definition file" -DEPLOY_TIMEOUT_PERIOD=0 +isjsonValid "task-definition.json" +info "Task definition file:" +cat task-definition.json | jq -while [ "${DEPLOYMENT_ID}" == "" ] -do - if [ "$DEPLOY_TIMEOUT_PERIOD" -ge "${DEPLOY_TIMEOUT:-900}" ]; then - echo "===> Timeout reached trying to create deployment. Exiting" - exit 1 - fi +# ----- Register task definition file ----- +h1 "Step 3: Registering task definition" +runCommand "aws ecs register-task-definition --cli-input-json file://./task-definition.json" \ + "Register task definition failed" \ + "Register task definition" \ + OUTPUT_TASK_ARN - DEPLOYMENT_ID=$(aws deploy create-deployment \ - --application-name $CLUSTER_NAME-$APP_NAME \ - --deployment-config-name CodeDeployDefault.ECSAllAtOnce \ - --deployment-group-name $CLUSTER_NAME-$APP_NAME \ - --description Deployment \ - --revision file://app-spec.json \ - --query="deploymentId" --output text) +OUTPUT_TASK_ARN=$(echo $OUTPUT_TASK_ARN | jq --raw-output '.taskDefinition.taskDefinitionArn') +export TASK_ARN=$OUTPUT_TASK_ARN - if [ $? -eq 255 ] && [ "${DEPLOY_CONCURRENCY_MODE}" == "fail" ] - then - # In case there is already a deployment in progress, script will fail - echo - echo - echo "===> Deployment already in progress for this application environment. Please approve or rollback current deployment before performing a new deployment" - echo - echo - exit 1 - fi - - sleep 10 # Wait until deployment is created - DEPLOY_TIMEOUT_PERIOD=$((DEPLOY_TIMEOUT_PERIOD + 10)) -done +# ----- Create app spec file ----- +h1 "Step 4: Creating App Spec for CodeDeploy" +runCommand "envsubst < app-spec.tpl.json > app-spec.json" \ + "Create app-spec file failed" \ + "Create app-spec file" -echo "---> For more info: https://$AWS_DEFAULT_REGION.console.aws.amazon.com/codesuite/codedeploy/deployments/$DEPLOYMENT_ID" +isjsonValid "app-spec.json" +info "App spec file:" +cat app-spec.json | jq -/work/tail-ecs-events.py & -TAIL_ECS_EVENTS_PID=$! +# ----- Create Deployment ----- +h1 "Step 5: Creating Deployment" +APPLICATION_NAME=$CLUSTER_NAME-$APP_NAME +DEPLOYMENT_CONFIG_NAME=CodeDeployDefault.ECSAllAtOnce +DEPLOYMENT_GROUP=$CLUSTER_NAME-$APP_NAME -RET=0 +# TODO: Check if is there any deployment in progress -while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "Created" ] -do - sleep 1 -done +DEPLOYMENT_CMD="aws deploy create-deployment \ + --output json \ + --application-name $APPLICATION_NAME \ + --deployment-config-name $DEPLOYMENT_CONFIG_NAME \ + --deployment-group-name $DEPLOYMENT_GROUP \ + --description Deployment \ + --revision file://app-spec.json" + +DEPLOYMENT_OUTPUT="" +runCommand "$DEPLOYMENT_CMD" \ + "Deployment of application \"$APPLICATION_NAME\" on deployment group \"$DEPLOYMENT_GROUP\" failed" \ + "" \ + DEPLOYMENT_OUTPUT -echo "---> Deployment created!" +DEPLOYMENT_ID=$(echo $DEPLOYMENT_OUTPUT | jsonValue 'deploymentId' | tr -d ' ') +success "Successfully created deployment: \"$DEPLOYMENT_ID\"" +note "For more info, you can follow your deployment at: https://$AWS_DEFAULT_REGION.console.aws.amazon.com/codesuite/codedeploy/deployments/$DEPLOYMENT_ID" + + +# ----- Monitor Deployment ----- +h1 "Step 6: Deployment Overview" DEPLOY_TIMEOUT_PERIOD=0 -DEPLOY_TIMEOUT_REACHED=0 - -while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "InProgress" ] -do - if [ "$DEPLOY_TIMEOUT_PERIOD" -ge "${DEPLOY_TIMEOUT:-900}" ]; then - echo "---> WARNING: Timeout reached. Rolling back deployment..." - aws deploy stop-deployment --deployment-id $DEPLOYMENT_ID --auto-rollback-enabled - DEPLOY_TIMEOUT_REACHED=1 - fi + +DEPLOYMENT_GET="aws deploy get-deployment --output json --deployment-id \"$DEPLOYMENT_ID\"" +h2 "Monitoring deployment \"$DEPLOYMENT_ID\" for \"$APPLICATION_NAME\" on deployment group $DEPLOYMENT_GROUP ..." +info "$DEPLOYMENT_GET" + +TASK_SET_ID="" + +while [ "${TASK_SET_ID}" == "" ]; do + TASK_SET_ID=$(aws ecs describe-services --cluster $CLUSTER_NAME --service $APP_NAME --query "services[0].taskSets[?status == 'ACTIVE'].id" --output text) sleep 1 - DEPLOY_TIMEOUT_PERIOD=$((DEPLOY_TIMEOUT_PERIOD + 1)) done -TASK_SET_ID=$(aws ecs describe-services --cluster $CLUSTER_NAME --service $APP_NAME --query "services[0].taskSets[?status == 'ACTIVE'].id" --output text) -if [ "${TASK_SET_ID}" != "" ]; then - echo "---> Task Set ID: $TASK_SET_ID" +info "Task Set ID: $TASK_SET_ID" + +# If the environment supports live reloading use carriage returns for a single line. +if [ "true" == "${AWS_CODE_DEPLOY_OUTPUT_STATUS_LIVE:-true}" ]; then + status_opts="\r${bold}" + status_opts_live="\r${bold}${blink}" +else + status_opts="\n${bold}" + status_opts_live="\n${bold}" fi -# Due the known issue on Codedeploy, CodeDeploy will fail the deployment if the ECS service is unhealthy/unstable for 5mins for replacement -# taskset during the wait status, this 5mins is a non-configurable value as today. -# For the reason above we wait for 10 minutes before consider the deployment in ready status as successful +h2 "Monitoring ECS service events for cluster ($CLUSTER_NAME) on service ($APP_NAME):" +/work/tail-ecs-events.py & TAIL_ECS_EVENTS_PID=$! +printf "\n" -WAIT_PERIOD=0 -MAX_WAIT=300 #$(aws ecs describe-services --cluster $CLUSTER_NAME --service $APP_NAME --query services[0].healthCheckGracePeriodSeconds --output text) -MAX_WAIT_BUFFER=60 +while : + do + DEPLOYMENT_GET_OUTPUT="$(eval $DEPLOYMENT_GET 2>&1)" + if [ $? != 0 ]; then + warnError "$DEPLOYMENT_GET_OUTPUT" + error "Deployment of application \"$APPLICATION_NAME\" on deployment group \"$DEPLOYMENT_GROUP\" failed" + exit 1 + fi -echo "---> Waiting $((MAX_WAIT + MAX_WAIT_BUFFER)) seconds for tasks to stabilise" + # Deployment Overview + IN_PROGRESS=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "InProgress" | tr -d "\r\n ") + PENDING=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "Pending" | tr -d "\r\n ") + SKIPPED=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "Skipped" | tr -d "\r\n ") + SUCCEEDED=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "Succeeded" | tr -d "\r\n ") + FAILED=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "Failed" | tr -d "\r\n ") -while [ "$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text)" == "Ready" ] -do - if [ "$WAIT_PERIOD" -ge "$((MAX_WAIT + MAX_WAIT_BUFFER))" ]; then - break - fi - sleep 10 - WAIT_PERIOD=$((WAIT_PERIOD + 10)) -done + # Deployment Status + STATUS=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "status" | tr -d "\r\n" | tr -d " ") + ERROR_MESSAGE=$(echo "$DEPLOYMENT_GET_OUTPUT" | jsonValue "message") -DEPLOYMENT_STATUS=$(aws deploy get-deployment --deployment-id $DEPLOYMENT_ID --query deploymentInfo.status --output text) -echo "---> Deployment status: $DEPLOYMENT_STATUS" + # Check if containers are being stoped + LAST_TASK_ARN=$(aws ecs list-tasks --cluster $CLUSTER_NAME --desired-status STOPPED --started-by $TASK_SET_ID --query taskArns[0] --output text) + if [ "${LAST_TASK_ARN}" != "None" ]; then + LAST_TASK_INFO=$(aws ecs describe-tasks --cluster $CLUSTER_NAME --tasks $LAST_TASK_ARN --query tasks[0]) + LAST_TASK_STATUS=$(echo $LAST_TASK_INFO | jq -r .lastStatus) + LAST_TASK_REASON=$(echo $LAST_TASK_INFO | jq -r .stoppedReason) -if [ "$DEPLOYMENT_STATUS" == "Failed" ] || [ "$DEPLOYMENT_STATUS" == "Stopped" ] -then - if [ "$TASK_SET_ID" != "" ] - then - TASK_ARN=$(aws ecs list-tasks --cluster $CLUSTER_NAME --desired-status STOPPED --started-by $TASK_SET_ID --query taskArns[0] --output text) - if [ "${TASK_ARN}" != "None" ]; then - echo "---> Displaying logs of STOPPED task: $TASK_ARN" - /work/tail-task-logs.py $TASK_ARN + if [ "${LAST_TASK_STATUS}" == "STOPPED" ]; then + runCommand "aws deploy stop-deployment --deployment-id $DEPLOYMENT_ID --auto-rollback-enabled" \ + "Rollback deployment failed" \ + "Rollback deployment success" + STATUS=Failed + ERROR_MESSAGE=$LAST_TASK_REASON + fi fi - fi - RET=1 -elif [ "$DEPLOYMENT_STATUS" == "Succeeded" ] -then - RET=0 -fi -if [ $RET -eq 0 ]; then - echo "---> Completed!" -else - if [ $DEPLOY_TIMEOUT_REACHED -eq 1 ]; then - echo "---> Deploy timeout reached and rollback triggered." - fi - echo "---> ERROR: Deployment FAILED!" -fi -kill $TAIL_ECS_EVENTS_PID + # Rechead limit + if [ "$DEPLOY_TIMEOUT_PERIOD" -ge "${DEPLOY_TIMEOUT:-900}" ]; then + warnNotice "Timeout reached. Rolling back deployment..." + runCommand "aws deploy stop-deployment --deployment-id $DEPLOYMENT_ID --auto-rollback-enabled" \ + "Rollback deployment failed" \ + "Rollback deployment success" + exit 1 + fi + + # Print Status + if [ "$STATUS" == "Failed" ]; then + error "Deployment failed: $ERROR_MESSAGE" + exit 1 + fi + + if [ "$STATUS" == "Stopped" ]; then + warnNotice "Deployment stopped by user" + info "$ERROR_MESSAGE" + exit 1 + fi + + if [ "$STATUS" == "Ready" ]; then + success "Deployment of application \"$APPLICATION_NAME\" on deployment group \"$DEPLOYMENT_GROUP\" ready and waiting for cutover" + break + fi + + if [ "$STATUS" == "Succeeded" ]; then + success "Deployment of application \"$APPLICATION_NAME\" on deployment group \"$DEPLOYMENT_GROUP\" succeeded" + break + fi + + # Increment timeout limit + ((DEPLOY_TIMEOUT_PERIOD=DEPLOY_TIMEOUT_PERIOD+1)) + sleep 1 + done -exit $RET \ No newline at end of file +# Kill PID from tail ecs events +kill $TAIL_ECS_EVENTS_PID \ No newline at end of file