psu/psu
Juan Carlos Mejías Rodríguez e873d4a9d8 Add debug mode
2018-11-24 15:09:14 -05:00

281 lines
8.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#######################################
# Check a parameter has been provided #
# Arguments: #
# $1 Argument value #
# $2 Argument name #
# $3 Argument envvar #
# $4 Argument flag #
#######################################
check_argument () {
local argument_value=$1
local argument_name=$2
local argument_envvar=$3
local argument_flag=$4
if [ -z "$argument_value" ]; then
echo "Error: Missing argument \"$argument_name\"."
echo "Try setting \"$argument_envvar\" environment variable or using the \"-$argument_flag\" flag."
exit 1
fi
}
###########################################
# Checks for error exit codes from httpie #
# Arguments: #
# $1 Httpie exit code #
# $2 Response returned by Portainer API #
###########################################
check_for_errors () {
local exit_code=$1
local response=$2
if [ $exit_code -ne 0 ]; then
case $exit_code in
2) echo 'Request timed out!' ;;
3) echo 'Unexpected HTTP 3xx Redirection!' ;;
4) echo 'HTTP 4xx Client Error!' && echo $response ;;
5) echo 'HTTP 5xx Server Error!' && echo $response ;;
6) echo 'Exceeded --max-redirects=<n> redirects!' ;;
*) echo 'Unholy Error!' ;;
esac
exit 1
fi
}
###########################################
# Print message if verbose mode is active #
# Arguments: #
# $1 Message #
###########################################
echo_verbose () {
local message=$1
if [ $VERBOSE_MODE == "true" ]; then
echo $message
fi
}
#########################################
# Print message if debug mode is active #
# Arguments: #
# $1 Message #
#########################################
echo_debug () {
local message=$1
if [ $DEBUG_MODE == "true" ]; then
echo $message
fi
}
deploy () {
STACK_YAML_PATH=$DOCKER_COMPOSE_FILE
STACK_YAML_CONTENT=$(cat "$STACK_YAML_PATH")
# Escape carriage returns
STACK_YAML_CONTENT="${STACK_YAML_CONTENT//$'\r'/''}"
# Escape double quotes
STACK_YAML_CONTENT="${STACK_YAML_CONTENT//$'"'/'\"'}"
# Escape newlines
STACK_YAML_CONTENT="${STACK_YAML_CONTENT//$'\n'/'\n'}"
if [ -z "$STACK" ]; then
echo_verbose "Result: Stack $STACK_NAME not found."
echo_verbose "Getting swarm cluster (if any)..."
DOCKER_INFO=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
"$PORTAINER_URL/api/endpoints/$PORTAINER_ENDPOINT/docker/info" \
"Authorization: Bearer $AUTH_TOKEN")
check_for_errors $? "$DOCKER_INFO"
echo_debug "Docker info -> $DOCKER_INFO"
SWARM_ID=$(echo $DOCKER_INFO | jq -r ".Swarm.Cluster.ID // empty")
echo_debug "Swarm ID -> $SWARM_ID"
echo_verbose "Creating stack $STACK_NAME..."
if [ -z "$SWARM_ID" ];then
DATA_PREFIX="{\"Name\":\"$STACK_NAME\",\"StackFileContent\":\""
DATA_SUFFIX="\"}"
echo "$DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX" > json.tmp
echo_debug "Stack JSON -> $DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX"
CREATE=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
--timeout=300 \
"$PORTAINER_URL/api/stacks" \
"Authorization: Bearer $AUTH_TOKEN" \
type==2 \
method==string \
endpointId==$PORTAINER_ENDPOINT \
@json.tmp)
echo_debug "Create action response -> $CREATE"
else
DATA_PREFIX="{\"Name\":\"$STACK_NAME\",\"SwarmID\":\"$SWARM_ID\",\"StackFileContent\":\""
DATA_SUFFIX="\"}"
echo "$DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX" > json.tmp
echo_debug "Stack JSON -> $DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX"
CREATE=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
--timeout=300 \
"$PORTAINER_URL/api/stacks" \
"Authorization: Bearer $AUTH_TOKEN" \
type==1 \
method==string \
endpointId==$PORTAINER_ENDPOINT \
@json.tmp)
echo_debug "Create action response -> $CREATE"
fi
check_for_errors $? "$CREATE"
rm json.tmp
else
echo_verbose "Result: Stack $STACK_NAME found."
STACK_ID="$(echo "$STACK" | jq -j ".Id")"
STACK_ENV_VARS="$(echo -n "$STACK"| jq ".Env" -jc)"
DATA_PREFIX="{\"Id\":\"$STACK_ID\",\"StackFileContent\":\""
DATA_SUFFIX="\",\"Env\":"$STACK_ENV_VARS",\"Prune\":$PORTAINER_PRUNE}"
echo "$DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX" > json.tmp
echo_debug "Stack JSON -> $DATA_PREFIX$STACK_YAML_CONTENT$DATA_SUFFIX"
echo_verbose "Updating stack $STACK_NAME..."
UPDATE=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
--timeout=300 \
PUT "$PORTAINER_URL/api/stacks/$STACK_ID" \
"Authorization: Bearer $AUTH_TOKEN" \
endpointId==$PORTAINER_ENDPOINT \
@json.tmp)
echo_debug "Update action response -> $UPDATE"
check_for_errors $? "$UPDATE"
rm json.tmp
fi
echo_verbose "Done"
}
undeploy () {
if [ -z "$STACK" ]; then
echo "Result: Stack $STACK_NAME not found."
exit 1
fi
echo_verbose "Result: Stack $STACK_NAME found."
STACK_ID="$(echo "$STACK" | jq -j ".Id")"
echo_debug "Stack ID -> $STACK_ID"
echo_verbose "Deleting stack $STACK_NAME..."
DELETE=$(http \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
DELETE "$PORTAINER_URL/api/stacks/$STACK_ID" \
"Authorization: Bearer $AUTH_TOKEN")
echo_debug "Delete action response -> $UPDATE"
check_for_errors $? "$DELETE"
echo_verbose "Done"
}
# Set arguments through envvars
ACTION=${ACTION}
PORTAINER_USER=${PORTAINER_USER}
PORTAINER_PASSWORD=${PORTAINER_PASSWORD}
PORTAINER_URL=${PORTAINER_URL}
PORTAINER_STACK_NAME=${PORTAINER_STACK_NAME}
DOCKER_COMPOSE_FILE=${DOCKER_COMPOSE_FILE}
PORTAINER_ENDPOINT=${PORTAINER_ENDPOINT:-"1"}
PORTAINER_PRUNE=${PORTAINER_PRUNE:-"false"}
HTTPIE_VERIFY_SSL=${HTTPIE_VERIFY_SSL:-"yes"}
VERBOSE_MODE=${VERBOSE_MODE:-"false"}
DEBUG_MODE=${DEBUG_MODE:-"false"}
# Set arguments through flags
while getopts a:u:p:l:n:c:e:rsvd option; do
case "${option}" in
a) ACTION=${OPTARG} ;;
u) PORTAINER_USER=${OPTARG} ;;
p) PORTAINER_PASSWORD=${OPTARG} ;;
l) PORTAINER_URL=${OPTARG} ;;
n) PORTAINER_STACK_NAME=${OPTARG} ;;
c) DOCKER_COMPOSE_FILE=${OPTARG} ;;
e) PORTAINER_ENDPOINT=${OPTARG} ;;
r) PORTAINER_PRUNE="true" ;;
s) HTTPIE_VERIFY_SSL="no" ;;
v) VERBOSE_MODE="true" ;;
d) DEBUG_MODE="true" ;;
esac
done
# Print config
echo_debug "ACTION -> $ACTION"
echo_debug "PORTAINER_USER -> $PORTAINER_USER"
echo_debug "PORTAINER_PASSWORD -> $PORTAINER_PASSWORD"
echo_debug "PORTAINER_URL -> $PORTAINER_URL"
echo_debug "PORTAINER_STACK_NAME -> $PORTAINER_STACK_NAME"
echo_debug "DOCKER_COMPOSE_FILE -> $DOCKER_COMPOSE_FILE"
echo_debug "PORTAINER_ENDPOINT -> $PORTAINER_ENDPOINT"
echo_debug "PORTAINER_PRUNE -> $PORTAINER_PRUNE"
echo_debug "HTTPIE_VERIFY_SSL -> $HTTPIE_VERIFY_SSL"
echo_debug "VERBOSE_MODE -> $VERBOSE_MODE"
echo_debug "DEBUG_MODE -> $DEBUG_MODE"
# Check required arguments have been provided
check_argument "$ACTION" "action" "ACTION" "a"
check_argument "$PORTAINER_USER" "portainer user" "PORTAINER_USER" "u"
check_argument "$PORTAINER_PASSWORD" "portainer password" "PORTAINER_PASSWORD" "p"
check_argument "$PORTAINER_URL" "portainer url" "PORTAINER_URL" "l"
check_argument "$PORTAINER_STACK_NAME" "portainer stack name" "PORTAINER_STACK_NAME" "n"
STACK_NAME=$PORTAINER_STACK_NAME
echo_verbose "Getting auth token..."
AUTH_TOKEN=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
$PORTAINER_URL/api/auth \
username=$PORTAINER_USER \
password=$PORTAINER_PASSWORD)
echo_debug "Get auth token response -> $AUTH_TOKEN"
check_for_errors $? "$AUTH_TOKEN"
AUTH_TOKEN=$(echo $AUTH_TOKEN | jq -r .jwt)
echo_debug "Auth token -> $AUTH_TOKEN"
echo_verbose "Done"
echo_verbose "Getting stack $STACK_NAME..."
STACKS=$(http \
--check-status \
--ignore-stdin \
--verify=$HTTPIE_VERIFY_SSL \
"$PORTAINER_URL/api/stacks" \
"Authorization: Bearer $AUTH_TOKEN")
echo_debug "Get stacks response -> $STACKS"
check_for_errors $? "$STACKS"
STACK=$(echo "$STACKS" \
| jq --arg STACK_NAME "$STACK_NAME" -jc '.[] | select(.Name == $STACK_NAME)')
echo_debug "Stack -> $STACK"
if [ $ACTION == "deploy" ]; then
check_argument "$DOCKER_COMPOSE_FILE" "docker compose file" "DOCKER_COMPOSE_FILE" "c"
deploy
exit 0
fi
if [ $ACTION == "undeploy" ]; then
undeploy
exit 0
fi
echo "Error: Unknown action \"$ACTION\"."
exit 1