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