Last active
April 17, 2024 21:00
-
-
Save callumgare/a763692160947c3f41a520838094b1e6 to your computer and use it in GitHub Desktop.
Creates a shell into an AWS ECS container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Enable strict mode | |
# http://redsymbol.net/articles/unofficial-bash-strict-mode/ | |
set -euo pipefail | |
IFS=$'\n\t' | |
usage () { | |
cat <<EOF | |
Usage: $(basename "$0") cluster-name [command to execute] | |
Example usage: $(basename "$0") iss4-dev ls / | |
Description: Executes a command in an ECS container. If "command to execute" | |
is not given then "bash" will be used. Use the AWS_PROFILE environment | |
variable to set the profile for AWS CLI to use. | |
To sepcify the profile as a quick one-liner you can prefix with | |
\`env AWS_PROFILE=\$NAME_OF_PROFILE_TO_USE\`. For example | |
\`env AWS_PROFILE=ds-iss-test $(basename "$0") iss3-test\`. | |
EOF | |
} | |
usage_as_additional_info () { | |
echo "" | |
echo "--------------------------------------------------------------------------------" | |
usage | |
} | |
if [[ "${1:-}" == "--help" ]]; then | |
usage | |
exit 0; | |
fi | |
if [[ -z "${1:-}" ]]; then | |
echo "Error: Missing first argument." >&2 | |
usage_as_additional_info | |
exit 1 | |
fi | |
if [[ -z "${2:-}" ]]; then | |
echo "Error: Missing second argument." >&2 | |
usage_as_additional_info | |
exit 1 | |
fi | |
CLUSTER=${1:-} | |
shift 1 | |
# Default command to "bash" if not given | |
if [ -z "${1:-}" ]; then | |
set -- "bash" | |
fi | |
COMMAND="$(printf ' %q' "$@")" | |
# Refresh aws token if previously issued token has expired | |
set +o pipefail | |
if aws configure list 2>&1 | grep -q 'run aws sso login' && true; then | |
aws sso login | |
fi | |
set -o pipefail | |
AWS_CONFIG_LIST=$(aws configure list | sed 's/^[ \t]*//') | |
CURRENT_AWS_PROFILE=$(echo "$AWS_CONFIG_LIST" | awk '$1 == "profile"' | awk '{print $2}') | |
CURRENT_AWS_ACCESS_KEY=$(echo "$AWS_CONFIG_LIST" | awk '$1 == "access_key"' | awk '{print $2}') | |
if [ "$CURRENT_AWS_ACCESS_KEY" == "<not" ]; then | |
if [ "$CURRENT_AWS_ACCESS_KEY" == "<not" ]; then | |
echo "Error: AWS CLI profile not set and no credentials not found. Please set the AWS_PROFILE environment variable used by AWS CLI." >&2 | |
else | |
echo "Error: AWS CLI profile set to \"$CURRENT_AWS_PROFILE\" but no credentials not found." >&2 | |
fi | |
exit 1 | |
fi | |
get_running_containers() { | |
TASKS_LIST_STDOUT=$(mktemp) | |
set +e # Disable exit on non-zero return since we want to do things if we get an error | |
TASKS_LIST=$(aws ecs list-tasks --cluster "$CLUSTER" --output text 2>"$TASKS_LIST_STDOUT") | |
TASKS_LIST_EXIT_CODE=$? | |
if [ "$TASKS_LIST_EXIT_CODE" != "0" ]; then | |
if grep -q "Cluster not found" < "$TASKS_LIST_STDOUT"; then | |
echo "The ECS cluster \"$CLUSTER\" not found using AWS CLI profile of \"$CURRENT_AWS_PROFILE\"" >&2 | |
exit 1 | |
else | |
cat "$TASKS_LIST_STDOUT" >&2 | |
rm "$TASKS_LIST_STDOUT" | |
exit 1 | |
fi | |
fi | |
set -e # Re-enable exit on non-zero return | |
TASK_IDS=$(awk '{print $2}' <<<"$TASKS_LIST"); | |
# Get container-level details, append task-level createdAt and taskDefinitionArnonly, then extract last segument of containerArn, taskArn and image | |
aws ecs describe-tasks --cluster "$CLUSTER" --tasks $TASK_IDS \ | |
--query "tasks[][containers[?lastStatus=='RUNNING'][name, containerArn, taskArn, image]][][]" --output text \ | |
| xargs -S "$(getconf ARG_MAX)" "-I{}" -- bash -c 'printf "%s %s %s\n" "$0" $(aws ecs describe-tasks --cluster "'"$CLUSTER"'" --tasks $(awk "{print \$3}" <<<"$0") --query "tasks[0] | [createdAt, taskDefinitionArn]" --output text)' {} \ | |
| awk -v OFS=$'\t' '{split($2,a,"/"); $2=a[4]; split($3,a,"/"); $3=a[3]; split($4,a,":"); $4=a[2]; split($6,a,":"); $6=a[7]; print $0}' | |
} | |
format_running_containers() { | |
{ | |
echo -e "Container Name\tContainer Id\t\tTask Id\tImage Tag\tCreation Date\tTask Defintion"; | |
echo "$1" | |
} | column -t -s$'\t' | |
} | |
TASKS_LIST=$(get_running_containers) | |
TASKS_COUNT=$(wc -l <<<"$TASKS_LIST" | awk '{print $1}') | |
if [ "$TASKS_COUNT" -gt "1" ]; then | |
echo "The ECS cluster \"$CLUSTER\" has more than 1 task. Which one would you like to execute the command in?"; | |
echo "" | |
TASK_IDS=$(awk '{print $2}' <<<"$TASKS_LIST"); | |
# readarray requires bash 4 and later | |
readarray -t TASKS_TABLE < <(format_running_containers "$TASKS_LIST") | |
# Print headers | |
echo " " "${TASKS_TABLE[@]:0:1}" | |
PS3=$'\nTask line number: ' | |
select TASK_LINE in "${TASKS_TABLE[@]:1}"; do | |
TASK_ID=$(awk '{print $3}' <<<"$TASK_LINE") | |
CONTAINER_NAME=$(awk '{print $1}' <<<"$TASK_LINE") | |
break; | |
done | |
elif [ "$TASKS_COUNT" == 0 ]; then | |
echo "The ECS cluster \"$CLUSTER\" has no tasks." 1>&2 | |
exit 1 | |
else | |
TASK_ID=$(awk '{print $3}' <<<"$TASKS_LIST") | |
CONTAINER_NAME=$(awk '{print $1}' <<<"$TASKS_LIST") | |
fi | |
exec aws ecs execute-command --cluster "$CLUSTER" --task "$TASK_ID" --container "$CONTAINER_NAME" --interactive --command "$COMMAND" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment