Skip to content

Commit d767274

Browse files
committed
Adds the run_command script which was inspiration
I wrote this script for a client and this was the inspiration to built something more full-fledged for repeated usage.
1 parent 452ffff commit d767274

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

run_command

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/env bash
2+
# Inspired by: https://medium.com/hackernoon/running-laravel-artisan-commands-on-aws-fargate-6c0e95f8e72b
3+
# Run a one off command against a Fargate container.
4+
# I dislike bash so much and yet... I created this thing which I like. Confusing.
5+
6+
# Colors
7+
red=$'\e[1;31m'
8+
grn=$'\e[1;32m'
9+
yel=$'\e[1;33m'
10+
blu=$'\e[1;34m'
11+
mag=$'\e[1;35m'
12+
cyn=$'\e[1;36m'
13+
end=$'\e[0m'
14+
15+
# Requirements:
16+
# Jq - Version >= 1.6
17+
# Terraform - Version >= 0.12.21
18+
# AWS CLI - Version >= 1.16.238
19+
20+
# Enforce Versions
21+
AWSCLI_VER_TAR=1.16.238
22+
JQ_VER_TAR=1.6
23+
TERRAFORM_VER_TAR=0.12.21
24+
TERRAFORM_VER=$( terraform --version 2>&1 | cut -d ' ' -f 2 | head -n 1 | cut -d 'v' -f 2 )
25+
AWSCLI_VER=$( aws --version 2>&1 | cut -d ' ' -f 1 | cut -d '/' -f 2 )
26+
JQ_VER=$( jq --version 2>&1 )
27+
28+
if [[ ${AWSCLI_VER} < ${AWSCLI_VER_TAR} ]]; then
29+
echo "ERROR: Please upgrade your AWS CLI to version ${AWSCLI_VER_TAR} or later!"
30+
exit 1
31+
fi
32+
33+
if [[ ${JQ_VER} < ${JQ_VER_TAR} ]]; then
34+
echo "ERROR: Please upgrade JQ version ${JQ_VER_TAR} or later!"
35+
exit 1
36+
fi
37+
38+
if [[ ${TERRAFORM_VER} < ${TERRAFORM_VER_TAR} ]]; then
39+
echo "ERROR: Please upgrade Terraform to version ${TERRAFORM_VER_TAR} or later!"
40+
exit 1
41+
fi
42+
43+
APP_ENV=""
44+
COMMAND=""
45+
DIR=$( dirname ${BASH_SOURCE[0]} )
46+
47+
usage() {
48+
echo "Usage: $0 -e <environment> -c \"<cmd>\""
49+
echo " <environment> must be either 'dev', 'stage', or 'prod'"
50+
echo " <cmd> the manage.py command to execute remotely via fargate"
51+
exit 1
52+
}
53+
54+
while getopts ":e:c:h:" o; do
55+
case "${o}" in
56+
e)
57+
APP_ENV=${OPTARG}
58+
(("${APP_ENV}" == "dev" || "${APP_ENV}" == "stage" || "${APP_ENV}" == "prod")) || usage
59+
;;
60+
c)
61+
COMMAND=${OPTARG}
62+
;;
63+
*)
64+
usage
65+
;;
66+
esac
67+
done
68+
shift $((OPTIND-1))
69+
70+
if [[ -z "${APP_ENV}" ]]; then
71+
usage
72+
fi
73+
74+
if [[ -z "${COMMAND}" ]]; then
75+
usage
76+
fi
77+
78+
CLUSTER_NAME="prefix-${APP_ENV}"
79+
APP_NAME="prefix-${APP_ENV}-app"
80+
81+
# Change directory to our Environment's Terraform Workspace before running `output`
82+
cd ${DIR}/terraform && terraform workspace select ${APP_ENV}
83+
84+
TERRAFORM_OUTPUTS=$( terraform output -json )
85+
PRIVATE_SUBNET_ID=$( echo $TERRAFORM_OUTPUTS | jq ".private_subnet_ids.value | .[0]" | sed -e 's/^"//' -e 's/"$//' )
86+
SECURITY_GROUP=$( echo $TERRAFORM_OUTPUTS | jq ".fargate_security_group.value" | sed -e 's/^"//' -e 's/"$//' )
87+
88+
NETWORK_CONF=$( jq -n \
89+
--arg subnet ${PRIVATE_SUBNET_ID} \
90+
--arg security_group ${SECURITY_GROUP} \
91+
'{
92+
"awsvpcConfiguration": {
93+
"subnets": [ $subnet ],
94+
"securityGroups": [ $security_group ],
95+
"assignPublicIp": "ENABLED"
96+
}
97+
}');
98+
99+
echo "Starting ${cyn}Run Task Operation${end}!"
100+
101+
RUN_TASK_OUTPUT=$( aws ecs run-task \
102+
--cluster ${CLUSTER_NAME} \
103+
--task-definition ${APP_NAME} \
104+
--overrides "{\"containerOverrides\":[{\"name\":\"${APP_NAME}\",\"command\":[\"chamber\", \"exec\", \"${APP_ENV}\", \"--\", \"python\", \"manage.py\", \"${COMMAND}\"],\"environment\":[{\"name\":\"RUN_COMMAND_TASK\", \"value\": \"true\"}]}]}" \
105+
--launch-type FARGATE \
106+
--network-configuration "${NETWORK_CONF}")
107+
108+
echo $RUN_TASK_OUTPUT | jq "."
109+
110+
echo "Finished ${cyn}Run Task Operation${end}."
111+
112+
TASK_ARN=$( echo $RUN_TASK_OUTPUT | jq -r ".tasks | .[0] | .taskArn" )
113+
TASK_ID=$( echo $TASK_ARN | cut -d '/' -f 3 )
114+
115+
LOG_GROUP_NAME="$APP_NAME-logs"
116+
LOG_STREAM_NAME="$APP_NAME/$APP_NAME/$TASK_ID"
117+
118+
echo -n "Waiting ${red}60 seconds${end} for Task to spin up..."
119+
120+
sleep 10
121+
echo -n "."
122+
sleep 10
123+
echo -n "."
124+
sleep 10
125+
echo -n "."
126+
sleep 10
127+
echo -n "."
128+
sleep 10
129+
echo "."
130+
sleep 10
131+
132+
echo "Waiting for Task to output logs to ${mag}$LOG_GROUP_NAME / $LOG_STREAM_NAME${end}."
133+
134+
WAIT_TIME=300 # 5 Minutes
135+
WAIT_START=$( date +%s )
136+
137+
while true; do
138+
WAIT_CURRENT=$( date +%s )
139+
WAIT_DIFF=$(( $WAIT_CURRENT - $WAIT_START ))
140+
141+
if [[ $WAIT_DIFF -gt $WAIT_TIME ]]; then
142+
echo "Failed to get logs from container within $WAIT_TIME seconds. Exiting."
143+
exit 1
144+
fi
145+
146+
LOGS=$( aws logs get-log-events \
147+
--log-group-name $LOG_GROUP_NAME \
148+
--log-stream-name $LOG_STREAM_NAME 2>/dev/null )
149+
LOG_COUNT=$( echo $LOGS | jq ".events | length" )
150+
if [[ $LOG_COUNT -gt 0 ]]; then
151+
# Do a final sleep (to let the job do its thing) and then break the loop
152+
echo ""
153+
sleep 30
154+
break
155+
fi
156+
157+
# If neither of the above completed then let's keep checking the logs
158+
echo -n "${grn}.${end}"
159+
160+
sleep 5
161+
done
162+
163+
FINAL_LOGS=$( aws logs get-log-events \
164+
--log-group-name $LOG_GROUP_NAME \
165+
--log-stream-name $LOG_STREAM_NAME )
166+
167+
echo "Task Logs:"
168+
echo $FINAL_LOGS | jq ".events"
169+
170+
echo "${yel}Completed!${end}"

0 commit comments

Comments
 (0)