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