-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
check-deploy
executable file
·192 lines (163 loc) · 6.29 KB
/
check-deploy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/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.
#
# By default, checks will be retried 5 times.
# You can change these by setting WAIT, TIMEOUT and ATTEMPTS to different values, for
# example:
#
# WAIT=30 # Wait 1/2 minute
# TIMEOUT=60 # Timeout after a minute
# ATTEMPTS=10 # retry checks 10 times
#
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 global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars
[[ -f "$DOKKU_ROOT/ENV" ]] && source $DOKKU_ROOT/ENV
[[ -f "$DOKKU_ROOT/$APP/ENV" ]] && source $DOKKU_ROOT/$APP/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}"
# 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/CHECKS.XXXXX)
docker cp $DOKKU_APP_CONTAINER_ID:/app/CHECKS $TMPDIR 2> /dev/null || true
FILENAME=${TMPDIR}/CHECKS
cleanup() {
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" ]] ; 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 container check successful!" && exit 0
fi
# 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
[[ "$NAME" = "ATTEMPTS" ]] && ATTEMPTS=$VALUE
fi
done
ATTEMPT=0
until [[ $SUCCESS == 1 || $ATTEMPT -ge $ATTEMPTS ]]
do
FAILEDCHECKS=0
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
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 "CHECKS expected result:"
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_warn "$LOG_URL: expected to but did not find: \"$EXPECTED\""
FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
fi
else
# Failed to connect/no response, OUTPUT contains error message
dokku_log_warn "$OUTPUT"
FAILEDCHECKS=$(( FAILEDCHECKS + 1 ))
fi
done
if [ $FAILEDCHECKS -gt 0 ]; then
dokku_log_warn "Check attempt $ATTEMPT/$ATTEMPTS failed."
SUCCESS=0
else
SUCCESS=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!"