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