Bump base image (#538)
[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
978ab0a4 85pups_version='v1.0.3'
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
faa7b961 94image="discourse/base:2.0.20210415-1332"
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 243 if tty >/dev/null; then
f8ba11c2 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
623f1073
MB
245 echo
246 if [[ $REPLY =~ ^[Yy]$ ]]
247 then
79c49c19
SS
248 $docker_path container prune --force --filter until=24h >/dev/null
249 $docker_path image prune --all --force --filter until=24h >/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
d90671f3 262set_volumes() {
e02c1511 263 volumes=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
02d9a654 264 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
d90671f3
SS
265}
266
41daa523 267set_links() {
e02c1511 268 links=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
41daa523 269 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
270}
271
06310c73
GXT
272find_templates() {
273 local templates=`cat $1 | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
7f77c274
SS
274 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
275
06310c73
GXT
276 local arrTemplates=${templates// / }
277
2ec550f7 278 if [ ! -z "$templates" ]; then
06310c73
GXT
279 echo $templates
280 else
281 echo ""
282 fi
283}
284
285set_template_info() {
286 templates=$(find_templates $config_file)
287
7f77c274
SS
288 arrTemplates=(${templates// / })
289 config_data=$(cat $config_file)
290
291 input="hack: true"
292
7f77c274
SS
293 for template in "${arrTemplates[@]}"
294 do
295 [ ! -z $template ] && {
296 input="$input _FILE_SEPERATOR_ $(cat $template)"
297 }
298 done
299
300 # we always want our config file last so it takes priority
301 input="$input _FILE_SEPERATOR_ $config_data"
302
303 read -r -d '' env_ruby << 'RUBY'
304 require 'yaml'
305
306 input=STDIN.readlines.join
093e6628 307 # default to UTF-8 for the dbs sake
3cb3d9c4 308 env = {'LANG' => 'en_US.UTF-8'}
7f77c274
SS
309 input.split('_FILE_SEPERATOR_').each do |yml|
310 yml.strip!
311 begin
312 env.merge!(YAML.load(yml)['env'] || {})
f3824347 313 rescue Psych::SyntaxError => e
314 puts e
315 puts "*ERROR."
7f77c274
SS
316 rescue => e
317 puts yml
318 p e
319 end
320 end
09d22c3f 321 env.each{|k,v| puts "*ERROR." if v.is_a?(Hash)}
0138494b 322 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
7f77c274
SS
323RUBY
324
fb827907
EP
325 tmp_input_file=$(mktemp)
326
327 echo "$input" > "$tmp_input_file"
328 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
329
330 rm -f "$tmp_input_file"
4b563ee8
SS
331
332 env=()
f3824347 333 ok=1
4b563ee8 334 while read i; do
f3824347 335 if [ "$i" == "*ERROR." ]; then
336 ok=0
337 elif [ -n "$i" ]; then
0138494b 338 env[${#env[@]}]="${i//\{\{config\}\}/${config}}"
16f2d250 339 fi
4b563ee8
SS
340 done <<< "$raw"
341
f3824347 342 if [ "$ok" -ne 1 ]; then
343 echo "${env[@]}"
c2d3ee4a 344 echo "YAML syntax error. Please check your containers/*.yml config files."
f3824347 345 exit 1
346 fi
762d9bbf 347
8f57aae5 348 # labels
762d9bbf
MP
349 read -r -d '' labels_ruby << 'RUBY'
350 require 'yaml'
351
352 input=STDIN.readlines.join
762d9bbf
MP
353 labels = {}
354 input.split('_FILE_SEPERATOR_').each do |yml|
355 yml.strip!
356 begin
357 labels.merge!(YAML.load(yml)['labels'] || {})
358 rescue Psych::SyntaxError => e
359 puts e
360 puts "*ERROR."
361 rescue => e
362 puts yml
363 p e
364 end
365 end
366 puts labels.map{|k,v| "-l\n#{k}=#{v}" }.join("\n")
367RUBY
368
fb827907
EP
369 tmp_input_file=$(mktemp)
370
371 echo "$input" > "$tmp_input_file"
372 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$labels_ruby"`
373
374 rm -f "$tmp_input_file"
762d9bbf
MP
375
376 labels=()
377 ok=1
378 while read i; do
379 if [ "$i" == "*ERROR." ]; then
380 ok=0
381 elif [ -n "$i" ]; then
daddbf86 382 labels[${#labels[@]}]=$(echo $i | sed s/{{config}}/${config}/g)
762d9bbf
MP
383 fi
384 done <<< "$raw"
385
386 if [ "$ok" -ne 1 ]; then
387 echo "${labels[@]}"
388 echo "YAML syntax error. Please check your containers/*.yml config files."
389 exit 1
390 fi
8f57aae5
NL
391
392 # expose
393 read -r -d '' ports_ruby << 'RUBY'
394 require 'yaml'
395
396 input=STDIN.readlines.join
397 ports = []
398 input.split('_FILE_SEPERATOR_').each do |yml|
399 yml.strip!
400 begin
401 ports += (YAML.load(yml)['expose'] || [])
402 rescue Psych::SyntaxError => e
403 puts e
404 puts "*ERROR."
405 rescue => e
406 puts yml
407 p e
408 end
409 end
16fb17cf 410 puts ports.map { |p| p.to_s.include?(':') ? "-p\n#{p}" : "--expose\n#{p}" }.join("\n")
8f57aae5
NL
411RUBY
412
413 tmp_input_file=$(mktemp)
414
415 echo "$input" > "$tmp_input_file"
416 raw=`exec cat "$tmp_input_file" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$ports_ruby"`
417
418 rm -f "$tmp_input_file"
419
420 ports=()
421 ok=1
422 while read i; do
423 if [ "$i" == "*ERROR." ]; then
424 ok=0
425 elif [ -n "$i" ]; then
426 ports[${#ports[@]}]=$i
427 fi
428 done <<< "$raw"
429
430 if [ "$ok" -ne 1 ]; then
431 echo "${ports[@]}"
432 echo "YAML syntax error. Please check your containers/*.yml config files."
433 exit 1
434 fi
bfc79e77
DE
435
436 merge_user_args
7f77c274
SS
437}
438
665468eb 439if [ -z $docker_path ]; then
52388b87 440 install_docker
665468eb 441fi
52388b87 442
de869404 443[ "$command" == "cleanup" ] && {
b54cb8ea
SG
444 $docker_path container prune --filter until=1h
445 $docker_path image prune --all --filter until=1h
2dfd2c6d
GXT
446
447 if [ -d /var/discourse/shared/standalone/postgres_data_old ]; then
448 echo
449 echo "Old PostgreSQL backup data cluster detected taking up $(du -hs /var/discourse/shared/standalone/postgres_data_old | awk '{print $1}') detected"
f8ba11c2 450 read -p "Would you like to remove it? (y/N): " -n 1 -r && echo
2dfd2c6d
GXT
451
452 if [[ $REPLY =~ ^[Yy]$ ]]; then
453 echo "removing old PostgreSQL data cluster at /var/discourse/shared/standalone/postgres_data_old..."
b20ba9ee 454 rm -rf /var/discourse/shared/standalone/postgres_data_old*
2dfd2c6d
GXT
455 else
456 exit 1
457 fi
458 fi
459
a8b66f98
L
460 exit 0
461}
5f803fb4 462
65573a0e
GXT
463if [ ! "$command" == "setup" ]; then
464 if [[ ! -e $config_file ]]; then
7e738616 465 echo "Config file was not found, ensure $config_file exists"
5dfdf9a3 466 echo
71680b16 467 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
7e738616 468 exit 1
65573a0e 469 fi
7e738616
S
470fi
471
e2ed1fb6
S
472docker_version=($($docker_path --version))
473docker_version=${test[2]//,/}
69545efd 474restart_policy=${restart_policy:---restart=always}
e2ed1fb6 475
30835a52 476set_existing_container(){
295e8f19 477 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
337a89aa
S
478}
479
665468eb 480run_stop() {
337a89aa 481
30835a52 482 set_existing_container
60f9f04c 483
30835a52 484 if [ ! -z $existing ]
337a89aa 485 then
30835a52
S
486 (
487 set -x
dd2804d1 488 $docker_path stop -t 30 $config
30835a52 489 )
337a89aa 490 else
30835a52 491 echo "$config was not started !"
f73c2d03 492 echo "./discourse-doctor may help diagnose the problem."
30835a52
S
493 exit 1
494 fi
495}
337a89aa 496
8877f99e
S
497set_run_image() {
498 run_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
499 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['run_image']"`
500
c786ffcd
GXT
501 if [ -n "$user_run_image" ]; then
502 run_image=$user_run_image
503 elif [ -z "$run_image" ]; then
8877f99e
S
504 run_image="$local_discourse/$config"
505 fi
506}
507
508set_boot_command() {
509 boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
510 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['boot_command']"`
511
512 if [ -z "$boot_command" ]; then
513
514 no_boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
515 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['no_boot_command']"`
516
517 if [ -z "$no_boot_command" ]; then
518 boot_command="/sbin/boot"
519 fi
520 fi
521}
522
bfc79e77
DE
523merge_user_args() {
524 local docker_args
525
526 docker_args=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
527 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['docker_args']"`
528
529 if [[ -n "$docker_args" ]]; then
47890a9a 530 user_args="$user_args_argv $docker_args"
bfc79e77
DE
531 fi
532}
533
665468eb 534run_start() {
337a89aa 535
7d49dbe7 536 if [ -z "$START_CMD_ONLY" ]
30835a52 537 then
7d49dbe7
SS
538 existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
539 echo $existing
540 if [ ! -z $existing ]
541 then
542 echo "Nothing to do, your container has already started!"
543 exit 0
544 fi
30835a52 545
7d49dbe7
SS
546 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
547 if [ ! -z $existing ]
548 then
549 echo "starting up existing container"
550 (
551 set -x
552 $docker_path start $config
553 )
554 exit 0
555 fi
30835a52
S
556 fi
557
30835a52
S
558 set_template_info
559 set_volumes
560 set_links
8877f99e
S
561 set_run_image
562 set_boot_command
30835a52 563
c6dd6f9d
FB
564 # get hostname and settings from container configuration
565 for envar in "${env[@]}"
566 do
567 if [[ $envar == DOCKER_USE_HOSTNAME* ]] || [[ $envar == DISCOURSE_HOSTNAME* ]]
568 then
569 # use as environment variable
570 eval $envar
571 fi
572 done
573
30835a52 574 (
c834fdd1 575 hostname=`hostname -s`
c6dd6f9d
FB
576 # overwrite hostname
577 if [ "$DOCKER_USE_HOSTNAME" = "true" ]
578 then
579 hostname=$DISCOURSE_HOSTNAME
580 else
581 hostname=$hostname-$config
582 fi
583
a0606001
S
584 # we got to normalize so we only have allowed strings, this is more comprehensive but lets see how bash does first
585 # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
586 # docker added more hostname rules
fd2e7637 587 hostname=${hostname//_/-}
a0606001 588
cad2919f
GXT
589
590 if [ -z "$SKIP_MAC_ADDRESS" ] ; then
591 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/'")"
592 fi
d2a86ee1 593
7d49dbe7
SS
594 if [ ! -z "$START_CMD_ONLY" ] ; then
595 docker_path="true"
596 fi
597
30835a52 598 set -x
7d49dbe7 599
27c21012 600 $docker_path run --shm-size=512m $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
bfc79e77 601 -e DOCKER_HOST_IP="$docker_ip" --name $config -t "${ports[@]}" $volumes $mac_address $user_args \
d2a86ee1 602 $run_image $boot_command
30835a52
S
603
604 )
605 exit 0
337a89aa
S
606
607}
608
2791af60
GXT
609run_run() {
610 set_template_info
611 set_volumes
612 set_links
613 set_run_image
614
615 unset ERR
616 (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 \
617 /bin/bash -c "$run_command") || ERR=$?
618
619 if [[ $ERR > 0 ]]; then
620 exit 1
621 fi
622}
623
624run_bootstrap() {
680dd4ea
S
625 # Is the image available?
626 # If not, pull it here so the user is aware what's happening.
a554d3dc 627 $docker_path history $image >/dev/null 2>&1 || pull_image
88126eba 628
680dd4ea 629 set_template_info
93149421 630
e02c1511 631 base_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 632 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
93149421 633
e02c1511 634 update_pups=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 635 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
b9c7b50e 636
680dd4ea
S
637 if [[ ! X"" = X"$base_image" ]]; then
638 image=$base_image
639 fi
b9c7b50e 640
680dd4ea 641 set_volumes
41daa523 642 set_links
f126bcc6 643
680dd4ea 644 rm -f $cidbootstrap
d90671f3 645
680dd4ea
S
646 run_command="cd /pups &&"
647 if [[ ! "false" = $update_pups ]]; then
978ab0a4 648 run_command="$run_command git pull && git checkout $pups_version &&"
680dd4ea 649 fi
ca2ce907 650 run_command="$run_command /pups/bin/pups --stdin"
2162f1d4 651
680dd4ea 652 echo $run_command
b9c7b50e 653
b4ab14c2 654 unset ERR
fb827907
EP
655
656 tmp_input_file=$(mktemp)
657
658 echo "$input" > "$tmp_input_file"
659 (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
660 /bin/bash -c "$run_command") || ERR=$?
661
fb827907
EP
662 rm -f "$tmp_input_file"
663
b4ab14c2
S
664 unset FAILED
665 # magic exit code that indicates a retry
666 if [[ "$ERR" == 77 ]]; then
382c8e40
S
667 $docker_path rm `cat $cidbootstrap`
668 rm $cidbootstrap
b4ab14c2 669 exit 77
382c8e40 670 elif [[ "$ERR" > 0 ]]; then
b4ab14c2
S
671 FAILED=TRUE
672 fi
19e3a6c0
S
673
674 if [[ $FAILED = "TRUE" ]]; then
675 if [[ ! -z "$DEBUG" ]]; then
676 $docker_path commit `cat $cidbootstrap` $local_discourse/$config-debug || echo 'FAILED TO COMMIT'
677 echo "** DEBUG ** Maintaining image for diagnostics $local_discourse/$config-debug"
678 fi
88126eba 679
19e3a6c0
S
680 $docker_path rm `cat $cidbootstrap`
681 rm $cidbootstrap
f73c2d03
JP
682 echo "** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one."
683 echo "./discourse-doctor may help diagnose the problem."
19e3a6c0
S
684 exit 1
685 fi
9fb5f2d3 686
680dd4ea 687 sleep 5
2162f1d4 688
4807b1b8
MB
689 $docker_path commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
690 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
680dd4ea 691}
9fb5f2d3 692
680dd4ea
S
693case "$command" in
694 bootstrap)
680dd4ea 695 run_bootstrap
2dd2e330 696 echo "Successfully bootstrapped, to startup use ./launcher start $config"
4b3aebe1 697 exit 0
5f803fb4 698 ;;
1acce9e4 699
1ec142a1
GXT
700 run)
701 run_run
702 exit 0
703 ;;
704
2fc6ff36 705 enter)
0c456e8c 706 exec $docker_path exec -it $config /bin/bash --login
2fc6ff36
S
707 ;;
708
5f803fb4 709 stop)
337a89aa
S
710 run_stop
711 exit 0
5f803fb4 712 ;;
7e738616 713
5f803fb4 714 logs)
7e738616 715
30835a52
S
716 $docker_path logs $config
717 exit 0
5f803fb4 718 ;;
7e738616 719
337a89aa
S
720 restart)
721 run_stop
722 run_start
723 exit 0
724 ;;
80c11be3 725
7d49dbe7
SS
726 start-cmd)
727 START_CMD_ONLY="1"
728 run_start
729 exit 0;
730 ;;
731
337a89aa
S
732 start)
733 run_start
734 exit 0
5f803fb4 735 ;;
7e738616 736
680dd4ea 737 rebuild)
4b6456ef 738 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
c2d3ee4a 739 echo "Ensuring launcher is up to date"
098533cb
S
740
741 git remote update
742
755ab5ac 743 LOCAL=$(git rev-parse HEAD)
098533cb 744 REMOTE=$(git rev-parse @{u})
755ab5ac 745 BASE=$(git merge-base HEAD @{u})
098533cb
S
746
747 if [ $LOCAL = $REMOTE ]; then
c2d3ee4a 748 echo "Launcher is up-to-date"
098533cb
S
749
750 elif [ $LOCAL = $BASE ]; then
13b0817c 751 echo "Updating Launcher..."
098533cb 752 git pull || (echo 'failed to update' && exit 1)
88ee2e35 753
13b0817c
MB
754 echo "Launcher updated, restarting..."
755 exec "$0" "${SAVED_ARGV[@]}"
098533cb
S
756
757 elif [ $REMOTE = $BASE ]; then
c2d3ee4a 758 echo "Your version of Launcher is ahead of origin"
098533cb
S
759
760 else
c2d3ee4a 761 echo "Launcher has diverged source, this is only expected in Dev mode"
098533cb
S
762 fi
763
4b6456ef 764 fi
30835a52
S
765
766 set_existing_container
767
768 if [ ! -z $existing ]
680dd4ea
S
769 then
770 echo "Stopping old container"
30835a52
S
771 (
772 set -x
49ed1415 773 $docker_path stop -t 60 $config
30835a52 774 )
680dd4ea
S
775 fi
776
777 run_bootstrap
778
30835a52 779 if [ ! -z $existing ]
680dd4ea 780 then
30835a52
S
781 echo "Removing old container"
782 (
783 set -x
784 $docker_path rm $config
785 )
680dd4ea
S
786 fi
787
788 run_start
789 exit 0
790 ;;
791
7e738616 792
5f803fb4 793 destroy)
98bd0edf 794 (set -x; $docker_path stop -t 10 $config && $docker_path rm $config) || (echo "$config was not found" && exit 0)
30835a52 795 exit 0
5f803fb4
SS
796 ;;
797esac
7e738616 798
5f803fb4 799usage