Update base image to cover latest security fixes
[discourse_docker.git] / launcher
CommitLineData
7dafe1c0 1#!/usr/bin/env bash
7e738616 2
5cb39519 3usage () {
c2d3ee4a 4 echo "Usage: launcher COMMAND CONFIG [--skip-prereqs] [--docker-args STRING]"
5cb39519 5 echo "Commands:"
1ec142a1
GXT
6 echo " start: Start/initialize a container"
7 echo " stop: Stop a running container"
8 echo " restart: Restart a container"
9 echo " destroy: Stop and remove a container"
10 echo " enter: Open a shell to run commands inside the container"
11 echo " logs: View the Docker logs for a container"
12 echo " bootstrap: Bootstrap a container for the config based on a template"
2791af60 13 echo " run: Run the given command with the config in the context of the last bootstrapped image"
1ec142a1
GXT
14 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
15 echo " cleanup: Remove all containers that have stopped for > 24 hours"
7d49dbe7 16 echo " start-cmd: Generate docker command used to start container"
5cb39519
JA
17 echo
18 echo "Options:"
1f656469 19 echo " --skip-prereqs Don't check launcher prerequisites"
1f656469 20 echo " --docker-args Extra arguments to pass when running docker"
cad2919f 21 echo " --skip-mac-address Don't assign a mac address"
c786ffcd 22 echo " --run-image Override the image used for running the container"
5cb39519
JA
23 exit 1
24}
25
13b0817c
MB
26# for potential re-exec later
27SAVED_ARGV=("$@")
28
7e738616
S
29command=$1
30config=$2
47890a9a
SG
31
32# user_args_argv is assigned once when the argument vector is parsed.
33user_args_argv=""
34# user_args is mutable: its value may change when templates are parsed.
35# Superset of user_args_argv.
65573a0e 36user_args=""
47890a9a 37
c786ffcd 38user_run_image=""
87c4f221 39
1ec142a1
GXT
40if [[ $command == "run" ]]; then
41 run_command=$3
42fi
43
1f656469 44while [ ${#} -gt 0 ]; do
65573a0e 45 case "${1}" in
19e3a6c0
S
46 --debug)
47 DEBUG="1"
48 ;;
1f656469 49 --skip-prereqs)
4f36bb43 50 SKIP_PREREQS="1"
1f656469 51 ;;
cad2919f
GXT
52 --skip-mac-address)
53 SKIP_MAC_ADDRESS="1"
54 ;;
1f656469 55 --docker-args)
47890a9a
SG
56 user_args_argv="$2"
57 user_args="$user_args_argv"
1f656469
GXT
58 shift
59 ;;
c786ffcd
GXT
60 --run-image)
61 user_run_image="$2"
62 shift
63 ;;
1f656469
GXT
64 esac
65
66 shift 1
67done
55d17203 68
ea4428d7 69if [ -z "$command" -o -z "$config" -a "$command" != "cleanup" ]; then
f80e6a37
GXT
70 usage
71 exit 1
72fi
73
87756d6d 74# Docker doesn't like uppercase characters, spaces or special characters, catch it now before we build everything out and then find out
abcf2a97 75re='[[:upper:]/ !@#$%^&*()+~`=]'
87756d6d
EH
76if [[ $config =~ $re ]];
77 then
8877f99e 78 echo
abcf2a97 79 echo "ERROR: Config name '$config' must not contain upper case characters, spaces or special characters. Correct config name and rerun $0."
87756d6d
EH
80 echo
81 exit 1
82fi
83
7936ebaa 84cd "$(dirname "$0")"
55d17203 85
0998a7c8 86docker_min_version='17.03.1'
ddf8c54c 87docker_rec_version='17.06.2'
6828238a
JP
88git_min_version='1.8.0'
89git_rec_version='1.8.0'
60668406 90
8dea575c 91config_file=containers/"$config".yml
5201a40c 92cidbootstrap=cids/"$config"_bootstrap.cid
5efded6a 93local_discourse=local_discourse
1b97cb19 94image="discourse/base:2.0.20201004-2310"
9eeb324e 95docker_path=`which docker.io 2> /dev/null || which docker`
6828238a 96git_path=`which git`
8877f99e 97
e0fd1f5b
TB
98if [ "${SUPERVISED}" = "true" ]; then
99 restart_policy="--restart=no"
100 attach_on_start="-a"
101 attach_on_run="-a stdout -a stderr"
102else
103 attach_on_run="-d"
104fi
105
f2a3edee
AY
106if [ -n "$DOCKER_HOST" ]; then
107 docker_ip=`sed -e 's/^tcp:\/\/\(.*\):.*$/\1/' <<< "$DOCKER_HOST"`
108elif [ -x "$(which ip 2>/dev/null)" ]; then
813fef38 109 docker_ip=`ip addr show docker0 | \
03bb0735
LG
110 grep 'inet ' | \
111 awk '{ split($2,a,"/"); print a[1] }';`
112else
813fef38 113 docker_ip=`ifconfig | \
03bb0735
LG
114 grep -B1 "inet addr" | \
115 awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
116 grep docker0 | \
117 awk -F: '{ print $3 }';`
118fi
80c11be3 119
7a96c86d 120# From https://stackoverflow.com/a/44660519/702738
60668406 121compare_version() {
7a96c86d
RSS
122 if [[ $1 == $2 ]]; then
123 return 1
124 fi
125 local IFS=.
126 local i a=(${1%%[^0-9.]*}) b=(${2%%[^0-9.]*})
127 local arem=${1#${1%%[^0-9.]*}} brem=${2#${2%%[^0-9.]*}}
128 for ((i=0; i<${#a[@]} || i<${#b[@]}; i++)); do
129 if ((10#${a[i]:-0} < 10#${b[i]:-0})); then
60668406 130 return 1
7a96c86d
RSS
131 elif ((10#${a[i]:-0} > 10#${b[i]:-0})); then
132 return 0
60668406
DP
133 fi
134 done
7a96c86d
RSS
135 if [ "$arem" '<' "$brem" ]; then
136 return 1
137 elif [ "$arem" '>' "$brem" ]; then
138 return 0
139 fi
140 return 1
60668406
DP
141}
142
665468eb
JA
143
144install_docker() {
c2d3ee4a 145 echo "Docker is not installed, you will need to install Docker in order to run Launcher"
bf6d49b5 146 echo "See https://docs.docker.com/installation/"
665468eb
JA
147 exit 1
148}
149
a554d3dc
KY
150pull_image() {
151 # Add a single retry to work around dockerhub TLS errors
94360a4e 152 $docker_path pull $image || $docker_path pull $image
a554d3dc
KY
153}
154
87c4f221 155check_prereqs() {
794e44d5
GXT
156
157 if [ -z $docker_path ]; then
665468eb
JA
158 install_docker
159 fi
a3e18d95 160
e741295a 161 # 1. docker daemon running?
30835a52
S
162 # we send stderr to /dev/null cause we don't care about warnings,
163 # it usually complains about swap which does not matter
164 test=`$docker_path info 2> /dev/null`
e741295a
MB
165 if [[ $? -ne 0 ]] ; then
166 echo "Cannot connect to the docker daemon - verify it is running and you have access"
167 exit 1
168 fi
169
90287f8e 170 # 2. running an approved storage driver?
98c5fec4 171 if ! $docker_path info 2> /dev/null | egrep -q 'Storage Driver: (aufs|zfs|overlay2)$'; then
90287f8e 172 echo "Your Docker installation is not using a supported storage driver. If we were to proceed you may have a broken install."
76ef2cbb 173 echo "overlay2 is the recommended storage driver, although zfs and aufs may work as well."
90287f8e
MP
174 echo "Other storage drivers are known to be problematic."
175 echo "You can tell what filesystem you are using by running \"docker info\" and looking at the 'Storage Driver' line."
5dfdf9a3 176 echo
90287f8e
MP
177 echo "If you wish to continue anyway using your existing unsupported storage driver,"
178 echo "read the source code of launcher and figure out how to bypass this check."
48f22d14 179 exit 1
a3e18d95
S
180 fi
181
60668406
DP
182 # 3. running recommended docker version
183 test=($($docker_path --version)) # Get docker version string
184 test=${test[2]//,/} # Get version alone and strip comma if exists
a3e18d95 185
87c4f221 186 # At least minimum docker version
cf00fce0 187 if compare_version "${docker_min_version}" "${test}"; then
60668406 188 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
a3e18d95
S
189 exit 1
190 fi
191
87c4f221 192 # Recommend newer docker version
60668406
DP
193 if compare_version "${docker_rec_version}" "${test}"; then
194 echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
195 fi
196
405948ee
S
197 # 4. discourse docker image is downloaded
198 test=`$docker_path images | awk '{print $1 ":" $2 }' | grep "$image"`
199
200 if [ -z "$test" ]; then
201 echo
202 echo "WARNING: We are about to start downloading the Discourse base image"
203 echo "This process may take anywhere between a few minutes to an hour, depending on your network speed"
204 echo
205 echo "Please be patient"
206 echo
a554d3dc
KY
207
208 pull_image
405948ee 209 fi
405948ee 210
6828238a
JP
211 # 5. running recommended git version
212 test=($($git_path --version)) # Get git version string
213 test=${test[2]//,/} # Get version alone and strip comma if exists
214
215 # At least minimum version
216 if compare_version "${git_min_version}" "${test}"; then
217 echo "ERROR: Git version ${test} not supported, please upgrade to at least ${git_min_version}, or recommended ${git_rec_version}"
218 exit 1
219 fi
220
221 # Recommend best version
222 if compare_version "${git_rec_version}" "${test}"; then
223 echo "WARNING: Git version ${test} deprecated, recommend upgrade to ${git_rec_version} or newer."
224 fi
225
226 # 6. able to attach stderr / out / tty
e02c1511 227 test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
a3e18d95
S
228 if [[ "$test" =~ "working" ]] ; then : ; else
229 echo "Your Docker installation is not working correctly"
230 echo
231 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
232 exit 1
233 fi
4770834b 234
49b2fcc4 235 # 7. enough space for the bootstrap on docker folder
8cdc533d
RSS
236 folder=`$docker_path info --format '{{.DockerRootDir}}'`
237 safe_folder=${folder:-/var/lib/docker}
49b2fcc4
RSS
238 test=$(($(stat -f --format="%a*%S" $safe_folder)/1024**3 < 5))
239 if [[ $test -ne 0 ]] ; then
da095c30
RSS
240 echo "You have less than 5GB of free space on the disk where $safe_folder is located. You will need more space to continue"
241 df -h $safe_folder
49b2fcc4 242 echo
623f1073
MB
243 if tty >/dev/null; then
244 read -p "Would you like to attempt to recover space by cleaning docker images and containers in the system?(y/N)" -n 1 -r
245 echo
246 if [[ $REPLY =~ ^[Yy]$ ]]
247 then
70aaf454
SG
248 $docker_path container prune --force --filter until=1h >/dev/null
249 $docker_path image prune --all --force --filter until=1h >/dev/null
623f1073
MB
250 echo "If the cleanup was successful, you may try again now"
251 fi
49b2fcc4
RSS
252 fi
253 exit 1
254 fi
6e784be6
MP
255}
256
6828238a 257
cf3dd6f2 258if [ -z "$SKIP_PREREQS" ] && [ "$command" != "cleanup" ]; then
87c4f221 259 check_prereqs
55d17203 260fi
a3e18d95 261
60f9f04c
S
262host_run() {
263 read -r -d '' env_ruby << 'RUBY'
264 require 'yaml'
265
266 input = STDIN.readlines.join
267 yaml = YAML.load(input)
268
269 if host_run = yaml['host_run']
270 params = yaml['params'] || {}
271 host_run.each do |run|
272 params.each do |k,v|
273 run = run.gsub("$#{k}", v)
274 end
275 STDOUT.write "#{run}--SEP--"
276 end
277 end
278RUBY
279
e02c1511 280 host_run=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e "$env_ruby"`
60f9f04c
S
281
282 while [ "$host_run" ] ; do
283 iter=${host_run%%--SEP--*}
284 echo
285 echo "Host run: $iter"
286 $iter || exit 1
287 echo
288 host_run="${host_run#*--SEP--}"
289 done
290}
291
292
d90671f3 293set_volumes() {
e02c1511 294 volumes=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
02d9a654 295 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
d90671f3
SS
296}
297
41daa523 298set_links() {
e02c1511 299 links=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
41daa523 300 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
301}
302
06310c73
GXT
303find_templates() {
304 local templates=`cat $1 | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
7f77c274
SS
305 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
306
06310c73
GXT
307 local arrTemplates=${templates// / }
308
2ec550f7 309 if [ ! -z "$templates" ]; then
06310c73
GXT
310 for template in "${arrTemplates[@]}"
311 do
312 local nested_templates=$(find_templates $template)
313
314 if [ ! -z "$nested_templates" ]; then
315 templates="$templates $nested_templates"
316 fi
317 done
318
319 echo $templates
320 else
321 echo ""
322 fi
323}
324
325set_template_info() {
326 templates=$(find_templates $config_file)
327
7f77c274
SS
328 arrTemplates=(${templates// / })
329 config_data=$(cat $config_file)
330
331 input="hack: true"
332
7f77c274
SS
333 for template in "${arrTemplates[@]}"
334 do
335 [ ! -z $template ] && {
336 input="$input _FILE_SEPERATOR_ $(cat $template)"
337 }
338 done
339
340 # we always want our config file last so it takes priority
341 input="$input _FILE_SEPERATOR_ $config_data"
342
343 read -r -d '' env_ruby << 'RUBY'
344 require 'yaml'
345
346 input=STDIN.readlines.join
093e6628 347 # default to UTF-8 for the dbs sake
3cb3d9c4 348 env = {'LANG' => 'en_US.UTF-8'}
7f77c274
SS
349 input.split('_FILE_SEPERATOR_').each do |yml|
350 yml.strip!
351 begin
352 env.merge!(YAML.load(yml)['env'] || {})
f3824347 353 rescue Psych::SyntaxError => e
354 puts e
355 puts "*ERROR."
7f77c274
SS
356 rescue => e
357 puts yml
358 p e
359 end
360 end
09d22c3f 361 env.each{|k,v| puts "*ERROR." if v.is_a?(Hash)}
0138494b 362 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
7f77c274
SS
363RUBY
364
fb827907
EP
365 tmp_input_file=$(mktemp)
366
367 echo "$input" > "$tmp_input_file"
368 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
369
370 rm -f "$tmp_input_file"
4b563ee8
SS
371
372 env=()
f3824347 373 ok=1
4b563ee8 374 while read i; do
f3824347 375 if [ "$i" == "*ERROR." ]; then
376 ok=0
377 elif [ -n "$i" ]; then
0138494b 378 env[${#env[@]}]="${i//\{\{config\}\}/${config}}"
16f2d250 379 fi
4b563ee8
SS
380 done <<< "$raw"
381
f3824347 382 if [ "$ok" -ne 1 ]; then
383 echo "${env[@]}"
c2d3ee4a 384 echo "YAML syntax error. Please check your containers/*.yml config files."
f3824347 385 exit 1
386 fi
762d9bbf 387
8f57aae5 388 # labels
762d9bbf
MP
389 read -r -d '' labels_ruby << 'RUBY'
390 require 'yaml'
391
392 input=STDIN.readlines.join
762d9bbf
MP
393 labels = {}
394 input.split('_FILE_SEPERATOR_').each do |yml|
395 yml.strip!
396 begin
397 labels.merge!(YAML.load(yml)['labels'] || {})
398 rescue Psych::SyntaxError => e
399 puts e
400 puts "*ERROR."
401 rescue => e
402 puts yml
403 p e
404 end
405 end
406 puts labels.map{|k,v| "-l\n#{k}=#{v}" }.join("\n")
407RUBY
408
fb827907
EP
409 tmp_input_file=$(mktemp)
410
411 echo "$input" > "$tmp_input_file"
412 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$labels_ruby"`
413
414 rm -f "$tmp_input_file"
762d9bbf
MP
415
416 labels=()
417 ok=1
418 while read i; do
419 if [ "$i" == "*ERROR." ]; then
420 ok=0
421 elif [ -n "$i" ]; then
daddbf86 422 labels[${#labels[@]}]=$(echo $i | sed s/{{config}}/${config}/g)
762d9bbf
MP
423 fi
424 done <<< "$raw"
425
426 if [ "$ok" -ne 1 ]; then
427 echo "${labels[@]}"
428 echo "YAML syntax error. Please check your containers/*.yml config files."
429 exit 1
430 fi
8f57aae5
NL
431
432 # expose
433 read -r -d '' ports_ruby << 'RUBY'
434 require 'yaml'
435
436 input=STDIN.readlines.join
437 ports = []
438 input.split('_FILE_SEPERATOR_').each do |yml|
439 yml.strip!
440 begin
441 ports += (YAML.load(yml)['expose'] || [])
442 rescue Psych::SyntaxError => e
443 puts e
444 puts "*ERROR."
445 rescue => e
446 puts yml
447 p e
448 end
449 end
16fb17cf 450 puts ports.map { |p| p.to_s.include?(':') ? "-p\n#{p}" : "--expose\n#{p}" }.join("\n")
8f57aae5
NL
451RUBY
452
453 tmp_input_file=$(mktemp)
454
455 echo "$input" > "$tmp_input_file"
456 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$ports_ruby"`
457
458 rm -f "$tmp_input_file"
459
460 ports=()
461 ok=1
462 while read i; do
463 if [ "$i" == "*ERROR." ]; then
464 ok=0
465 elif [ -n "$i" ]; then
466 ports[${#ports[@]}]=$i
467 fi
468 done <<< "$raw"
469
470 if [ "$ok" -ne 1 ]; then
471 echo "${ports[@]}"
472 echo "YAML syntax error. Please check your containers/*.yml config files."
473 exit 1
474 fi
bfc79e77
DE
475
476 merge_user_args
7f77c274
SS
477}
478
665468eb 479if [ -z $docker_path ]; then
52388b87 480 install_docker
665468eb 481fi
52388b87 482
de869404 483[ "$command" == "cleanup" ] && {
b54cb8ea
SG
484 $docker_path container prune --filter until=1h
485 $docker_path image prune --all --filter until=1h
2dfd2c6d
GXT
486
487 if [ -d /var/discourse/shared/standalone/postgres_data_old ]; then
488 echo
489 echo "Old PostgreSQL backup data cluster detected taking up $(du -hs /var/discourse/shared/standalone/postgres_data_old | awk '{print $1}') detected"
490 read -p "Would you like to remove it? (Y/n): " -n 1 -r && echo
491
492 if [[ $REPLY =~ ^[Yy]$ ]]; then
493 echo "removing old PostgreSQL data cluster at /var/discourse/shared/standalone/postgres_data_old..."
b20ba9ee 494 rm -rf /var/discourse/shared/standalone/postgres_data_old*
2dfd2c6d
GXT
495 else
496 exit 1
497 fi
498 fi
499
a8b66f98
L
500 exit 0
501}
5f803fb4 502
65573a0e
GXT
503if [ ! "$command" == "setup" ]; then
504 if [[ ! -e $config_file ]]; then
7e738616 505 echo "Config file was not found, ensure $config_file exists"
5dfdf9a3 506 echo
71680b16 507 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
7e738616 508 exit 1
65573a0e 509 fi
7e738616
S
510fi
511
e2ed1fb6
S
512docker_version=($($docker_path --version))
513docker_version=${test[2]//,/}
69545efd 514restart_policy=${restart_policy:---restart=always}
e2ed1fb6 515
30835a52 516set_existing_container(){
295e8f19 517 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
337a89aa
S
518}
519
665468eb 520run_stop() {
337a89aa 521
30835a52 522 set_existing_container
60f9f04c 523
30835a52 524 if [ ! -z $existing ]
337a89aa 525 then
30835a52
S
526 (
527 set -x
a9cba0fc 528 $docker_path stop -t 10 $config
30835a52 529 )
337a89aa 530 else
30835a52 531 echo "$config was not started !"
f73c2d03 532 echo "./discourse-doctor may help diagnose the problem."
30835a52
S
533 exit 1
534 fi
535}
337a89aa 536
8877f99e
S
537set_run_image() {
538 run_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
539 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['run_image']"`
540
c786ffcd
GXT
541 if [ -n "$user_run_image" ]; then
542 run_image=$user_run_image
543 elif [ -z "$run_image" ]; then
8877f99e
S
544 run_image="$local_discourse/$config"
545 fi
546}
547
548set_boot_command() {
549 boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
550 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['boot_command']"`
551
552 if [ -z "$boot_command" ]; then
553
554 no_boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
555 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['no_boot_command']"`
556
557 if [ -z "$no_boot_command" ]; then
558 boot_command="/sbin/boot"
559 fi
560 fi
561}
562
bfc79e77
DE
563merge_user_args() {
564 local docker_args
565
566 docker_args=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
567 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['docker_args']"`
568
569 if [[ -n "$docker_args" ]]; then
47890a9a 570 user_args="$user_args_argv $docker_args"
bfc79e77
DE
571 fi
572}
573
665468eb 574run_start() {
337a89aa 575
7d49dbe7 576 if [ -z "$START_CMD_ONLY" ]
30835a52 577 then
7d49dbe7
SS
578 existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
579 echo $existing
580 if [ ! -z $existing ]
581 then
582 echo "Nothing to do, your container has already started!"
583 exit 0
584 fi
30835a52 585
7d49dbe7
SS
586 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
587 if [ ! -z $existing ]
588 then
589 echo "starting up existing container"
590 (
591 set -x
592 $docker_path start $config
593 )
594 exit 0
595 fi
30835a52
S
596 fi
597
598 host_run
1f656469 599
30835a52
S
600 set_template_info
601 set_volumes
602 set_links
8877f99e
S
603 set_run_image
604 set_boot_command
30835a52 605
c6dd6f9d
FB
606 # get hostname and settings from container configuration
607 for envar in "${env[@]}"
608 do
609 if [[ $envar == DOCKER_USE_HOSTNAME* ]] || [[ $envar == DISCOURSE_HOSTNAME* ]]
610 then
611 # use as environment variable
612 eval $envar
613 fi
614 done
615
30835a52 616 (
c834fdd1 617 hostname=`hostname -s`
c6dd6f9d
FB
618 # overwrite hostname
619 if [ "$DOCKER_USE_HOSTNAME" = "true" ]
620 then
621 hostname=$DISCOURSE_HOSTNAME
622 else
623 hostname=$hostname-$config
624 fi
625
a0606001
S
626 # we got to normalize so we only have allowed strings, this is more comprehensive but lets see how bash does first
627 # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
628 # docker added more hostname rules
fd2e7637 629 hostname=${hostname//_/-}
a0606001 630
cad2919f
GXT
631
632 if [ -z "$SKIP_MAC_ADDRESS" ] ; then
633 mac_address="--mac-address $($docker_path run $user_args -i --rm -a stdout -a stderr $image /bin/sh -c "echo $hostname | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'")"
634 fi
d2a86ee1 635
7d49dbe7
SS
636 if [ ! -z "$START_CMD_ONLY" ] ; then
637 docker_path="true"
638 fi
639
30835a52 640 set -x
7d49dbe7 641
27c21012 642 $docker_path run --shm-size=512m $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
bfc79e77 643 -e DOCKER_HOST_IP="$docker_ip" --name $config -t "${ports[@]}" $volumes $mac_address $user_args \
d2a86ee1 644 $run_image $boot_command
30835a52
S
645
646 )
647 exit 0
337a89aa
S
648
649}
650
2791af60
GXT
651run_run() {
652 set_template_info
653 set_volumes
654 set_links
655 set_run_image
656
657 unset ERR
658 (exec $docker_path run --rm --shm-size=512m $user_args $links "${env[@]}" -e DOCKER_HOST_IP="$docker_ip" -i -a stdin -a stdout -a stderr $volumes $run_image \
659 /bin/bash -c "$run_command") || ERR=$?
660
661 if [[ $ERR > 0 ]]; then
662 exit 1
663 fi
664}
665
666run_bootstrap() {
60f9f04c
S
667 host_run
668
680dd4ea
S
669 # Is the image available?
670 # If not, pull it here so the user is aware what's happening.
a554d3dc 671 $docker_path history $image >/dev/null 2>&1 || pull_image
88126eba 672
680dd4ea 673 set_template_info
93149421 674
e02c1511 675 base_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 676 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
93149421 677
e02c1511 678 update_pups=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 679 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
b9c7b50e 680
680dd4ea
S
681 if [[ ! X"" = X"$base_image" ]]; then
682 image=$base_image
683 fi
b9c7b50e 684
680dd4ea 685 set_volumes
41daa523 686 set_links
f126bcc6 687
680dd4ea 688 rm -f $cidbootstrap
d90671f3 689
680dd4ea
S
690 run_command="cd /pups &&"
691 if [[ ! "false" = $update_pups ]]; then
692 run_command="$run_command git pull &&"
693 fi
ca2ce907 694 run_command="$run_command /pups/bin/pups --stdin"
2162f1d4 695
680dd4ea 696 echo $run_command
b9c7b50e 697
b4ab14c2 698 unset ERR
fb827907
EP
699
700 tmp_input_file=$(mktemp)
701
702 echo "$input" > "$tmp_input_file"
703 (exec cat "$tmp_input_file" | $docker_path run --shm-size=512m $user_args $links "${env[@]}" -e DOCKER_HOST_IP="$docker_ip" --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
b4ab14c2
S
704 /bin/bash -c "$run_command") || ERR=$?
705
fb827907
EP
706 rm -f "$tmp_input_file"
707
b4ab14c2
S
708 unset FAILED
709 # magic exit code that indicates a retry
710 if [[ "$ERR" == 77 ]]; then
382c8e40
S
711 $docker_path rm `cat $cidbootstrap`
712 rm $cidbootstrap
b4ab14c2 713 exit 77
382c8e40 714 elif [[ "$ERR" > 0 ]]; then
b4ab14c2
S
715 FAILED=TRUE
716 fi
19e3a6c0
S
717
718 if [[ $FAILED = "TRUE" ]]; then
719 if [[ ! -z "$DEBUG" ]]; then
720 $docker_path commit `cat $cidbootstrap` $local_discourse/$config-debug || echo 'FAILED TO COMMIT'
721 echo "** DEBUG ** Maintaining image for diagnostics $local_discourse/$config-debug"
722 fi
88126eba 723
19e3a6c0
S
724 $docker_path rm `cat $cidbootstrap`
725 rm $cidbootstrap
f73c2d03
JP
726 echo "** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one."
727 echo "./discourse-doctor may help diagnose the problem."
19e3a6c0
S
728 exit 1
729 fi
9fb5f2d3 730
680dd4ea 731 sleep 5
2162f1d4 732
4807b1b8
MB
733 $docker_path commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
734 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
680dd4ea 735}
9fb5f2d3 736
680dd4ea
S
737case "$command" in
738 bootstrap)
680dd4ea 739 run_bootstrap
2dd2e330 740 echo "Successfully bootstrapped, to startup use ./launcher start $config"
4b3aebe1 741 exit 0
5f803fb4 742 ;;
1acce9e4 743
1ec142a1
GXT
744 run)
745 run_run
746 exit 0
747 ;;
748
2fc6ff36 749 enter)
0c456e8c 750 exec $docker_path exec -it $config /bin/bash --login
2fc6ff36
S
751 ;;
752
5f803fb4 753 stop)
337a89aa
S
754 run_stop
755 exit 0
5f803fb4 756 ;;
7e738616 757
5f803fb4 758 logs)
7e738616 759
30835a52
S
760 $docker_path logs $config
761 exit 0
5f803fb4 762 ;;
7e738616 763
337a89aa
S
764 restart)
765 run_stop
766 run_start
767 exit 0
768 ;;
80c11be3 769
7d49dbe7
SS
770 start-cmd)
771 START_CMD_ONLY="1"
772 run_start
773 exit 0;
774 ;;
775
337a89aa
S
776 start)
777 run_start
778 exit 0
5f803fb4 779 ;;
7e738616 780
680dd4ea 781 rebuild)
4b6456ef 782 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
c2d3ee4a 783 echo "Ensuring launcher is up to date"
098533cb
S
784
785 git remote update
786
755ab5ac 787 LOCAL=$(git rev-parse HEAD)
098533cb 788 REMOTE=$(git rev-parse @{u})
755ab5ac 789 BASE=$(git merge-base HEAD @{u})
098533cb
S
790
791 if [ $LOCAL = $REMOTE ]; then
c2d3ee4a 792 echo "Launcher is up-to-date"
098533cb
S
793
794 elif [ $LOCAL = $BASE ]; then
13b0817c 795 echo "Updating Launcher..."
098533cb 796 git pull || (echo 'failed to update' && exit 1)
88ee2e35 797
13b0817c
MB
798 echo "Launcher updated, restarting..."
799 exec "$0" "${SAVED_ARGV[@]}"
098533cb
S
800
801 elif [ $REMOTE = $BASE ]; then
c2d3ee4a 802 echo "Your version of Launcher is ahead of origin"
098533cb
S
803
804 else
c2d3ee4a 805 echo "Launcher has diverged source, this is only expected in Dev mode"
098533cb
S
806 fi
807
4b6456ef 808 fi
30835a52
S
809
810 set_existing_container
811
812 if [ ! -z $existing ]
680dd4ea
S
813 then
814 echo "Stopping old container"
30835a52
S
815 (
816 set -x
49ed1415 817 $docker_path stop -t 60 $config
30835a52 818 )
680dd4ea
S
819 fi
820
821 run_bootstrap
822
30835a52 823 if [ ! -z $existing ]
680dd4ea 824 then
30835a52
S
825 echo "Removing old container"
826 (
827 set -x
828 $docker_path rm $config
829 )
680dd4ea
S
830 fi
831
832 run_start
833 exit 0
834 ;;
835
7e738616 836
5f803fb4 837 destroy)
98bd0edf 838 (set -x; $docker_path stop -t 10 $config && $docker_path rm $config) || (echo "$config was not found" && exit 0)
30835a52 839 exit 0
5f803fb4
SS
840 ;;
841esac
7e738616 842
5f803fb4 843usage