651155a2148c15e98e025295e270e628dc4c8e80
[discourse_docker.git] / launcher
1 #!/usr/bin/env bash
2
3 usage () {
4 echo "Usage: launcher COMMAND CONFIG [--skip-prereqs] [--docker-args STRING]"
5 echo "Commands:"
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"
13 echo " run: Run the given command with the config in the context of the last bootstrapped image"
14 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
15 echo " cleanup: Remove all containers that have stopped for > 24 hours"
16 echo " start-cmd: Generate docker command used to start container"
17 echo
18 echo "Options:"
19 echo " --skip-prereqs Don't check launcher prerequisites"
20 echo " --docker-args Extra arguments to pass when running docker"
21 echo " --skip-mac-address Don't assign a mac address"
22 echo " --run-image Override the image used for running the container"
23 exit 1
24 }
25
26 # for potential re-exec later
27 SAVED_ARGV=("$@")
28
29 command=$1
30 config=$2
31
32 # user_args_argv is assigned once when the argument vector is parsed.
33 user_args_argv=""
34 # user_args is mutable: its value may change when templates are parsed.
35 # Superset of user_args_argv.
36 user_args=""
37
38 user_run_image=""
39
40 if [[ $command == "run" ]]; then
41 run_command=$3
42 fi
43
44 while [ ${#} -gt 0 ]; do
45 case "${1}" in
46 --debug)
47 DEBUG="1"
48 ;;
49 --skip-prereqs)
50 SKIP_PREREQS="1"
51 ;;
52 --skip-mac-address)
53 SKIP_MAC_ADDRESS="1"
54 ;;
55 --docker-args)
56 user_args_argv="$2"
57 user_args="$user_args_argv"
58 shift
59 ;;
60 --run-image)
61 user_run_image="$2"
62 shift
63 ;;
64 esac
65
66 shift 1
67 done
68
69 if [ -z "$command" -o -z "$config" -a "$command" != "cleanup" ]; then
70 usage
71 exit 1
72 fi
73
74 # Docker doesn't like uppercase characters, spaces or special characters, catch it now before we build everything out and then find out
75 re='[[:upper:]/ !@#$%^&*()+~`=]'
76 if [[ $config =~ $re ]];
77 then
78 echo
79 echo "ERROR: Config name '$config' must not contain upper case characters, spaces or special characters. Correct config name and rerun $0."
80 echo
81 exit 1
82 fi
83
84 cd "$(dirname "$0")"
85
86 docker_min_version='17.03.1'
87 docker_rec_version='17.06.2'
88 git_min_version='1.8.0'
89 git_rec_version='1.8.0'
90
91 config_file=containers/"$config".yml
92 cidbootstrap=cids/"$config"_bootstrap.cid
93 local_discourse=local_discourse
94 image="discourse/base:2.0.20201004-2310"
95 docker_path=`which docker.io 2> /dev/null || which docker`
96 git_path=`which git`
97
98 if [ "${SUPERVISED}" = "true" ]; then
99 restart_policy="--restart=no"
100 attach_on_start="-a"
101 attach_on_run="-a stdout -a stderr"
102 else
103 attach_on_run="-d"
104 fi
105
106 if [ -n "$DOCKER_HOST" ]; then
107 docker_ip=`sed -e 's/^tcp:\/\/\(.*\):.*$/\1/' <<< "$DOCKER_HOST"`
108 elif [ -x "$(which ip 2>/dev/null)" ]; then
109 docker_ip=`ip addr show docker0 | \
110 grep 'inet ' | \
111 awk '{ split($2,a,"/"); print a[1] }';`
112 else
113 docker_ip=`ifconfig | \
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 }';`
118 fi
119
120 # From https://stackoverflow.com/a/44660519/702738
121 compare_version() {
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
130 return 1
131 elif ((10#${a[i]:-0} > 10#${b[i]:-0})); then
132 return 0
133 fi
134 done
135 if [ "$arem" '<' "$brem" ]; then
136 return 1
137 elif [ "$arem" '>' "$brem" ]; then
138 return 0
139 fi
140 return 1
141 }
142
143
144 install_docker() {
145 echo "Docker is not installed, you will need to install Docker in order to run Launcher"
146 echo "See https://docs.docker.com/installation/"
147 exit 1
148 }
149
150 pull_image() {
151 # Add a single retry to work around dockerhub TLS errors
152 $docker_path pull $image || $docker_path pull $image
153 }
154
155 check_prereqs() {
156
157 if [ -z $docker_path ]; then
158 install_docker
159 fi
160
161 # 1. docker daemon running?
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`
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
170 # 2. running an approved storage driver?
171 if ! $docker_path info 2> /dev/null | egrep -q 'Storage Driver: (aufs|zfs|overlay2)$'; then
172 echo "Your Docker installation is not using a supported storage driver. If we were to proceed you may have a broken install."
173 echo "overlay2 is the recommended storage driver, although zfs and aufs may work as well."
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."
176 echo
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."
179 exit 1
180 fi
181
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
185
186 # At least minimum docker version
187 if compare_version "${docker_min_version}" "${test}"; then
188 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
189 exit 1
190 fi
191
192 # Recommend newer docker version
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
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
207
208 pull_image
209 fi
210
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
227 test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
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
234
235 # 7. enough space for the bootstrap on docker folder
236 folder=`$docker_path info --format '{{.DockerRootDir}}'`
237 safe_folder=${folder:-/var/lib/docker}
238 test=$(($(stat -f --format="%a*%S" $safe_folder)/1024**3 < 5))
239 if [[ $test -ne 0 ]] ; then
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
242 echo
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
248 $docker_path container prune --force --filter until=1h >/dev/null
249 $docker_path image prune --all --force --filter until=1h >/dev/null
250 echo "If the cleanup was successful, you may try again now"
251 fi
252 fi
253 exit 1
254 fi
255 }
256
257
258 if [ -z "$SKIP_PREREQS" ] && [ "$command" != "cleanup" ]; then
259 check_prereqs
260 fi
261
262 host_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
278 RUBY
279
280 host_run=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e "$env_ruby"`
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
293 set_volumes() {
294 volumes=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
295 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
296 }
297
298 set_links() {
299 links=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
300 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
301 }
302
303 find_templates() {
304 local templates=`cat $1 | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
305 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
306
307 local arrTemplates=${templates// / }
308
309 if [ ! -z "$templates" ]; then
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
325 set_template_info() {
326 templates=$(find_templates $config_file)
327
328 arrTemplates=(${templates// / })
329 config_data=$(cat $config_file)
330
331 input="hack: true"
332
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
347 # default to UTF-8 for the dbs sake
348 env = {'LANG' => 'en_US.UTF-8'}
349 input.split('_FILE_SEPERATOR_').each do |yml|
350 yml.strip!
351 begin
352 env.merge!(YAML.load(yml)['env'] || {})
353 rescue Psych::SyntaxError => e
354 puts e
355 puts "*ERROR."
356 rescue => e
357 puts yml
358 p e
359 end
360 end
361 env.each{|k,v| puts "*ERROR." if v.is_a?(Hash)}
362 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
363 RUBY
364
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"
371
372 env=()
373 ok=1
374 while read i; do
375 if [ "$i" == "*ERROR." ]; then
376 ok=0
377 elif [ -n "$i" ]; then
378 env[${#env[@]}]="${i//\{\{config\}\}/${config}}"
379 fi
380 done <<< "$raw"
381
382 if [ "$ok" -ne 1 ]; then
383 echo "${env[@]}"
384 echo "YAML syntax error. Please check your containers/*.yml config files."
385 exit 1
386 fi
387
388 # labels
389 read -r -d '' labels_ruby << 'RUBY'
390 require 'yaml'
391
392 input=STDIN.readlines.join
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")
407 RUBY
408
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"
415
416 labels=()
417 ok=1
418 while read i; do
419 if [ "$i" == "*ERROR." ]; then
420 ok=0
421 elif [ -n "$i" ]; then
422 labels[${#labels[@]}]=$(echo $i | sed s/{{config}}/${config}/g)
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
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
450 puts ports.map { |p| p.to_s.include?(':') ? "-p\n#{p}" : "--expose\n#{p}" }.join("\n")
451 RUBY
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
475
476 merge_user_args
477 }
478
479 if [ -z $docker_path ]; then
480 install_docker
481 fi
482
483 [ "$command" == "cleanup" ] && {
484 $docker_path container prune --filter until=1h
485 $docker_path image prune --all --filter until=1h
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..."
494 rm -rf /var/discourse/shared/standalone/postgres_data_old*
495 else
496 exit 1
497 fi
498 fi
499
500 exit 0
501 }
502
503 if [ ! "$command" == "setup" ]; then
504 if [[ ! -e $config_file ]]; then
505 echo "Config file was not found, ensure $config_file exists"
506 echo
507 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
508 exit 1
509 fi
510 fi
511
512 docker_version=($($docker_path --version))
513 docker_version=${test[2]//,/}
514 restart_policy=${restart_policy:---restart=always}
515
516 set_existing_container(){
517 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
518 }
519
520 run_stop() {
521
522 set_existing_container
523
524 if [ ! -z $existing ]
525 then
526 (
527 set -x
528 $docker_path stop -t 10 $config
529 )
530 else
531 echo "$config was not started !"
532 echo "./discourse-doctor may help diagnose the problem."
533 exit 1
534 fi
535 }
536
537 set_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
541 if [ -n "$user_run_image" ]; then
542 run_image=$user_run_image
543 elif [ -z "$run_image" ]; then
544 run_image="$local_discourse/$config"
545 fi
546 }
547
548 set_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
563 merge_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
570 user_args="$user_args_argv $docker_args"
571 fi
572 }
573
574 run_start() {
575
576 if [ -z "$START_CMD_ONLY" ]
577 then
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
585
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
596 fi
597
598 host_run
599
600 set_template_info
601 set_volumes
602 set_links
603 set_run_image
604 set_boot_command
605
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
616 (
617 hostname=`hostname -s`
618 # overwrite hostname
619 if [ "$DOCKER_USE_HOSTNAME" = "true" ]
620 then
621 hostname=$DISCOURSE_HOSTNAME
622 else
623 hostname=$hostname-$config
624 fi
625
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
629 hostname=${hostname//_/-}
630
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
635
636 if [ ! -z "$START_CMD_ONLY" ] ; then
637 docker_path="true"
638 fi
639
640 set -x
641
642 $docker_path run --shm-size=512m $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
643 -e DOCKER_HOST_IP="$docker_ip" --name $config -t "${ports[@]}" $volumes $mac_address $user_args \
644 $run_image $boot_command
645
646 )
647 exit 0
648
649 }
650
651 run_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
666 run_bootstrap() {
667 host_run
668
669 # Is the image available?
670 # If not, pull it here so the user is aware what's happening.
671 $docker_path history $image >/dev/null 2>&1 || pull_image
672
673 set_template_info
674
675 base_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
676 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
677
678 update_pups=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
679 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
680
681 if [[ ! X"" = X"$base_image" ]]; then
682 image=$base_image
683 fi
684
685 set_volumes
686 set_links
687
688 rm -f $cidbootstrap
689
690 run_command="cd /pups &&"
691 if [[ ! "false" = $update_pups ]]; then
692 run_command="$run_command git pull &&"
693 fi
694 run_command="$run_command /pups/bin/pups --stdin"
695
696 echo $run_command
697
698 unset ERR
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 \
704 /bin/bash -c "$run_command") || ERR=$?
705
706 rm -f "$tmp_input_file"
707
708 unset FAILED
709 # magic exit code that indicates a retry
710 if [[ "$ERR" == 77 ]]; then
711 $docker_path rm `cat $cidbootstrap`
712 rm $cidbootstrap
713 exit 77
714 elif [[ "$ERR" > 0 ]]; then
715 FAILED=TRUE
716 fi
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
723
724 $docker_path rm `cat $cidbootstrap`
725 rm $cidbootstrap
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."
728 exit 1
729 fi
730
731 sleep 5
732
733 $docker_path commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
734 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
735 }
736
737 case "$command" in
738 bootstrap)
739 run_bootstrap
740 echo "Successfully bootstrapped, to startup use ./launcher start $config"
741 exit 0
742 ;;
743
744 run)
745 run_run
746 exit 0
747 ;;
748
749 enter)
750 exec $docker_path exec -it $config /bin/bash --login
751 ;;
752
753 stop)
754 run_stop
755 exit 0
756 ;;
757
758 logs)
759
760 $docker_path logs $config
761 exit 0
762 ;;
763
764 restart)
765 run_stop
766 run_start
767 exit 0
768 ;;
769
770 start-cmd)
771 START_CMD_ONLY="1"
772 run_start
773 exit 0;
774 ;;
775
776 start)
777 run_start
778 exit 0
779 ;;
780
781 rebuild)
782 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
783 echo "Ensuring launcher is up to date"
784
785 git remote update
786
787 LOCAL=$(git rev-parse HEAD)
788 REMOTE=$(git rev-parse @{u})
789 BASE=$(git merge-base HEAD @{u})
790
791 if [ $LOCAL = $REMOTE ]; then
792 echo "Launcher is up-to-date"
793
794 elif [ $LOCAL = $BASE ]; then
795 echo "Updating Launcher..."
796 git pull || (echo 'failed to update' && exit 1)
797
798 echo "Launcher updated, restarting..."
799 exec "$0" "${SAVED_ARGV[@]}"
800
801 elif [ $REMOTE = $BASE ]; then
802 echo "Your version of Launcher is ahead of origin"
803
804 else
805 echo "Launcher has diverged source, this is only expected in Dev mode"
806 fi
807
808 fi
809
810 set_existing_container
811
812 if [ ! -z $existing ]
813 then
814 echo "Stopping old container"
815 (
816 set -x
817 $docker_path stop -t 60 $config
818 )
819 fi
820
821 run_bootstrap
822
823 if [ ! -z $existing ]
824 then
825 echo "Removing old container"
826 (
827 set -x
828 $docker_path rm $config
829 )
830 fi
831
832 run_start
833 exit 0
834 ;;
835
836
837 destroy)
838 (set -x; $docker_path stop -t 10 $config && $docker_path rm $config) || (echo "$config was not found" && exit 0)
839 exit 0
840 ;;
841 esac
842
843 usage