-
Notifications
You must be signed in to change notification settings - Fork 9
/
helper.sh
executable file
·380 lines (332 loc) · 11.9 KB
/
helper.sh
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
#!/bin/bash
# THIS IS RUN ON THE GUEST MACHINE
# Structure: now everything here will be a target of makefile.
# Then helper.sh will be called by the target with correct parameter for
# the shell script
# with this file you can:
# CATEGORY: DEV
# bump the version of the oms submodules and commit (currently not there)
bump_repo ()
{
git submodule foreach "git checkout stable && git pull"
git add "$(git submodule status | grep '^+' | awk '{ print $2 }')"
#if something is staged, do the following two lines
git diff --cached --quiet
#shellcheck disable=SC2181
if (( "$?" )); then
git checkout -b "bump-submodules-$(date '+%d-%m')-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 4)"
git commit -m "chore(bump): Bump version of the submodules via make bump"
fi
}
bump_single_module ()
{
cd "${1}" || { echo "no folder ${1}!" && exit 189 ; }
git checkout stable && git pull
cd ..
git add "${1}"
#if something is staged, do the following two lines
git diff --cached --quiet
#shellcheck disable=SC2181
if (( "$?" )); then
git checkout -b "bump-submodules-$(date '+%d-%m')-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 4)"
git commit -m "chore(bump): Bump version of the submodule via make bump module=${1}"
fi
}
# bump the version of the oms submodules and do not commit
bump_nocommit ()
{
git submodule foreach "git checkout stable && git pull"
}
#CATEGORY: DEPLOY
# 'create first secrets' is in start.sh
# FIRST DEPLOYMENT
init_boot ()
{
if [[ ! -f .init ]]; then
#always check if the repo is "complete"
git submodule update --init
docker network inspect OMS &>/dev/null || (echo -e "[MyAEGEE] Creating 'OMS' docker network" && docker network create OMS)
touch "${DIR}"/secrets/acme.json # to avoid making it think it's a folder
chmod 600 "${DIR}"/secrets/acme.json # Traefik doesn't let ACME challenge go through otherwise
touch "${DIR}"/gateways/docker/traefik/traefik.toml # to avoid making it think it's a folder
if [[ "${MYAEGEE_ENV}" != "development" ]]; then
envsubst < "${DIR}"/gateways/docker/traefik/traefik.toml.template > "${DIR}"/gateways/docker/traefik/traefik.toml
else
cat "${DIR}"/gateways/docker/traefik/traefik.toml.dev > "${DIR}"/gateways/docker/traefik/traefik.toml
fi
echo -e "\n[Deployment] Setting secrets\n"
bash "${DIR}"/scripts-vagrant_provision/generate_secrets.sh
echo "manual things still to do (if applicable use-case): "
echo " init cachet files (oms-status/docker/setup.sh)"
echo " init grafana config with the slack token (vim monitor/docker/config/gf-provisioning/notifiers/conf.yml)"
echo " init prometheus scraping config with the basic auth (vim monitor/docker/config/prometheus.yml)"
echo " install the pip requirement for the python extra scripts (notification): see the script in scripts-vagrant_provision"
touch .init
else
echo "already initialised"
fi
}
# change passwords (calls an external script)
# ONLY ON FIRST DEPLOYMENT
pw_changer ()
{
echo -e "\n[Deployment] Setting passwords\n"
bash "${DIR}"/scripts-server/password-setter.sh
}
# wrapper for the compose mess (ACCEPTS PARAMETERS)
compose_wrapper ()
{ #TO DO: put hostname check and do not accept the nuke and stop in production
service_string=$(printenv ENABLED_SERVICES)
# shellcheck disable=SC2206
services=( ${service_string//:/ } )
command=( docker-compose -f "${DIR}/base-docker-compose.yml" )
for s in "${services[@]}"; do
if [[ -f "${DIR}/${s}/docker/docker-compose.yml" ]]; then
if [[ "${MYAEGEE_ENV}" == "production" ]]; then
command+=( -f "${DIR}/${s}/docker/docker-compose.yml" )
else
command+=( -f "${DIR}/${s}/docker/docker-compose.yml" -f "${DIR}/${s}/docker/docker-compose.dev.yml" )
fi
else
echo -e "[MyAEGEE] WARNING: No docker file found for ${s} (full path ${DIR}/${s}/docker/docker-compose.yml)"
fi
done
command+=( "${@}" )
if ( $verbose ); then
echo -e "\n[MyAEGEE] Full command:\n${command[*]}\n"
fi
"${command[@]}"
return $?
}
# edit the env file before launching
# FIRST DEPLOYMENT
edit_env_file ()
{
EDITOR=$(env | grep EDITOR | grep -oe '[^=]*$');
export EDITOR;
if [ -z "${EDITOR}" ]; then
echo "[Deployment] no EDITOR variable, setting it to vim"
export EDITOR="vim";
fi
if ( ! ${NON_INTERACTIVE} ); then
#Ask if one wants to tweak the .env before starting it up
echo "Do you wish to edit .env file? (write the number)"
select yn in "Yes" "No"; do
case $yn in
Yes ) "${EDITOR}" "${DIR}"/.env; break;;
No ) break;;
esac
done
fi
}
# https://unix.stackexchange.com/questions/82598/how-do-i-write-a-retry-logic-in-script-to-keep-retrying-to-run-it-upto-5-times
function retry {
local n=1
local max=120
local delay=1
while true; do
# shellcheck disable=SC2015
{
docker inspect --format '{{json .State.Health.Status }}' "${1}" | grep 'healthy'
} && break || {
if [[ ${n} -lt ${max} ]]; then
((n++))
echo "Command failed. Attempt ${n}/${max}."
sleep ${delay};
else
fail "The command has failed after ${n} attempts."
fi
}
done
}
WANTEDNAME=$(head -n1 Vagrantfile | grep -oP 'machine_name = "\K[^"]+' )
HOST=$(hostname -f)
# TODO: ignore this when using --no-vagrant in start.sh
if [[ ! ${HOST} =~ ^${WANTEDNAME} ]]; then
echo "You're on ${HOST}, (the HOST) but you should be on '${WANTEDNAME}' (the GUEST). Exiting..."
exit 1
fi
# HUMAN INTERVENTION NEEDED: register in .env your services
## Export all environment variables from .env to this script in case we need them some time
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# https://stackoverflow.com/questions/19331497/set-environment-variables-from-file-of-key-value-pairs
# shellcheck disable=SC2046
export $(grep -v '^#' "${DIR}/.env" | xargs -d '\n')
if [[ "${MYAEGEE_ENV}" != "production" && "${MYAEGEE_ENV}" != "development" ]]; then
echo "Error: MYAEGEE_ENV can only be 'production' or 'development'"
exit 1
fi
HOSTNAME="$(hostname)"
export HOSTNAME
# Entry: check if the number of arguments is max 2 (one for the target one for the verbose)
init=false;
build=false;
start=false;
refresh=false;
monitor=false;
stop=false;
down=false;
restart=false;
nuke=false;
bump=false;
bumpmodules=false;
execute=false;
debug=false;
list=false;
pull=false;
wait_until_healthy=false;
verbose=false;
docker=false;
command_num=0;
declare -a arguments # = EMPTY ARRAY
if [[ "$#" -ge 1 ]]; then
while [ "$#" -gt 0 ]; do
case "$1" in
--init) init=true; ((command_num++)); shift ;;
--build) build=true; ((command_num++)); shift ;;
--start) start=true; ((command_num++)); shift ;;
--refresh) refresh=true; ((command_num++)); shift ;;
--monitor) monitor=true; ((command_num++)); shift ;;
--stop) stop=true; ((command_num++)); shift ;;
--down) down=true; ((command_num++)); shift ;;
--restart) restart=true; ((command_num++)); shift ;;
--nuke) nuke=true; ((command_num++)); shift ;;
--bump) bump=true; ((command_num++)); shift ;;
--bumpmodules) bumpmodules=true; ((command_num++)); shift ;;
--execute) execute=true; ((command_num++)); shift ;;
--debug) debug=true; ((command_num++)); shift ;;
--list) list=true; ((command_num++)); shift ;;
--pull) pull=true; ((command_num++)); shift ;;
--wait-until-healthy) wait_until_healthy=true; ((command_num++)); shift ;;
--docker) docker=true; ((command_num++)); shift ;;
-v) verbose=true; shift ;;
--) shift ; arguments+=("${@}"); break ;;
-*) echo "unknown option: ${1}" 2>&1;
echo "Usage: helper.sh {--init|--build|--start|--refresh|--monitor|--stop|--down|--restart|--nuke|--execute|--bump|--pull|--wait-until-healthy|--docker} [-v]"; exit 1;;
*) arguments+=("${1}"); shift;;
esac
done
else
echo "Too few parameters"; exit 1
echo "Usage: helper.sh {--init|--build|--start|--refresh|--monitor|--stop|--down|--restart|--nuke|--execute|--bump|--docker} [-v]"; exit 1
fi
# shellcheck disable=SC2004
if (( ${command_num} > 1 )); then
echo "Too many commands! Only one command per time"
echo "Usage: helper.sh {--init|--build|--start|--refresh|--monitor|--stop|--down|--restart|--nuke|--execute|--bump|--docker} [-v]"; exit 1
fi
# FIRST DEPLOYMENT
#TODO: implement the interactive part
if ( $init ); then
init_boot && NON_INTERACTIVE=true; edit_env_file && pw_changer
fi
# build it for the first time
# FIRST DEPLOYMENT
if ( $build ); then
compose_wrapper config > current-config.yml
if ( $verbose ); then
compose_wrapper build
else
compose_wrapper build > /dev/null
fi
exit $?
fi
#pull all, or pull single container
if ( $pull ); then
compose_wrapper pull "${arguments[@]}"
exit $?
fi
#start all, or start single container
if ( $start ); then
compose_wrapper config > current-config.yml && compose_wrapper up -d "${arguments[@]}"
exit $?
fi
#rebuild all, or rebuild single container
if ( $refresh ); then #THIS IS AN UPGRADING, i.e. CD pipeline target
compose_wrapper config > current-config.yml && compose_wrapper up -d --build "${arguments[@]}"
exit $?
fi
# execute command
#compose_wrapper exec #and additional args: the name of the container and the command
#FIXME: with the make target, arguments cannot be specified via cli
if ( $execute ); then
compose_wrapper exec "${arguments[@]}"
exit $?
fi
# cheap way to bypass all the safety introduced till now...
if ( $docker ); then
compose_wrapper "${arguments[@]}"
exit $?
fi
#
#DEV/UTILS
#
#Brings the submodules to stable and commits
if ( $bump ); then
if [ -z "${arguments[*]}" ]; then
bump_repo
else
bump_single_module "${arguments[*]}"
fi
fi
#Brings the submodules to stable, no commit. Launched by operator
if ( $bumpmodules ); then
bump_nocommit
fi
#Shows compiled docker-compose manifests
if ( $debug ); then
compose_wrapper config | tee would-be-config.yml
exit $?
fi
if ( $list ); then
compose_wrapper ps
exit $?
fi
#You can see everything, or pass a container name and monitors only that
#FIXME: with the make target, it cannot follow specific logs (passed as
# arg to make; only possible via direct invoking of ./helper.sh)
if ( $monitor ); then
compose_wrapper logs -f --tail=100 "${arguments[@]}"
exit $?
fi
if ( $wait_until_healthy ); then
CONTAINER_ID=$(compose_wrapper ps -q "${arguments[@]}")
echo "Container ID: ${CONTAINER_ID}"
retry "${CONTAINER_ID}"
fi
#
# DANGER ZONE
#
if ( $stop ); then
if [[ -n "${arguments[*]}" ]]; then #IF NOT EMPTY, continue: we only want this command to be used for a single container
compose_wrapper stop "${arguments[@]}" #TODO: improve robustness. if there is rubbish it is still not empty
exit $?
fi
echo "'Stop' must only be used with a container name"
exit 0
fi
if ( $down ); then
if [[ -n "${arguments[*]}" ]]; then #IF NOT EMPTY, continue: we only want this command to be used for a single container
compose_wrapper down "${arguments[@]}" #TODO: improve robustness. if there is rubbish it is still not empty
exit $?
fi
echo "'Down' must only be used with a container name"
exit 0
fi
if ( $restart ); then
if [[ -n "${arguments[*]}" ]]; then #IF NOT EMPTY, continue: we only want this command to be used for a single container
compose_wrapper restart "${arguments[*]}" #TODO: improve robustness. if there is rubbish it is still not empty
exit $?
fi
echo "'Restart' must only be used with a container name"
exit 0
fi
if ( $nuke ); then
if [[ "$(hostname)" == *prod* ]]; then
echo "DUUUDE you can't kill production" && exit 1;
else
compose_wrapper down -v
exit $?
fi
fi
#return 0;