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