mirror of
https://github.com/dokku/dokku.git
synced 2025-12-29 00:25:08 +01:00
173 lines
5.4 KiB
Bash
Executable File
173 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Hook to check server against list of checks specified in CHECKS file.
|
|
#
|
|
# The CHECKS file may contain empty lines, comments (lines starting with #),
|
|
# settings (NAME=VALUE) and check instructions.
|
|
#
|
|
# The format of a check instruction is a path, optionally followed by the
|
|
# expected content. For example:
|
|
#
|
|
# / My Amazing App
|
|
# /stylesheets/index.css .body
|
|
# /scripts/index.js $(function()
|
|
# /images/logo.png
|
|
#
|
|
# To check an application that supports multiple hostnames, use relative URLs
|
|
# that include the hostname, for example:
|
|
#
|
|
# //admin.example.com Admin Dashboard
|
|
# //static.example.com/logo.png
|
|
#
|
|
# You can also specify the protocol to explicitly check HTTPS requests.
|
|
#
|
|
# The default behavior is to wait for 5 seconds before running the first check,
|
|
# and timeout each check to 30 minutes.
|
|
#
|
|
# You can change these by setting WAIT and TIMEOUT to different values, for
|
|
# example:
|
|
#
|
|
# WAIT=30 # Wait 1/2 minute
|
|
# TIMEOUT=60 # Timeout after a minute
|
|
#
|
|
|
|
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
|
source "$(dirname $0)/../common/functions"
|
|
|
|
APP="$1"; DOKKU_APP_LISTEN_PORT="$2"; DOKKU_APP_LISTEN_IP="$3"; DOKKU_APP_CONTAINER_ID="$4"
|
|
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" ]] && [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]]; then
|
|
DOKKU_APP_CONTAINER_ID=$(< "$DOKKU_ROOT/$APP/CONTAINER")
|
|
fi
|
|
|
|
|
|
# source in app env to get DOKKU_CHECKS_WAIT and any other necessary vars
|
|
[[ -f "$DOKKU_ROOT/ENV" ]] && source $DOKKU_ROOT/ENV
|
|
|
|
# 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}"
|
|
|
|
|
|
# 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/CHECKS.XXXXX)
|
|
docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS $TMPDIR 2> /dev/null || true
|
|
if [[ ! -s "${TMPDIR}/CHECKS" ]] ; then
|
|
dokku_log_verbose "CHECKS file not found in container: running simple container check..."
|
|
rm -rf $TMPDIR
|
|
|
|
# simple default check to see if the container stuck around
|
|
# for more thorough checks, create a CHECKS file
|
|
DOKKU_DEFAULT_WAIT=$((WAIT+TIMEOUT))
|
|
dokku_log_info1 "Waiting for $DOKKU_DEFAULT_WAIT seconds ..."
|
|
sleep $DOKKU_DEFAULT_WAIT
|
|
|
|
docker ps -q --no-trunc | grep -q "$DOKKU_APP_CONTAINER_ID" || dokku_log_fail "App container failed to start!!"
|
|
dokku_log_info1 "Default check successful!" && exit 0
|
|
fi
|
|
|
|
|
|
FILENAME=${TMPDIR}/CHECKS
|
|
|
|
cleanup() {
|
|
rm -rf $TMPDIR
|
|
if [[ $DOKKU_TRACE ]] ; then
|
|
dokku_log_info1 "Begin server log ..."
|
|
docker logs $DOKKU_APP_CONTAINER_ID
|
|
dokku_log_info1 "End server log\n"
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
|
|
# Reads name/value pairs, sets the WAIT and TIMEOUT variables
|
|
exec < "$FILENAME"
|
|
while read LINE ; do
|
|
# Name/value pair
|
|
if [[ "$LINE" =~ ^.+= ]] ; then
|
|
TRIM=${LINE%#*}
|
|
NAME=${TRIM%=*}
|
|
VALUE=${TRIM#*=}
|
|
[[ "$NAME" = "WAIT" ]] && WAIT=$VALUE
|
|
[[ "$NAME" = "TIMEOUT" ]] && TIMEOUT=$VALUE
|
|
fi
|
|
done
|
|
|
|
|
|
dokku_log_info1 "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
|
|
CURL_OPTIONS="-q --compressed --fail --location --max-time $TIMEOUT"
|
|
|
|
|
|
exec < "$FILENAME"
|
|
while read CHECK_URL EXPECTED ; do
|
|
# Ignore empty lines and lines starting with #
|
|
# shellcheck disable=SC1001
|
|
[[ -z "$CHECK_URL" || "$CHECK_URL" =~ ^\# ]] && continue
|
|
# Ignore variables
|
|
[[ "$CHECK_URL" =~ ^.+= ]] && continue
|
|
|
|
if [[ "$CHECK_URL" =~ ^https?: ]] ; then
|
|
URL_PROTOCOL=${CHECK_URL%:*}
|
|
CHECK_URL=${CHECK_URL#*:}
|
|
else
|
|
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
|
|
UNPREFIXED=${CHECK_URL#//}
|
|
URL_HOSTNAME=${UNPREFIXED%%/*}
|
|
URL_PATHNAME=${UNPREFIXED#$URL_HOSTNAME}
|
|
|
|
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 "$LOG_URL => \"$EXPECTED\""
|
|
[[ $DOKKU_TRACE ]] && dokku_log_verbose "$ curl $CURL_ARGS"
|
|
|
|
# Capture HTTP response or CURL error message
|
|
if OUTPUT=$(curl -# $CURL_ARGS 2>&1) ; then
|
|
# OUTPUT contains the HTTP response
|
|
if [[ ! "$OUTPUT" =~ $EXPECTED ]] ; then
|
|
dokku_log_fail "$LOG_URL: expected to but did not find: \"$EXPECTED\""
|
|
exit 1
|
|
fi
|
|
else
|
|
# Failed to connect/no response, OUTPUT contains error message
|
|
dokku_log_fail "$OUTPUT"
|
|
exit 2
|
|
fi
|
|
done
|
|
|
|
|
|
dokku_log_info1 "All checks successful!"
|
|
|