Last active
October 28, 2020 15:50
-
-
Save jeremypruitt/62d6beeb7a85db5f9aa9cbbc55ba81ed to your computer and use it in GitHub Desktop.
Shell script to help run Terraform in a Docker container
This file contains 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 | |
set -e | |
set -o pipefail | |
# FORMATTING ################################################################### | |
DEFAULT=`tput sgr0` | |
BOLD=`tput bold` | |
RED=`tput setaf 1` | |
GREEN=`tput setaf 2` | |
YELLOW=`tput setaf 3` | |
CYAN=`tput setaf 6` | |
# FUNCTIONS #################################################################### | |
# log - log to console with color output | |
function log { | |
if [ $# -lt 2 ]; then | |
local log_msg="$1" | |
else | |
local log_type="$1" | |
local log_msg="$2" | |
fi | |
case "$log_type" in | |
info) echo -e "\n${BOLD}${CYAN}${log_msg}${DEFAULT}" ;; | |
error) echo -e "\n${BOLD}${RED}ERROR: ${log_msg}${DEFAULT}\n" ;; | |
*) echo -e "\n${log_msg}" ;; | |
esac | |
} | |
function usage { | |
echo "Usage:" | |
echo " $(basname $0) <role> [cmd] Run AWS command as role" | |
echo " $(basname $0) <role> Generate env vars for assuming role" | |
echo "" | |
echo "Examples:" | |
echo " \$ $(basename $0) dev-deploy aws s3 ls" # Run AWS command as dev-deploy | |
echo " \$ $(basename $0) operations-admin" # Print out env vars for operations-admin | |
echo "" | |
} | |
function lookup_account { | |
ar_env=$1 | |
account=$(sed -n -e '/variable "aws_accounts"/,/}/ p' ${env_root}/variables.tf | \ | |
sed -nE -e "s/[[:space:]]*${ar_env}[[:space:]]*=[[:space:]]*\"(.*)\"/\1/p" | |
) | |
if [[ -z $account ]]; then | |
log error "Failed to lookup account for ${ar_env}" 1>&2 | |
exit 1 | |
fi | |
log info $account | |
} | |
function aws_assume_role { | |
ar_env=$1 | |
ar_role=$2 | |
if [[ $ar_env == "identity" ]]; then | |
log info "Do not need to assume_role for the ops environment" 1>&2 | |
return | |
fi | |
account=$(lookup_account $ar_env) | |
role="arn:aws:iam::${account}:role/${ar_role}" | |
aws_tmp=$(mktemp -t aws-XXXX.json) | |
aws sts assume-role --role-arn ${role} --role-session-name terraform > ${aws_tmp} | |
aws_key=$(cat ${aws_tmp} | jq -r ".Credentials.AccessKeyId") | |
aws_secret=$(cat ${aws_tmp} | jq -r ".Credentials.SecretAccessKey") | |
aws_session_token=$(cat ${aws_tmp} | jq -r ".Credentials.SessionToken") | |
aws_session_expiration=$(cat ${aws_tmp} | jq -r ".Credentials.Expiration") | |
} | |
function discover_aws_credentials { | |
aws_region=${AWS_DEFAULT_REGION:-$(aws configure get region)} | |
aws_key=${AWS_ACCESS_KEY_ID:-$(aws configure get aws_access_key_id)} | |
aws_secret=${AWS_SECRET_ACCESS_KEY:-$(aws configure get aws_secret_access_key)} | |
if [[ -z $aws_region || -z $aws_key || -z $aws_secret ]]; then | |
log error "Could not get AWS credentials" 1>&2 | |
log info "Run 'aws configure' or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_DEFAULT_REGION" 1>&2 | |
exit 1 | |
fi | |
} | |
function aws_env { | |
if [[ -n $aws_session_token ]]; then | |
export AWS_SESSION_TOKEN="$aws_session_token" | |
fi | |
export AWS_ACCESS_KEY_ID="$aws_key" | |
export AWS_SECRET_ACCESS_KEY="$aws_secret" | |
export AWS_DEFAULT_REGION="$aws_region" | |
export TF_VAR_aws_region="$aws_region" | |
} | |
# Get ARGS | |
ENV=${1} | |
ROLE=${2:-deployer} | |
ARGS=${@:3} | |
if [[ $# < 1 ]]; then | |
log error "Missing arguments" | |
usage && exit 1 | |
fi | |
unset AWS_DEFAULT_REGION \ | |
AWS_ACCESS_KEY_ID \ | |
AWS_SECRET_ACCESS_KEY \ | |
AWS_SESSION_TOKEN \ | |
AWS_SESSION_EXPIRATION | |
discover_aws_credentials | |
aws_assume_role $ENV $ROLE | |
if [[ $# > 0 ]]; then | |
AWS_DEFAULT_REGION="$aws_region" \ | |
AWS_ACCESS_KEY_ID="$aws_key" \ | |
AWS_SECRET_ACCESS_KEY="$aws_secret" \ | |
AWS_SESSION_TOKEN="$aws_session_token" \ | |
AWS_SESSION_EXPIRATION="$aws_session_expiration" \ | |
"$@" | |
else | |
echo export AWS_DEFAULT_REGION=\"$aws_region\" | |
echo export AWS_ACCESS_KEY_ID=\"$aws_key\" | |
echo export AWS_SECRET_ACCESS_KEY=\"$aws_secret\" | |
echo export AWS_SESSION_TOKEN=\"$aws_session_token\" | |
echo export AWS_SESSION_EXPIRATION=\"$aws_session_expiration\" | |
fi |
This file contains 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
#!/bin/bash | |
set -e | |
set -o pipefail | |
# FORMATTING ################################################################### | |
DEFAULT=`tput sgr0` | |
BOLD=`tput bold` | |
RED=`tput setaf 1` | |
GREEN=`tput setaf 2` | |
YELLOW=`tput setaf 3` | |
CYAN=`tput setaf 6` | |
# FUNCTIONS #################################################################### | |
# log - log to console with color output | |
function log { | |
if [ $# -lt 2 ]; then | |
local log_msg="$1" | |
else | |
local log_type="$1" | |
local log_msg="$2" | |
fi | |
case "$log_type" in | |
info) echo -e "\n${BOLD}${CYAN}${log_msg}${DEFAULT}" ;; | |
error) echo -e "\n${BOLD}${RED}ERROR: ${log_msg}${DEFAULT}\n" ;; | |
*) echo -e "\n${log_msg}" ;; | |
esac | |
} | |
function usage { | |
echo "Usage:" | |
echo " <env> required: <env> can be 'dev' or 'prod'" | |
echo "" | |
echo " $0 <env> ping-hosts Ping all hosts in inventory" | |
echo "" | |
echo " $0 tasks List all tasks" | |
echo " $0 environments List all environments" | |
echo "" | |
echo " $0 help Show this help output" | |
echo "" | |
} | |
# list_all_tasks - Return a space separated list of all cases in the $TASK | |
# case statement of this file. Used for shell autocompletion. | |
# 1) Grab just the $TASK case statement block from the runner.sh | |
# 2) Pull just the "case" lines | |
# 3) sed removes the trailing parentheses | |
function list_all_tasks() { | |
task_list=$( \ | |
sed -n -e '/^case $TASK in/{' -e ':a' -e 'n' -e '/^esac$/b' -e 'p' -e 'ba' -e '}' runner.sh \ | |
| grep '^ [-a-zA-Z0-9_]*)$' \ | |
| sed -e 's/)//g' \ | |
) | |
log info "TASKS:" | |
for task in $task_list; do | |
echo $task | grep "^help$" >/dev/null && continue | |
echo " $0 <ENV> $task [ARGS]" | |
done | |
} | |
# Return a space separated list of all environments. An environment is any | |
# directory that starts with `env-`. | |
function list_all_environments() { | |
log info "ENVIRONMENTS:" | |
for env in $(ls -1d env-*); do echo " $0 $env <TASK> [ARGS]"; done | |
} | |
# MAIN ######################################################################### | |
# Get ARGS | |
ENV=${1} | |
TASK=${2} | |
ARGS=${@:3} | |
if [ "$ENV" = 'dev' ] || [ "$ENV" = 'prod' ]; then | |
pushd env-$ENV | |
elif [ "$ENV" = 'tasks' ]; then | |
list_all_tasks && exit 0 | |
elif [ "$ENV" = 'environments' ] || [ "$ENV" = 'envs' ]; then | |
list_all_environments && exit 0 | |
else | |
log error "Missing proper <env>: (prod or dev)" | |
usage && exit 1 | |
fi | |
PWD=`pwd` | |
# Terraform | |
TF_IMAGE="hashicorp/terraform:latest" | |
MOUNT_TF_MODULES="-v $(pwd)/../modules:/modules:ro" | |
# AWS | |
ENV_VARS="-e AWS_PROFILE=${AWS_PROFILE}" | |
MOUNT_AWS_CREDS="-v ${HOME}/.aws/credentials:/root/.aws/credentials:ro" | |
MOUNT_AWS_CONFIG="-v ${HOME}/.aws/config:/root/.aws/config:ro" | |
# Run Docker interactively | |
DOCKER_CMD="docker" | |
DOCKER_RUN="${DOCKER_CMD} run" | |
DOCKER_RUN_IT="${DOCKER_RUN} -it" | |
MOUNT_DATA="-v $(pwd):/data -w /data" | |
case $TASK in | |
init) | |
TF_CMD=init | |
;; | |
plan) | |
TF_CMD=plan | |
;; | |
apply) | |
TF_CMD=apply | |
;; | |
refresh) | |
TF_CMD=refresh | |
;; | |
destroy) | |
TF_CMD=destroy | |
;; | |
import) | |
TF_CMD=import | |
;; | |
graph) | |
TF_CMD=graph | |
;; | |
console) | |
TF_CMD=console | |
;; | |
version) | |
TF_CMD=--version | |
;; | |
help) | |
usage | |
exit 0 | |
;; | |
*) | |
usage | |
exit 1 | |
;; | |
esac | |
log info " --> Running terraform $TF_CMD in $ENV" | |
log info " --> $DOCKER_RUN_IT $MOUNT_AWS_CREDS $MOUNT_AWS_CONFIG $MOUNT_DATA $TF_IMAGE $TF_CMD $ARGS" | |
$DOCKER_RUN_IT $MOUNT_AWS_CREDS \ | |
$MOUNT_AWS_CONFIG \ | |
$MOUNT_DATA \ | |
$MOUNT_TF_MODULES \ | |
$ENV_VARS \ | |
$TF_IMAGE \ | |
$TF_CMD $ARGS \ | |
&& log info "DONE" \ | |
|| log error "Problem running docker command" | |
# Return to original directory | |
popd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment