more style/function tweaks
This commit is contained in:
committed by
Michael Hobbs
parent
89f289b433
commit
aa2415eeb8
@@ -33,189 +33,198 @@
|
||||
# TIMEOUT=60 # Timeout after a minute
|
||||
# ATTEMPTS=10 # retry checks 10 times
|
||||
#
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/checks/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
APP="$1"; DOKKU_APP_CONTAINER_ID="$2"; DOKKU_APP_CONTAINER_TYPE="$3"; DOKKU_APP_LISTEN_PORT="$4"; DOKKU_APP_LISTEN_IP="$5"
|
||||
if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT" ]]; then
|
||||
DOKKU_APP_LISTEN_PORT=$(< "$DOKKU_ROOT/$APP/PORT")
|
||||
fi
|
||||
if [[ -z "$DOKKU_APP_LISTEN_IP" ]] && [[ -f "$DOKKU_ROOT/$APP/IP" ]]; then
|
||||
DOKKU_APP_LISTEN_IP=$(< "$DOKKU_ROOT/$APP/IP")
|
||||
fi
|
||||
if [[ -z "$DOKKU_APP_CONTAINER_ID" ]]; then
|
||||
DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") )
|
||||
DOKKU_APP_CONTAINER_ID=${DOKKU_APP_CIDS[0]}
|
||||
fi
|
||||
|
||||
|
||||
# source global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars
|
||||
eval "$(config_export global)"
|
||||
eval "$(config_export app "$APP")"
|
||||
|
||||
if [[ "$(is_app_checks_enabled "$APP")" == "false" ]];then
|
||||
dokku_log_info2_quiet "Zero downtime checks for app ($APP) have been disabled. moving on..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Wait this many seconds (default 5) for server to start before running checks.
|
||||
WAIT="${DOKKU_CHECKS_WAIT:-5}"
|
||||
# Wait this many seconds (default 30) for each response.
|
||||
TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}"
|
||||
# use this number of retries for checks
|
||||
ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}"
|
||||
|
||||
# try to copy CHECKS from container if not in APP dir & quit gracefully if it doesn't exist
|
||||
# docker cp exits with status 1 when run as non-root user when it tries to chown the file
|
||||
# after successfully copying the file. Thus, we suppress stderr.
|
||||
# ref: https://github.com/dotcloud/docker/issues/3986
|
||||
TMPDIR=$(mktemp -d /tmp/dokku_CHECKS.XXXXX)
|
||||
docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS "$TMPDIR" 2> /dev/null || true
|
||||
|
||||
FILENAME=${TMPDIR}/CHECKS
|
||||
|
||||
cleanup() {
|
||||
local desc="cleans up TMPDIR and print container output"
|
||||
rm -rf "$TMPDIR"
|
||||
dokku_log_info2_quiet "$APP container output:"
|
||||
dokku_container_log_verbose_quiet $DOKKU_APP_CONTAINER_ID
|
||||
dokku_log_info2_quiet "end $APP container output"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ ! -s "${TMPDIR}/CHECKS" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then
|
||||
# We allow custom check for web instances only
|
||||
if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then
|
||||
dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS."
|
||||
dokku_log_verbose "See http://dokku.viewdocs.io/dokku/checks-examples.md for examples"
|
||||
dokku_log_verbose "CHECKS file not found in container: Running simple container check..."
|
||||
else
|
||||
dokku_log_verbose "Non web container detected: Running default container check..."
|
||||
checks_check_deploy() {
|
||||
local desc="checks check-deploy plugin trigger"
|
||||
local trigger="checks_check_deploy"
|
||||
local APP="$1"; local DOKKU_APP_CONTAINER_ID="$2"; local DOKKU_APP_CONTAINER_TYPE="$3"; local DOKKU_APP_LISTEN_PORT="$4"; local DOKKU_APP_LISTEN_IP="$5"
|
||||
if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT" ]]; then
|
||||
local DOKKU_APP_LISTEN_PORT=$(< "$DOKKU_ROOT/$APP/PORT")
|
||||
fi
|
||||
if [[ -z "$DOKKU_APP_LISTEN_IP" ]] && [[ -f "$DOKKU_ROOT/$APP/IP" ]]; then
|
||||
local DOKKU_APP_LISTEN_IP=$(< "$DOKKU_ROOT/$APP/IP")
|
||||
fi
|
||||
if [[ -z "$DOKKU_APP_CONTAINER_ID" ]]; then
|
||||
local DOKKU_APP_CIDS=( $(get_app_container_ids "$APP") )
|
||||
local DOKKU_APP_CONTAINER_ID=${DOKKU_APP_CIDS[0]}
|
||||
fi
|
||||
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
# simple default check to see if the container stuck around
|
||||
DOKKU_DEFAULT_CHECKS_WAIT="${DOKKU_DEFAULT_CHECKS_WAIT:-10}"
|
||||
dokku_log_info1 "Waiting for $DOKKU_DEFAULT_CHECKS_WAIT seconds ..."
|
||||
sleep "$DOKKU_DEFAULT_CHECKS_WAIT"
|
||||
# source global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars
|
||||
eval "$(config_export global)"
|
||||
eval "$(config_export app "$APP")"
|
||||
|
||||
! (is_container_running $DOKKU_APP_CONTAINER_ID) && dokku_log_fail "App container failed to start!!"
|
||||
container_restarts=$(docker inspect -f "{{ .RestartCount }}" $DOKKU_APP_CONTAINER_ID)
|
||||
if [[ $container_restarts -ne 0 ]]; then
|
||||
docker stop "$DOKKU_APP_CONTAINER_ID" || true
|
||||
dokku_log_fail "App container failed to start!!"
|
||||
if [[ "$(is_app_checks_enabled "$APP")" == "false" ]];then
|
||||
dokku_log_info2_quiet "Zero downtime checks for app ($APP) have been disabled. moving on..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
dokku_log_info1 "Default container check successful!" && exit 0
|
||||
fi
|
||||
# Wait this many seconds (default 5) for server to start before running checks.
|
||||
local WAIT="${DOKKU_CHECKS_WAIT:-5}"
|
||||
# Wait this many seconds (default 30) for each response.
|
||||
local TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}"
|
||||
# use this number of retries for checks
|
||||
local ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}"
|
||||
|
||||
# Reads name/value pairs, sets the WAIT and TIMEOUT variables
|
||||
exec < "$FILENAME"
|
||||
while read -r LINE; do
|
||||
# Name/value pair
|
||||
if [[ "$LINE" =~ ^.+= ]]; then
|
||||
TRIM=${LINE%#*}
|
||||
NAME=${TRIM%=*}
|
||||
VALUE=${TRIM#*=}
|
||||
[[ "$NAME" = "WAIT" ]] && WAIT=$VALUE
|
||||
[[ "$NAME" = "TIMEOUT" ]] && TIMEOUT=$VALUE
|
||||
[[ "$NAME" = "ATTEMPTS" ]] && ATTEMPTS=$VALUE
|
||||
fi
|
||||
done
|
||||
# try to copy CHECKS from container if not in APP dir & quit gracefully if it doesn't exist
|
||||
# docker cp exits with status 1 when run as non-root user when it tries to chown the file
|
||||
# after successfully copying the file. Thus, we suppress stderr.
|
||||
# ref: https://github.com/dotcloud/docker/issues/3986
|
||||
local TMPDIR=$(mktemp -d /tmp/dokku_CHECKS.XXXXX)
|
||||
docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS "$TMPDIR" 2> /dev/null || true
|
||||
|
||||
ATTEMPT=0
|
||||
local FILENAME=${TMPDIR}/CHECKS
|
||||
|
||||
until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]]
|
||||
do
|
||||
FAILEDCHECKS=0
|
||||
ATTEMPT=$(( ATTEMPT + 1 ))
|
||||
dokku_log_info1 "Attempt $ATTEMPT/$ATTEMPTS Waiting for $WAIT seconds ..."
|
||||
sleep "$WAIT"
|
||||
cleanup() {
|
||||
local desc="cleans up TMPDIR and print container output"
|
||||
local id="$1"
|
||||
rm -rf "$TMPDIR"
|
||||
dokku_log_info2_quiet "$APP container output:"
|
||||
dokku_container_log_verbose_quiet "$id"
|
||||
dokku_log_info2_quiet "end $APP container output"
|
||||
}
|
||||
trap 'cleanup $DOKKU_APP_CONTAINER_ID' RETURN INT TERM EXIT
|
||||
|
||||
if [[ ! -s "${TMPDIR}/CHECKS" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then
|
||||
# We allow custom check for web instances only
|
||||
if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then
|
||||
dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS."
|
||||
dokku_log_verbose "See http://dokku.viewdocs.io/dokku/checks-examples.md for examples"
|
||||
dokku_log_verbose "CHECKS file not found in container: Running simple container check..."
|
||||
else
|
||||
dokku_log_verbose "Non web container detected: Running default container check..."
|
||||
fi
|
||||
|
||||
# -q do not use .curlrc (must come first)
|
||||
# --compressed Test compression handled correctly
|
||||
# --fail Fail on server errors (4xx, 5xx)
|
||||
# --location Follow redirects
|
||||
CURL_OPTIONS="-q --compressed --fail --location --max-time $TIMEOUT"
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
# Set X-Forwarded-Proto header if TLS is enabled.
|
||||
SSL="$DOKKU_ROOT/$APP/tls"; WILDCARD_SSL="$DOKKU_ROOT/tls"
|
||||
if [[ -e "$SSL/server.crt" && -e "$SSL/server.key" ]] || [[ -e "$WILDCARD_SSL/server.crt" && -e "$WILDCARD_SSL/server.key" ]]; then
|
||||
CURL_OPTIONS+=" -H X-Forwarded-Proto:https"
|
||||
# simple default check to see if the container stuck around
|
||||
local DOKKU_DEFAULT_CHECKS_WAIT="${DOKKU_DEFAULT_CHECKS_WAIT:-10}"
|
||||
dokku_log_info1 "Waiting for $DOKKU_DEFAULT_CHECKS_WAIT seconds ..."
|
||||
sleep "$DOKKU_DEFAULT_CHECKS_WAIT"
|
||||
|
||||
! (is_container_running $DOKKU_APP_CONTAINER_ID) && dokku_log_fail "App container failed to start!!"
|
||||
local container_restarts=$(docker inspect -f "{{ .RestartCount }}" $DOKKU_APP_CONTAINER_ID)
|
||||
if [[ $container_restarts -ne 0 ]]; then
|
||||
docker stop "$DOKKU_APP_CONTAINER_ID" || true
|
||||
dokku_log_fail "App container failed to start!!"
|
||||
fi
|
||||
|
||||
dokku_log_info1 "Default container check successful!" && exit 0
|
||||
fi
|
||||
|
||||
# Reads name/value pairs, sets the WAIT and TIMEOUT variables
|
||||
exec < "$FILENAME"
|
||||
while read -r CHECK_URL EXPECTED; do
|
||||
# Ignore empty lines and lines starting with #
|
||||
# shellcheck disable=SC1001
|
||||
[[ -z "$CHECK_URL" || "$CHECK_URL" =~ ^\# ]] && continue
|
||||
# Ignore if it's not a URL in a supported format
|
||||
# shellcheck disable=SC1001
|
||||
! [[ "$CHECK_URL" =~ ^(http(s)?:)?\/.* ]] && continue
|
||||
local LINE
|
||||
while read -r LINE; do
|
||||
# Name/value pair
|
||||
if [[ "$LINE" =~ ^.+= ]]; then
|
||||
local TRIM=${LINE%#*}
|
||||
local NAME=${TRIM%=*}
|
||||
local VALUE=${TRIM#*=}
|
||||
[[ "$NAME" = "WAIT" ]] && local WAIT=$VALUE
|
||||
[[ "$NAME" = "TIMEOUT" ]] && local TIMEOUT=$VALUE
|
||||
[[ "$NAME" = "ATTEMPTS" ]] && local ATTEMPTS=$VALUE
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$CHECK_URL" =~ ^https?: ]]; then
|
||||
URL_PROTOCOL=${CHECK_URL%:*}
|
||||
CHECK_URL=${CHECK_URL#*:}
|
||||
else
|
||||
URL_PROTOCOL="http"
|
||||
local ATTEMPT=0
|
||||
|
||||
until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]]
|
||||
do
|
||||
local FAILEDCHECKS=0
|
||||
local ATTEMPT=$(( ATTEMPT + 1 ))
|
||||
dokku_log_info1 "Attempt $ATTEMPT/$ATTEMPTS Waiting for $WAIT seconds ..."
|
||||
sleep "$WAIT"
|
||||
|
||||
|
||||
# -q do not use .curlrc (must come first)
|
||||
# --compressed Test compression handled correctly
|
||||
# --fail Fail on server errors (4xx, 5xx)
|
||||
# --location Follow redirects
|
||||
local CURL_OPTIONS="-q --compressed --fail --location --max-time $TIMEOUT"
|
||||
|
||||
# Set X-Forwarded-Proto header if TLS is enabled.
|
||||
local SSL="$DOKKU_ROOT/$APP/tls"; local WILDCARD_SSL="$DOKKU_ROOT/tls"
|
||||
if [[ -e "$SSL/server.crt" && -e "$SSL/server.key" ]] || [[ -e "$WILDCARD_SSL/server.crt" && -e "$WILDCARD_SSL/server.key" ]]; then
|
||||
local CURL_OPTIONS+=" -H X-Forwarded-Proto:https"
|
||||
fi
|
||||
|
||||
if [[ "$CHECK_URL" =~ ^//.+ ]]; then
|
||||
# To test a URL with specific host name, we still make request to localhost,
|
||||
# but we set Host header to $SEND_HOST.
|
||||
#
|
||||
# The pattern is
|
||||
# //SEND_HOST/PATHNAME
|
||||
UNPREFIXED=${CHECK_URL#//}
|
||||
URL_HOSTNAME=${UNPREFIXED%%/*}
|
||||
URL_PATHNAME=${UNPREFIXED#$URL_HOSTNAME}
|
||||
exec < "$FILENAME"
|
||||
local CHECK_URL
|
||||
local EXPECTED
|
||||
while read -r CHECK_URL EXPECTED; do
|
||||
# Ignore empty lines and lines starting with #
|
||||
# shellcheck disable=SC1001
|
||||
[[ -z "$CHECK_URL" || "$CHECK_URL" =~ ^\# ]] && continue
|
||||
# Ignore if it's not a URL in a supported format
|
||||
# shellcheck disable=SC1001
|
||||
! [[ "$CHECK_URL" =~ ^(http(s)?:)?\/.* ]] && continue
|
||||
|
||||
HEADERS="-H Host:$URL_HOSTNAME"
|
||||
else
|
||||
URL_HOSTNAME=localhost
|
||||
URL_PATHNAME=$CHECK_URL
|
||||
fi
|
||||
|
||||
# This URL will show up in the messages
|
||||
LOG_URL="$URL_PROTOCOL://$URL_HOSTNAME$URL_PATHNAME"
|
||||
# And how we formulate the CURL request
|
||||
CURL_ARGS="$CURL_OPTIONS $URL_PROTOCOL://$DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT$URL_PATHNAME $HEADERS"
|
||||
|
||||
dokku_log_verbose "CHECKS expected result:"
|
||||
dokku_log_verbose "$LOG_URL => \"$EXPECTED\""
|
||||
[[ $DOKKU_TRACE ]] && dokku_log_verbose "$ curl $CURL_ARGS"
|
||||
|
||||
# Capture HTTP response or CURL error message
|
||||
# shellcheck disable=SC2086
|
||||
if OUTPUT=$(curl -# $CURL_ARGS 2>&1); then
|
||||
# OUTPUT contains the HTTP response
|
||||
if [[ ! "$OUTPUT" =~ $EXPECTED ]]; then
|
||||
dokku_log_warn "$LOG_URL: expected to but did not find: \"$EXPECTED\""
|
||||
FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
|
||||
if [[ "$CHECK_URL" =~ ^https?: ]]; then
|
||||
local URL_PROTOCOL=${CHECK_URL%:*}
|
||||
local CHECK_URL=${CHECK_URL#*:}
|
||||
else
|
||||
local URL_PROTOCOL="http"
|
||||
fi
|
||||
|
||||
if [[ "$CHECK_URL" =~ ^//.+ ]]; then
|
||||
# To test a URL with specific host name, we still make request to localhost,
|
||||
# but we set Host header to $SEND_HOST.
|
||||
#
|
||||
# The pattern is
|
||||
# //SEND_HOST/PATHNAME
|
||||
local UNPREFIXED=${CHECK_URL#//}
|
||||
local URL_HOSTNAME=${UNPREFIXED%%/*}
|
||||
local URL_PATHNAME=${UNPREFIXED#$URL_HOSTNAME}
|
||||
|
||||
local HEADERS="-H Host:$URL_HOSTNAME"
|
||||
else
|
||||
local URL_HOSTNAME=localhost
|
||||
local URL_PATHNAME=$CHECK_URL
|
||||
fi
|
||||
|
||||
# This URL will show up in the messages
|
||||
local LOG_URL="$URL_PROTOCOL://$URL_HOSTNAME$URL_PATHNAME"
|
||||
# And how we formulate the CURL request
|
||||
local CURL_ARGS="$CURL_OPTIONS $URL_PROTOCOL://$DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT$URL_PATHNAME $HEADERS"
|
||||
|
||||
dokku_log_verbose "CHECKS expected result:"
|
||||
dokku_log_verbose "$LOG_URL => \"$EXPECTED\""
|
||||
[[ $DOKKU_TRACE ]] && dokku_log_verbose "$ curl $CURL_ARGS"
|
||||
|
||||
# Capture HTTP response or CURL error message
|
||||
# shellcheck disable=SC2086
|
||||
if OUTPUT=$(curl -# $CURL_ARGS 2>&1); then
|
||||
# OUTPUT contains the HTTP response
|
||||
if [[ ! "$OUTPUT" =~ $EXPECTED ]]; then
|
||||
dokku_log_warn "$LOG_URL: expected to but did not find: \"$EXPECTED\""
|
||||
local FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
|
||||
fi
|
||||
else
|
||||
# Failed to connect/no response, OUTPUT contains error message
|
||||
dokku_log_warn "$OUTPUT"
|
||||
local FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $FAILEDCHECKS -gt 0 ]]; then
|
||||
dokku_log_warn "Check attempt $ATTEMPT/$ATTEMPTS failed."
|
||||
local SUCCESS=0
|
||||
else
|
||||
# Failed to connect/no response, OUTPUT contains error message
|
||||
dokku_log_warn "$OUTPUT"
|
||||
FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
|
||||
local SUCCESS=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $FAILEDCHECKS -gt 0 ]]; then
|
||||
dokku_log_warn "Check attempt $ATTEMPT/$ATTEMPTS failed."
|
||||
SUCCESS=0
|
||||
else
|
||||
SUCCESS=1
|
||||
dokku_log_fail "Could not start due to $FAILEDCHECKS failed checks."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $FAILEDCHECKS -gt 0 ]]; then
|
||||
dokku_log_fail "Could not start due to $FAILEDCHECKS failed checks."
|
||||
exit 1
|
||||
fi
|
||||
dokku_log_info1 "All checks successful!"
|
||||
}
|
||||
|
||||
dokku_log_info1 "All checks successful!"
|
||||
checks_check_deploy "$@"
|
||||
|
||||
Reference in New Issue
Block a user