better name for prereq check
[discourse_docker.git] / launcher
CommitLineData
ace450bd 1#!/bin/bash
7e738616 2
5cb39519 3usage () {
1f656469 4 echo "Usage: launcher COMMAND CONFIG [--skip-prereqs] [--skip-discourse-prereqs] [--docker-args STRING]"
5cb39519
JA
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: Use nsenter to enter a container"
11 echo " logs: Docker logs for container"
12 echo " bootstrap: Bootstrap a container for the config based on a template"
13 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
14 echo " cleanup: Remove all containers that have stopped for > 24 hours"
87c4f221 15 echo " setup: Create a new configuration file and bootstrap"
5cb39519
JA
16 echo
17 echo "Options:"
1f656469
GXT
18 echo " --skip-prereqs Don't check launcher prerequisites"
19 echo " --skip-discourse-prereqs Don't check prerequisites specifiy to Discourse"
20 echo " --docker-args Extra arguments to pass when running docker"
5cb39519
JA
21 exit 1
22}
23
1f656469 24
7e738616
S
25command=$1
26config=$2
1f656469
GXT
27shift 2
28user_args=""
29
87c4f221
JA
30[ $# -lt 2 ] && {
31 usage
32}
33
1f656469 34while [ ${#} -gt 0 ]; do
87c4f221 35 case "$command" in
1f656469
GXT
36
37 --skip-prereqs)
38 SKIP_PREREQ="1"
39 ;;
40 --skip-discourse-prereqs)
41 SKIP_DISCOURSE_PREREQS="1"
42 ;;
43 --docker-args)
44 user_args="$2"
45 shift
46 ;;
47 *)
48 echo "Unknown options '${1}'"
49 usage
50 ;;
51 esac
52
53 shift 1
54done
55d17203 55
87756d6d
EH
56# Docker doesn't like uppercase characters, spaces or special characters, catch it now before we build everything out and then find out
57re='[A-Z/ !@#$%^&*()+~`=]'
58if [[ $config =~ $re ]];
59 then
8877f99e 60 echo
87756d6d
EH
61 echo "ERROR: Config name must not contain upper case characters, spaces or special characters. Correct config name and rerun $0."
62 echo
63 exit 1
64fi
65
7936ebaa 66cd "$(dirname "$0")"
55d17203 67
478e03e2
S
68docker_min_version='1.6.0'
69docker_rec_version='1.6.0'
6828238a
JP
70git_min_version='1.8.0'
71git_rec_version='1.8.0'
60668406 72
8dea575c 73config_file=containers/"$config".yml
5201a40c 74cidbootstrap=cids/"$config"_bootstrap.cid
5efded6a 75local_discourse=local_discourse
fecfcdcf 76image=discourse/discourse:1.0.17
4807b1b8 77docker_path=`which docker.io || which docker`
6828238a 78git_path=`which git`
55e2de5d 79template_path=samples/standalone.yml
f8c887b6 80changelog=/tmp/changelog # used to test whether sed did anything
8877f99e 81
e0fd1f5b
TB
82if [ "${SUPERVISED}" = "true" ]; then
83 restart_policy="--restart=no"
84 attach_on_start="-a"
85 attach_on_run="-a stdout -a stderr"
86else
87 attach_on_run="-d"
88fi
89
f2a3edee
AY
90if [ -n "$DOCKER_HOST" ]; then
91 docker_ip=`sed -e 's/^tcp:\/\/\(.*\):.*$/\1/' <<< "$DOCKER_HOST"`
92elif [ -x "$(which ip 2>/dev/null)" ]; then
813fef38 93 docker_ip=`ip addr show docker0 | \
03bb0735
LG
94 grep 'inet ' | \
95 awk '{ split($2,a,"/"); print a[1] }';`
96else
813fef38 97 docker_ip=`ifconfig | \
03bb0735
LG
98 grep -B1 "inet addr" | \
99 awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
100 grep docker0 | \
101 awk -F: '{ print $3 }';`
102fi
80c11be3 103
60668406
DP
104compare_version() {
105 declare -a ver_a
106 declare -a ver_b
107 IFS=. read -a ver_a <<< "$1"
108 IFS=. read -a ver_b <<< "$2"
109
110 while [[ -n $ver_a ]]; do
111 if (( ver_a > ver_b )); then
112 return 0
113 elif (( ver_b > ver_a )); then
114 return 1
115 else
116 unset ver_a[0]
117 ver_a=("${ver_a[@]}")
118 unset ver_b[0]
119 ver_b=("${ver_b[@]}")
120 fi
121 done
122 return 1 # They are equal
123}
124
665468eb
JA
125
126install_docker() {
127
128 echo "Docker is not installed, you will need to install Docker in order to run Discourse"
129 echo "Please visit https://docs.docker.com/installation/ for instructions on how to do this for your system"
130 echo
131 echo "If you are running a recent Ubuntu Server, try the following:"
132 echo "sudo apt-get install docker-engine"
133
134 exit 1
135}
136
87c4f221 137check_prereqs() {
794e44d5
GXT
138
139 if [ -z $docker_path ]; then
665468eb
JA
140 install_docker
141 fi
a3e18d95 142
e741295a 143 # 1. docker daemon running?
30835a52
S
144 # we send stderr to /dev/null cause we don't care about warnings,
145 # it usually complains about swap which does not matter
146 test=`$docker_path info 2> /dev/null`
e741295a
MB
147 if [[ $? -ne 0 ]] ; then
148 echo "Cannot connect to the docker daemon - verify it is running and you have access"
149 exit 1
150 fi
151
185e78c6
S
152 # 2. running aufs or btrfs
153 test=`$docker_path info 2> /dev/null | grep 'Driver: '`
48f22d14
S
154 if [[ "$test" =~ [aufs|btrfs|zfs|overlay] ]] ; then : ; else
155 echo "Your Docker installation is not using a supported filesystem if we were to proceed you may have a broken install."
156 echo "aufs is the recommended filesystem you should be using (zfs/btrfs and overlay may work as well)"
157 echo "You can tell what filesystem you are using by running \"docker info\" and looking at the driver"
5dfdf9a3
JA
158 echo
159 echo "If you wish to continue anyway using your existing unsupported filesystem, "
48f22d14
S
160 echo "read the source code of launcher and figure out how to bypass this."
161 exit 1
a3e18d95
S
162 fi
163
60668406
DP
164 # 3. running recommended docker version
165 test=($($docker_path --version)) # Get docker version string
166 test=${test[2]//,/} # Get version alone and strip comma if exists
a3e18d95 167
87c4f221 168 # At least minimum docker version
cf00fce0 169 if compare_version "${docker_min_version}" "${test}"; then
60668406 170 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
a3e18d95
S
171 exit 1
172 fi
173
87c4f221 174 # Recommend newer docker version
60668406
DP
175 if compare_version "${docker_rec_version}" "${test}"; then
176 echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
177 fi
178
405948ee
S
179 # 4. discourse docker image is downloaded
180 test=`$docker_path images | awk '{print $1 ":" $2 }' | grep "$image"`
181
182 if [ -z "$test" ]; then
183 echo
184 echo "WARNING: We are about to start downloading the Discourse base image"
185 echo "This process may take anywhere between a few minutes to an hour, depending on your network speed"
186 echo
187 echo "Please be patient"
188 echo
189
190 fi
405948ee 191
6828238a
JP
192 # 5. running recommended git version
193 test=($($git_path --version)) # Get git version string
194 test=${test[2]//,/} # Get version alone and strip comma if exists
195
196 # At least minimum version
197 if compare_version "${git_min_version}" "${test}"; then
198 echo "ERROR: Git version ${test} not supported, please upgrade to at least ${git_min_version}, or recommended ${git_rec_version}"
199 exit 1
200 fi
201
202 # Recommend best version
203 if compare_version "${git_rec_version}" "${test}"; then
204 echo "WARNING: Git version ${test} deprecated, recommend upgrade to ${git_rec_version} or newer."
205 fi
206
207 # 6. able to attach stderr / out / tty
e02c1511 208 test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
a3e18d95
S
209 if [[ "$test" =~ "working" ]] ; then : ; else
210 echo "Your Docker installation is not working correctly"
211 echo
212 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
213 exit 1
214 fi
4770834b 215
6e784be6
MP
216}
217
6828238a
JP
218
219
6e784be6
MP
220check_resources() {
221 # Memory
a752d8ea 222 resources="ok"
794e44d5 223 avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
a752d8ea
MP
224 if [ "$avail_mem" -lt 900 ]; then
225 resources="insufficient"
226 echo "WARNING: You do not appear to have sufficient memory to run Discourse."
227 echo
228 echo "Your system may not work properly, or future upgrades of Discourse may"
229 echo "not complete successfully."
b3f0d057
MP
230 echo
231 echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#create-new-cloud-server"
a752d8ea 232 elif [ "$avail_mem" -lt 1800 ]; then
b3f0d057
MP
233 total_swap="$(LANG=C free -m | grep ^Swap: | awk '{print $2}')"
234 if [ "$total_swap" -lt 1000 ]; then
efd8ae0f 235 resources="insufficient"
a752d8ea
MP
236 echo "WARNING: You must have at least 1GB of swap when running with less"
237 echo "than 2GB of RAM."
238 echo
239 echo "Your system may not work properly, or future upgrades of Discourse may"
240 echo "not complete successfully."
b3f0d057
MP
241 echo
242 echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#set-up-swap-if-needed"
b3f0d057
MP
243 fi
244 fi
4770834b 245
6e784be6 246 # Disk space
4770834b
MP
247 free_disk="$(df /var | tail -n 1 | awk '{print $4}')"
248 if [ "$free_disk" -lt 5000 ]; then
a752d8ea
MP
249 resources="insufficient"
250 echo "WARNING: You must have at least 5GB of *free* disk space to run Discourse."
251 echo
252 echo "Insufficient disk space may result in problems running your site, and may"
253 echo "not even allow Discourse installation to complete successfully."
4770834b
MP
254 echo
255 echo "Please free up some space, or expand your disk, before continuing."
794e44d5
GXT
256 echo
257 echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused packages and \`./launcher cleanup\` to remove stale Docker containers."
4770834b
MP
258 exit 1
259 fi
a752d8ea
MP
260
261 if [ -t 0 ] && [ "$resources" != "ok" ]; then
262 echo
263 read -p "Press ENTER to continue, or Ctrl-C to exit and give your system more resources"
264 fi
a3e18d95
S
265}
266
c574dbda
GXT
267check_ports() {
268 local valid=$(netstat -tln | awk '{print $4}' | grep ":${1}\$")
269
270 if [ -n "$valid" ]; then
271 echo "Launcher has detected that port ${1} is in use."
5dfdf9a3 272 echo
c574dbda
GXT
273 echo "If you are trying to run Discourse simultaneously with another web server like Apache or nginx, you will need to bind to a different port."
274 echo "See https://meta.discourse.org/t/17247 for help."
1410a21f 275 echo "To continue anyway, re-run Launcher with --skip-prereqs"
c574dbda
GXT
276 exit 1
277 fi
278}
279
1f656469 280if [ -z "$SKIP_PREREQS" ] ; then
87c4f221 281 check_prereqs
55d17203 282fi
a3e18d95 283
60f9f04c
S
284host_run() {
285 read -r -d '' env_ruby << 'RUBY'
286 require 'yaml'
287
288 input = STDIN.readlines.join
289 yaml = YAML.load(input)
290
291 if host_run = yaml['host_run']
292 params = yaml['params'] || {}
293 host_run.each do |run|
294 params.each do |k,v|
295 run = run.gsub("$#{k}", v)
296 end
297 STDOUT.write "#{run}--SEP--"
298 end
299 end
300RUBY
301
e02c1511 302 host_run=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e "$env_ruby"`
60f9f04c
S
303
304 while [ "$host_run" ] ; do
305 iter=${host_run%%--SEP--*}
306 echo
307 echo "Host run: $iter"
308 $iter || exit 1
309 echo
310 host_run="${host_run#*--SEP--}"
311 done
312}
313
314
d90671f3 315set_volumes() {
e02c1511 316 volumes=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
d90671f3
SS
317 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
318}
319
41daa523 320set_links() {
e02c1511 321 links=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
41daa523 322 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
323}
324
7f77c274
SS
325set_template_info() {
326
e02c1511 327 templates=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
7f77c274
SS
328 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
329
7f77c274
SS
330 arrTemplates=(${templates// / })
331 config_data=$(cat $config_file)
332
333 input="hack: true"
334
7f77c274
SS
335 for template in "${arrTemplates[@]}"
336 do
337 [ ! -z $template ] && {
338 input="$input _FILE_SEPERATOR_ $(cat $template)"
339 }
340 done
341
342 # we always want our config file last so it takes priority
343 input="$input _FILE_SEPERATOR_ $config_data"
344
345 read -r -d '' env_ruby << 'RUBY'
346 require 'yaml'
347
348 input=STDIN.readlines.join
3cb3d9c4
S
349 # default to UTF-8 for the dbs sake
350 env = {'LANG' => 'en_US.UTF-8'}
7f77c274
SS
351 input.split('_FILE_SEPERATOR_').each do |yml|
352 yml.strip!
353 begin
354 env.merge!(YAML.load(yml)['env'] || {})
f3824347 355 rescue Psych::SyntaxError => e
356 puts e
357 puts "*ERROR."
7f77c274
SS
358 rescue => e
359 puts yml
360 p e
361 end
362 end
4b563ee8 363 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
7f77c274
SS
364RUBY
365
e02c1511 366 raw=`exec echo "$input" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
4b563ee8
SS
367
368 env=()
f3824347 369 ok=1
4b563ee8 370 while read i; do
f3824347 371 if [ "$i" == "*ERROR." ]; then
372 ok=0
373 elif [ -n "$i" ]; then
16f2d250
S
374 env[${#env[@]}]=$i
375 fi
4b563ee8
SS
376 done <<< "$raw"
377
f3824347 378 if [ "$ok" -ne 1 ]; then
379 echo "${env[@]}"
d6d1fb6e 380 echo "YAML syntax error. Please check your /var/discourse/containers/*.yml config files."
f3824347 381 exit 1
382 fi
7f77c274
SS
383}
384
665468eb 385if [ -z $docker_path ]; then
52388b87 386 install_docker
665468eb 387fi
52388b87 388
de869404 389[ "$command" == "cleanup" ] && {
c692f743
L
390 echo
391 echo "The following command will"
392 echo "- Delete all docker images for old containers"
393 echo "- Delete all stopped and orphan containers"
394 echo
395 read -p "Are you sure (Y/n): " -n 1 -r && echo
396 if [[ $REPLY =~ ^[Yy]$ || ! $REPLY ]]
397 then
30835a52 398 space=$(df /var/lib/docker | awk '{ print $4 }' | grep -v Available)
29a35d1b 399 echo "Starting Cleanup (bytes free $space)"
30835a52 400
29a35d1b 401 STATE_DIR=./.gc-state scripts/docker-gc
30835a52 402
29a35d1b
S
403 space=$(df /var/lib/docker | awk '{ print $4 }' | grep -v Available)
404 echo "Finished Cleanup (bytes free $space)"
30835a52 405
c692f743 406 else
30835a52 407 exit 1
c692f743 408 fi
a8b66f98
L
409 exit 0
410}
5f803fb4 411
f72ab68a 412if [[ ! -e $config_file ]]
7e738616
S
413 then
414 echo "Config file was not found, ensure $config_file exists"
5dfdf9a3 415 echo
71680b16 416 echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
7e738616
S
417 exit 1
418fi
419
e2ed1fb6
S
420docker_version=($($docker_path --version))
421docker_version=${test[2]//,/}
69545efd 422restart_policy=${restart_policy:---restart=always}
e2ed1fb6 423
30835a52 424set_existing_container(){
295e8f19 425 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
337a89aa
S
426}
427
665468eb 428run_stop() {
337a89aa 429
30835a52 430 set_existing_container
60f9f04c 431
30835a52 432 if [ ! -z $existing ]
337a89aa 433 then
30835a52
S
434 (
435 set -x
436 $docker_path stop -t 10 $config
437 )
337a89aa 438 else
30835a52
S
439 echo "$config was not started !"
440 exit 1
441 fi
442}
337a89aa 443
8877f99e
S
444set_run_image() {
445 run_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
446 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['run_image']"`
447
448 if [ -z "$run_image" ]; then
449 run_image="$local_discourse/$config"
450 fi
451}
452
453set_boot_command() {
454 boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
455 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['boot_command']"`
456
457 if [ -z "$boot_command" ]; then
458
459 no_boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
460 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['no_boot_command']"`
461
462 if [ -z "$no_boot_command" ]; then
463 boot_command="/sbin/boot"
464 fi
465 fi
466}
467
5cb39519 468scale_ram_and_cpu() {
f8c887b6 469
5dfdf9a3 470 # grab info about total system ram and physical (NOT LOGICAL!) CPU cores
f8c887b6 471 avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
5dfdf9a3
JA
472 avail_gb=$(( $avail_mem / 950 ))
473 avail_cores=`cat /proc/cpuinfo | grep "cpu cores" | uniq | awk '{print $4}'`
474 echo "Found ${avail_gb}GB of memory and $avail_cores physical CPU cores"
f8c887b6 475
5dfdf9a3 476 # db_shared_buffers: 128MB for 1GB, 256MB for 2GB, or 256MB * GB, max 4096MB
f8c887b6
JP
477 if [ "$avail_gb" -eq "1" ]
478 then
5dfdf9a3 479 db_shared_buffers=128
f8c887b6 480 else
5dfdf9a3
JA
481 if [ "$avail_gb" -eq "2" ]
482 then
483 db_shared_buffers=256
484 else
485 db_shared_buffers=$(( 256 * $avail_gb ))
486 fi
794e44d5 487 fi
5dfdf9a3 488 db_shared_buffers=$(( db_shared_buffers < 4096 ? db_shared_buffers : 4096 ))
f72ab68a 489
5cb39519 490 sed -i -e "s/^ #db_shared_buffers:.*/ db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $config_file
f8c887b6
JP
491 if [ -s $changelog ]
492 then
5cb39519 493 echo "setting db_shared_buffers = ${db_shared_buffers}MB based on detected CPU/RAM"
f8c887b6 494 rm $changelog
f8c887b6 495 fi
794e44d5 496
f8c887b6 497
5dfdf9a3 498 # UNICORN_WORKERS: 2 * GB for 2GB or less, or 2 * CPU, max 8
f8c887b6
JP
499 if [ "$avail_gb" -le "2" ]
500 then
5dfdf9a3 501 unicorn_workers=$(( 2 * $avail_gb ))
f8c887b6 502 else
5dfdf9a3 503 unicorn_workers=$(( 2 * $avail_cores ))
f8c887b6 504 fi
5dfdf9a3 505 unicorn_workers=$(( unicorn_workers < 8 ? unicorn_workers : 8 ))
f72ab68a 506
55e2de5d 507 sed -i -e "s/^ #UNICORN_WORKERS:.*/ UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
f8c887b6
JP
508 if [ -s $changelog ]
509 then
5cb39519 510 echo "setting UNICORN_WORKERS = ${unicorn_workers} based on detected CPU/RAM"
794e44d5 511 rm $changelog
f8c887b6 512 fi
794e44d5 513
f8c887b6
JP
514}
515
1d8470dd 516set_config() {
849ea5b1 517 if [ -f $config_file ]
1d8470dd 518 then
849ea5b1
JP
519 echo $config_file exists already.
520 echo To remove it use: rm $config_file
521 exit 1
1d8470dd 522 fi
849ea5b1
JP
523 cp ./samples/standalone.yml $config_file
524 if [ ! -f $config_file ]
1d8470dd 525 then
849ea5b1
JP
526 echo Unable to copy $config_file. Are you root?
527 exit 1
1d8470dd 528 fi
1d8470dd 529
849ea5b1
JP
530 local hostname="discourse.example.com"
531 local developer_emails="me@example.com"
532 local smtp_address="smtp.example.com"
533 local smtp_user_name="user@example.com"
534 local smtp_password="pa\$\$word"
535 local letsencrypt_account_email="your.email@example.com"
536 local letsencrypt_status="change to enable"
537
1d8470dd
JP
538 local new_value=""
539 local letsencrypt_status="change to enable"
f017e88c
JP
540 local config_sane="n"
541 local config_ok="n"
542 local update_ok="y"
849ea5b1 543
f017e88c 544 while [[ "$config_ok" == "n" || "$config_sane" == "n" ]]
1d8470dd 545 do
1d8470dd
JP
546 if [ ! -z $hostname ]
547 then
548 read -p "hostname: [$hostname]: " new_value
549 if [ ! -z $new_value ]
550 then
551 hostname=$new_value
552 else
553 echo "Unchanged."
554 fi
555 fi
556 if [ ! -z $developer_emails ]
557 then
558 read -p "developer_emails [$developer_emails]: " new_value
559 if [ ! -z $new_value ]
560 then
561 developer_emails=$new_value
562 fi
563 fi
564 if [ ! -z $smtp_address ]
565 then
566 read -p "smtp_address [$smtp_address]: " new_value
567 if [ ! -z $new_value ]
568 then
569 smtp_address=$new_value
570 fi
571 fi
f017e88c
JP
572 if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
573 then
574 smtp_user_name="SMTP_Injection"
575
576 fi
577 if [ "$smtp_address" == "smtp.sendgrid.net" ]
578 then
579 smtp_user_name="apikey"
580 fi
1d8470dd
JP
581 if [ ! -z $smtp_user_name ]
582 then
583 read -p "smtp_user_name [$smtp_user_name]: " new_value
584 if [ ! -z $new_value ]
585 then
586 smtp_user_name=$new_value
587 fi
588 fi
589 if [ ! -z $smtp_password ]
590 then
591 read -p "smtp_password [$smtp_password]: " new_value
592 if [ ! -z $new_value ]
593 then
594 smtp_password=$new_value
595 fi
596 fi
597 if [ ! -z $letsencrypt_account_email ]
598 then
599 read -p "letsencrypt_account_email ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
600 if [ ! -z $new_value ]
601 then
f017e88c
JP
602 letsencrypt_account_email=$new_value
603 if [ "$new_value" == "off" ]
604 then
605 letsencrypt_status="change to enable"
606 else
607 letsencrypt_status="Enter 'OFF' to disable."
608 echo "Letsencrypt enabled."
609 fi
1d8470dd
JP
610 else
611 echo "letsencrypt unchanged"
612 fi
613 fi
614
f017e88c
JP
615 #TODO sanity check these values. For now we trust the user's input.
616 config_sane="y"
617
618 if [ "$config_sane" == "y" ]
619 then
849ea5b1 620 echo -e "\nThat's it! Everything is set. Read carefully before continuing.\n"
f017e88c
JP
621 else
622 echo "Errors found in settings"
623 fi
1d8470dd
JP
624
625 echo "DISCOURSE_HOSTNAME: $hostname"
626 echo "DISCOURSE_DEVELOPER_EMAILS: $developer_emails"
627 echo "DISCOURSE_SMTP_ADDRESS: $smtp_address"
628 echo "DISCOURSE_SMTP_USER_NAME: $smtp_user_name"
629 echo "DISCOURSE_SMTP_PASSWORD: $smtp_password"
f017e88c 630 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
1d8470dd 631 then
f017e88c
JP
632 echo "LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email"
633 echo "LETSENCRYPT will be enabled."
1d8470dd 634 else
f017e88c 635 echo "LETSENCRYPT will not be enabled."
1d8470dd
JP
636 fi
637 echo
f017e88c 638 read -p "Enter to write these settings to $config_file, 'N' to retry, or ^C to start again: " config_ok
1d8470dd
JP
639 done
640
f017e88c
JP
641 echo -e "\nWriting changes to $config_file:"
642 sed -i -e "s/^ DISCOURSE_HOSTNAME: 'discourse.example.com'/ DISCOURSE_HOSTNAME: $hostname/w $changelog" $config_file
643 if [ -s $changelog ]
644 then
645 cat $changelog
646 rm $changelog
647 else
648 echo DISCOURSE_HOSTNAME change failed.
649 update_ok="n"
650 fi
1d8470dd 651
f017e88c
JP
652 sed -i -e "s/^ DISCOURSE_DEVELOPER_EMAILS:.*/ DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $config_file
653 if [ -s $changelog ]
1d8470dd 654 then
f017e88c
JP
655 cat $changelog
656 rm $changelog
657 else
658 echo DISCOURSE_DEVELOPER_EMAILS change failed.
659 update_ok="n"
1d8470dd 660 fi
f017e88c
JP
661
662 sed -i -e "s/^ DISCOURSE_SMTP_ADDRESS: smtp.example.com.*/ DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $config_file
663 if [ -s $changelog ]
664 then
665 cat $changelog
666 rm $changelog
667 else
668 echo DISCOURSE_SMTP_ADDRESS change failed.
669 update_ok="n"
670 fi
671
672 sed -i -e "s/^ #DISCOURSE_SMTP_USER_NAME: user@example.com.*/ DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $config_file
673 if [ -s $changelog ]
674 then
675 cat $changelog
676 rm $changelog
677 else
678 echo DISCOURSE_SMTP_USER_NAME change failed.
679 update_ok="n"
680 fi
681
682 sed -i -e "s/^ #DISCOURSE_SMTP_PASSWORD: pa\$\$word.*/ DISCOURSE_SMTP_PASSWORD: $smtp_password/w $changelog" $config_file
683 if [ -s $changelog ]
684 then
685 cat $changelog
686 rm $changelog
687 else
688 echo DISCOURSE_SMTP_PASSWORD change failed.
689 update_ok="n"
690 fi
691
692 if [ "$letsencrypt_status" != "change to enable" ]
693 then
694 sed -i -e "s/^ #LETSENCRYPT_ACCOUNT_EMAIL: your.email@example.com/ LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $config_file
695 if [ -s $changelog ]
696 then
697 cat $changelog
698 rm $changelog
699 else
700 echo LETSENCRYPT_ACCOUNT_EMAIL change failed.
701 update_ok="n"
702 fi
703 local src='^ #- "templates\/web.ssl.template.yml"'
704 local dst=' \- "templates\/web.ssl.template.yml"'
705 sed -i -e "s/$src/$dst/w $changelog" $config_file
706 if [ -s $changelog ]
707 then
708 echo " web.ssl.template.yml enabled"
709 else
710 update_ok="n"
711 echo " web.ssl.template.yml NOT ENABLED--was it on already?"
712 fi
713 local src='^ #- "templates\/web.letsencrypt.ssl.template.yml"'
714 local dst=' - "templates\/web.letsencrypt.ssl.template.yml"'
715
716 sed -i -e "s/$src/$dst/w $changelog" $config_file
717 if [ -s $changelog ]
718 then
719 echo " letsencrypt.ssl.template.yml enabled"
720 else
721 update_ok="n"
722 echo "letsencrypt.ssl.template.yml NOT ENABLED--was it on already?"
723 fi
724 fi # enable letsencrypt
725
726 if [ "$update_ok" == "y" ]
727 then
728 echo -e "\n$config_file updated successfully."
729 else
730 echo -e "There was an error changing the configuration.\n"
731 fi
1d8470dd
JP
732}
733
665468eb 734run_start() {
337a89aa 735
295e8f19
S
736 existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
737 echo $existing
30835a52
S
738 if [ ! -z $existing ]
739 then
740 echo "Nothing to do, your container has already started!"
eac33309 741 exit 0
30835a52
S
742 fi
743
295e8f19 744 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
30835a52
S
745 if [ ! -z $existing ]
746 then
747 echo "starting up existing container"
748 (
749 set -x
750 $docker_path start $config
751 )
752 exit 0
753 fi
754
755 host_run
1f656469
GXT
756
757 if [ -z "$SKIP_DISCOURSE_PREREQS" ] ; then
758 ports=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
c574dbda
GXT
759 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| \"-p #{p}\"}.join(' ')"`
760
1f656469
GXT
761 IFS='-p ' read -a array <<< "$ports"
762 for element in "${array[@]}"
763 do
c574dbda
GXT
764 IFS=':' read -a args <<< "$element"
765 if [ "${#args[@]}" == "2" ]; then
766 check_ports "${args[0]}"
767 elif [ "${#args[@]}" == "3" ]; then
768 check_ports "${args[1]}"
769 fi
1f656469
GXT
770 done
771 fi
30835a52 772
8b617e6e
PG
773 docker_args=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
774 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['docker_args']"`
775
30835a52
S
776 set_template_info
777 set_volumes
778 set_links
8877f99e
S
779 set_run_image
780 set_boot_command
30835a52 781
c6dd6f9d
FB
782 # get hostname and settings from container configuration
783 for envar in "${env[@]}"
784 do
785 if [[ $envar == DOCKER_USE_HOSTNAME* ]] || [[ $envar == DISCOURSE_HOSTNAME* ]]
786 then
787 # use as environment variable
788 eval $envar
789 fi
790 done
791
30835a52 792 (
c834fdd1 793 hostname=`hostname -s`
c6dd6f9d
FB
794 # overwrite hostname
795 if [ "$DOCKER_USE_HOSTNAME" = "true" ]
796 then
797 hostname=$DISCOURSE_HOSTNAME
798 else
799 hostname=$hostname-$config
800 fi
801
a0606001
S
802 # we got to normalize so we only have allowed strings, this is more comprehensive but lets see how bash does first
803 # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
804 # docker added more hostname rules
805 hostname=${hostname/_/-}
806
30835a52 807 set -x
c6dd6f9d 808 $docker_path run $user_args $links $attach_on_run $restart_policy "${env[@]}" -h "$hostname" \
c3c05144 809 -e DOCKER_HOST_IP=$docker_ip --name $config -t $ports $volumes $docker_args $run_image $boot_command
30835a52
S
810
811 )
812 exit 0
337a89aa
S
813
814}
815
665468eb 816valid_config_check() {
794e44d5 817
665468eb 818 valid_config="y"
1c915080
JA
819 for x in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
820 DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
ec8f8b83
JP
821 do
822 mail_var=`grep "^ $x:" $config_file`
5dfdf9a3
JA
823 local result=$?
824 local default="example.com"
ec8f8b83
JP
825 if (( result == 0 ))
826 then
5dfdf9a3 827 if [[ $mail_var = *"$default"* ]]
1c915080
JA
828 then
829 echo "Warning: $x left at incorrect default of example.com"
830 valid_config="n"
ec8f8b83
JP
831 fi
832 else
5dfdf9a3 833 echo "Warning: $x not configured"
1c915080 834 valid_config="n"
ec8f8b83
JP
835 fi
836 done
1c915080 837 if [ -t 0 ] && [ "$valid_config" != "y" ]; then
e93d165d
JA
838 echo
839 read -p "Press Ctrl-C to exit and edit $config_file or ENTER to continue"
ec8f8b83
JP
840 fi
841}
842
665468eb 843run_bootstrap() {
1f656469
GXT
844 if [ -z "$SKIP_DISCOURSE_PREREQS" ] ; then
845 # Does your system meet the minimum requirements?
846 check_resources
60f9f04c 847
1f656469
GXT
848 # is our configuration file valid?
849 valid_config_check
6e784be6 850
1f656469
GXT
851 # make minor scaling adjustments for RAM and CPU
852 scale_ram_and_cpu
853 fi
794e44d5 854
5dfdf9a3 855 # I got no frigging clue what this does, ask Sam Saffron. It RUNS STUFF ON THE HOST I GUESS?
60f9f04c
S
856 host_run
857
680dd4ea
S
858 # Is the image available?
859 # If not, pull it here so the user is aware what's happening.
4807b1b8 860 $docker_path history $image >/dev/null 2>&1 || $docker_path pull $image
88126eba 861
680dd4ea 862 set_template_info
93149421 863
e02c1511 864 base_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 865 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
93149421 866
e02c1511 867 update_pups=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 868 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
b9c7b50e 869
680dd4ea
S
870 if [[ ! X"" = X"$base_image" ]]; then
871 image=$base_image
872 fi
b9c7b50e 873
680dd4ea 874 set_volumes
41daa523 875 set_links
b9c7b50e 876
680dd4ea 877 rm -f $cidbootstrap
d90671f3 878
680dd4ea
S
879 run_command="cd /pups &&"
880 if [[ ! "false" = $update_pups ]]; then
881 run_command="$run_command git pull &&"
882 fi
883 run_command="$run_command /pups/bin/pups --stdin"
2162f1d4 884
680dd4ea 885 echo $run_command
b9c7b50e 886
e02c1511 887 (exec echo "$input" | $docker_path run $user_args $links "${env[@]}" -e DOCKER_HOST_IP=$docker_ip --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
680dd4ea 888 /bin/bash -c "$run_command") \
4807b1b8 889 || ($docker_path rm `cat $cidbootstrap` && rm $cidbootstrap)
88126eba 890
4b733d87 891 [ ! -e $cidbootstrap ] && echo "** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one" && exit 1
9fb5f2d3 892
680dd4ea 893 sleep 5
2162f1d4 894
4807b1b8
MB
895 $docker_path commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
896 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
680dd4ea 897}
9fb5f2d3 898
8877f99e
S
899
900
680dd4ea
S
901case "$command" in
902 bootstrap)
680dd4ea 903 run_bootstrap
2dd2e330 904 echo "Successfully bootstrapped, to startup use ./launcher start $config"
4b3aebe1 905 exit 0
5f803fb4 906 ;;
1acce9e4 907
849ea5b1
JP
908 setup)
909 set_config
910 read -p "Press ENTER to continue, or Ctrl-C to exit to check $config_file"
911 run_bootstrap
912 exit 0
913 ;;
914
2fc6ff36 915 enter)
0c456e8c 916 exec $docker_path exec -it $config /bin/bash --login
2fc6ff36
S
917 ;;
918
5f803fb4 919 stop)
337a89aa
S
920 run_stop
921 exit 0
5f803fb4 922 ;;
7e738616 923
5f803fb4 924 logs)
7e738616 925
30835a52
S
926 $docker_path logs $config
927 exit 0
5f803fb4 928 ;;
7e738616 929
337a89aa
S
930 restart)
931 run_stop
932 run_start
933 exit 0
934 ;;
80c11be3 935
337a89aa
S
936 start)
937 run_start
938 exit 0
5f803fb4 939 ;;
7e738616 940
680dd4ea 941 rebuild)
4b6456ef 942 if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
098533cb
S
943 echo "Ensuring discourse docker is up to date"
944
945 git remote update
946
947 LOCAL=$(git rev-parse @)
948 REMOTE=$(git rev-parse @{u})
949 BASE=$(git merge-base @ @{u})
950
951 if [ $LOCAL = $REMOTE ]; then
952 echo "Discourse Docker is up-to-date"
953
954 elif [ $LOCAL = $BASE ]; then
955 echo "Updating Discourse Docker"
956 git pull || (echo 'failed to update' && exit 1)
957 exec /bin/bash $0 $@
958
959 elif [ $REMOTE = $BASE ]; then
960 echo "Your version of Discourse Docker is ahead of origin"
961
962 else
905ec302 963 echo "Discourse Docker has diverged source, this is only expected in Dev mode"
098533cb
S
964 fi
965
4b6456ef 966 fi
30835a52
S
967
968 set_existing_container
969
970 if [ ! -z $existing ]
680dd4ea
S
971 then
972 echo "Stopping old container"
30835a52
S
973 (
974 set -x
975 $docker_path stop -t 10 $config
976 )
680dd4ea
S
977 fi
978
979 run_bootstrap
980
30835a52 981 if [ ! -z $existing ]
680dd4ea 982 then
30835a52
S
983 echo "Removing old container"
984 (
985 set -x
986 $docker_path rm $config
987 )
680dd4ea
S
988 fi
989
990 run_start
991 exit 0
992 ;;
993
7e738616 994
5f803fb4 995 destroy)
30835a52
S
996 (set -x; $docker_path stop -t 10 $config && $docker_path rm $config) || (echo "$config was not found" && exit 0)
997 exit 0
5f803fb4
SS
998 ;;
999esac
7e738616 1000
5f803fb4 1001usage