Merge branch 'runit-init' of https://github.com/Supermathie/discourse_docker
[discourse_docker.git] / launcher
CommitLineData
ace450bd 1#!/bin/bash
7e738616
S
2
3command=$1
4config=$2
55d17203
RW
5opt=$3
6
7936ebaa 7cd "$(dirname "$0")"
55d17203 8
60668406 9docker_min_version='0.9.1'
68f0b9dc 10docker_rec_version='0.11.1'
60668406 11
8dea575c 12config_file=containers/"$config".yml
7e738616 13cidfile=cids/"$config".cid
1acce9e4 14cidbootstrap=cids/"$config"_boostrap.cid
5efded6a 15local_discourse=local_discourse
23022c1d 16image=samsaffron/discourse:0.2.2
4807b1b8 17docker_path=`which docker.io || which docker`
7e738616 18
80c11be3
SS
19docker_ip=`/sbin/ifconfig | \
20 grep -B1 "inet addr" | \
21 awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
22 grep docker0 | \
23 awk -F: '{ print $3 }';`
24
25
5f803fb4 26usage () {
55d17203 27 echo "Usage: launcher COMMAND CONFIG [--skip-prereqs]"
7e738616 28 echo "Commands:"
1acce9e4
SS
29 echo " start: Start/initialize a container"
30 echo " stop: Stop a running container"
31 echo " restart: Restart a container"
32 echo " destroy: Stop and remove a container"
5f803fb4 33 echo " ssh: Start a bash shell in a running container"
1acce9e4 34 echo " logs: Docker logs for container"
7936ebaa 35 echo " mailtest: Test the mail settings in a container"
408a9c19 36 echo " bootstrap: Bootstrap a container for the config based on a template"
680dd4ea 37 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
55d17203
RW
38 echo
39 echo "Options:"
40 echo " --skip-prereqs Don't check prerequisites"
7e738616
S
41 exit 1
42}
43
60668406
DP
44compare_version() {
45 declare -a ver_a
46 declare -a ver_b
47 IFS=. read -a ver_a <<< "$1"
48 IFS=. read -a ver_b <<< "$2"
49
50 while [[ -n $ver_a ]]; do
51 if (( ver_a > ver_b )); then
52 return 0
53 elif (( ver_b > ver_a )); then
54 return 1
55 else
56 unset ver_a[0]
57 ver_a=("${ver_a[@]}")
58 unset ver_b[0]
59 ver_b=("${ver_b[@]}")
60 fi
61 done
62 return 1 # They are equal
63}
64
a3e18d95
S
65prereqs() {
66
e741295a 67 # 1. docker daemon running?
4807b1b8 68 test=`$docker_path info >/dev/null`
e741295a
MB
69
70 if [[ $? -ne 0 ]] ; then
71 echo "Cannot connect to the docker daemon - verify it is running and you have access"
72 exit 1
73 fi
74
2d7d1501 75 # 2. running aufs
4807b1b8 76 test=`$docker_path info 2> /dev/null | grep 'Driver: aufs'`
a3e18d95 77 if [[ "$test" =~ "aufs" ]] ; then : ; else
2d7d1501
S
78 echo "Your Docker installation is not using aufs, in the past we have had issues with it"
79 echo "If you are unable to bootstrap your image (or stop it) please report the issue at:"
80 echo "https://meta.discourse.org/t/discourse-docker-installation-without-aufs/15639"
a3e18d95
S
81 fi
82
60668406
DP
83 # 3. running recommended docker version
84 test=($($docker_path --version)) # Get docker version string
85 test=${test[2]//,/} # Get version alone and strip comma if exists
a3e18d95 86
cf00fce0
S
87 [[ "$test" =~ "0.12.0" ]] && echo "You are running a broken version of Docker, please upgrade ASAP. See: https://meta.discourse.org/t/the-installation-stopped-in-the-middle/16311/ for more details." && exit 1
88
60668406 89 # At least minimum version
cf00fce0 90 if compare_version "${docker_min_version}" "${test}"; then
60668406 91 echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
a3e18d95
S
92 exit 1
93 fi
94
60668406
DP
95 # Recommend best version
96 if compare_version "${docker_rec_version}" "${test}"; then
97 echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
98 fi
99
e741295a 100 # 4. able to attach stderr / out / tty
4807b1b8 101 test=`$docker_path run -i --rm -a stdout -a stderr $image echo working`
a3e18d95
S
102 if [[ "$test" =~ "working" ]] ; then : ; else
103 echo "Your Docker installation is not working correctly"
104 echo
105 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
106 exit 1
107 fi
108}
109
55d17203
RW
110if [ "$opt" != "--skip-prereqs" ] ; then
111 prereqs
112fi
a3e18d95 113
88126eba 114get_ssh_pub_key() {
9d28af0e
MB
115 if tty -s ; then
116 if [[ ! -e ~/.ssh/id_rsa.pub && ! -e ~/.ssh/id_dsa.pub ]] ; then
8aca5cb7
JA
117 echo "This user has no SSH key, but a SSH key is required to access the Discourse Docker container."
118 read -p "Generate a SSH key? (Y/n) " -n 1 -r
4c01e298
S
119 if [[ $REPLY =~ ^[Nn]$ ]] ; then
120 echo
121 echo WARNING: You may not be able to log in to your container.
88126eba 122 echo
88126eba
S
123 else
124 echo
4c01e298
S
125 echo Generating SSH key
126 mkdir -p ~/.ssh && ssh-keygen -f ~/.ssh/id_rsa -t rsa -N ''
88126eba
S
127 echo
128 fi
129 fi
130 fi
131
9d28af0e 132 ssh_pub_key="$(cat ~/.ssh/id_rsa.pub 2>/dev/null || cat ~/.ssh/id_dsa.pub)"
88126eba
S
133}
134
135
52388b87
SS
136install_docker() {
137
138 echo "Docker is not installed, make sure you are running on the 3.8 kernel"
139 echo "The best supported Docker release is Ubuntu 12.04.03 for it run the following"
140 echo
141 echo "sudo apt-get update"
142 echo "sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring"
143 echo "sudo reboot"
144 echo
145
146 echo "sudo sh -c \"wget -qO- https://get.docker.io/gpg | apt-key add -\""
147 echo "sudo sh -c \"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list\""
148 echo "sudo apt-get update"
149 echo "sudo apt-get install lxc-docker"
150
151 exit 1
152}
153
d90671f3 154set_volumes() {
4807b1b8 155 volumes=`cat $config_file | $docker_path run --rm -i -a stdout -a stdin $image ruby -e \
d90671f3
SS
156 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
157}
158
7f77c274
SS
159set_template_info() {
160
4807b1b8 161 templates=`cat $config_file | $docker_path run --rm -i -a stdin -a stdout $image ruby -e \
7f77c274
SS
162 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
163
164
165 arrTemplates=(${templates// / })
166 config_data=$(cat $config_file)
167
168 input="hack: true"
169
170
171 for template in "${arrTemplates[@]}"
172 do
173 [ ! -z $template ] && {
174 input="$input _FILE_SEPERATOR_ $(cat $template)"
175 }
176 done
177
178 # we always want our config file last so it takes priority
179 input="$input _FILE_SEPERATOR_ $config_data"
180
181 read -r -d '' env_ruby << 'RUBY'
182 require 'yaml'
183
184 input=STDIN.readlines.join
185 env = {}
186 input.split('_FILE_SEPERATOR_').each do |yml|
187 yml.strip!
188 begin
189 env.merge!(YAML.load(yml)['env'] || {})
f3824347 190 rescue Psych::SyntaxError => e
191 puts e
192 puts "*ERROR."
7f77c274
SS
193 rescue => e
194 puts yml
195 p e
196 end
197 end
4b563ee8 198 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
7f77c274
SS
199RUBY
200
4807b1b8 201 raw=`exec echo "$input" | $docker_path run --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
4b563ee8
SS
202
203 env=()
f3824347 204 ok=1
4b563ee8 205 while read i; do
f3824347 206 if [ "$i" == "*ERROR." ]; then
207 ok=0
208 elif [ -n "$i" ]; then
16f2d250
S
209 env[${#env[@]}]=$i
210 fi
4b563ee8
SS
211 done <<< "$raw"
212
f3824347 213 if [ "$ok" -ne 1 ]; then
214 echo "${env[@]}"
215 echo "YAML syntax error. Please check your configuration files."
216 exit 1
217 fi
4b563ee8 218 echo "Calculated ENV: ${env[@]}"
7f77c274
SS
219}
220
52388b87
SS
221[ -z $docker_path ] && {
222 install_docker
223}
224
5f803fb4 225
c1005add 226[ $# -lt 2 ] && {
5f803fb4
SS
227 usage
228}
229
7e738616
S
230if [ ! -e $config_file ]
231 then
232 echo "Config file was not found, ensure $config_file exists"
233 exit 1
234fi
235
337a89aa 236
7936ebaa
MB
237run_mailtest(){
238 if [ ! -e $config_file ]; then
239 echo "Config does not exist: $config_file" >&2
240 exit 1
241 fi
242 exec scripts/mailtest $config_file
243}
244
337a89aa
S
245run_stop(){
246 if [ ! -e $cidfile ]
247 then
248 echo "No cid found"
249 exit 1
250 else
4807b1b8 251 $docker_path stop -t 10 `cat $cidfile`
337a89aa
S
252 fi
253}
254
255run_start(){
256
257 if [ ! -e $cidfile ]
258 then
259 echo "No cid found, creating a new container"
4807b1b8 260 ports=`cat $config_file | $docker_path run --rm -i -a stdout -a stdin $image ruby -e \
337a89aa
S
261 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| '-p ' << p.to_s << ' '}.join"`
262
263 set_template_info
264 set_volumes
265
4807b1b8 266 existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep "$config$" | awk '{ print $1 }'`
337a89aa
S
267 if [ ! -z $existing ]
268 then
269 echo "Found an existing container by its name, recovering cidfile, please rerun"
270 echo $existing > $cidfile
271 exit 1
272 fi
273
4807b1b8 274 $docker_path run "${env[@]}" -h "`hostname`-$config" -e DOCKER_HOST_IP=$docker_ip --name $config -t --cidfile $cidfile $ports \
23022c1d 275 -d $volumes $local_discourse/$config /sbin/runit
337a89aa
S
276
277 exit 0
278 else
279 cid=`cat $cidfile`
280
281 if [ -z $cid ]
282 then
283 echo "Detected empty cid file, deleting, please re-run"
284 rm $cidfile
285 exit 1
286 fi
287
4807b1b8 288 found=`$docker_path ps -q -a --no-trunc | grep $cid`
337a89aa
S
289 if [ -z $found ]
290 then
291 echo "Invalid cid file, deleting, please re-run"
292 rm $cidfile
293 exit 1
294 fi
295
296 echo "cid found, ensuring container is started"
4807b1b8 297 $docker_path start `cat $cidfile`
337a89aa
S
298 exit 0
299 fi
300
301}
302
680dd4ea
S
303run_bootstrap(){
304 get_ssh_pub_key
88126eba 305
680dd4ea
S
306 # Is the image available?
307 # If not, pull it here so the user is aware what's happening.
4807b1b8 308 $docker_path history $image >/dev/null 2>&1 || $docker_path pull $image
88126eba 309
680dd4ea 310 set_template_info
93149421 311
4807b1b8 312 base_image=`cat $config_file | $docker_path run --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 313 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
93149421 314
4807b1b8 315 update_pups=`cat $config_file | $docker_path run --rm -i -a stdin -a stdout $image ruby -e \
680dd4ea 316 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
b9c7b50e 317
680dd4ea
S
318 if [[ ! X"" = X"$base_image" ]]; then
319 image=$base_image
320 fi
b9c7b50e 321
680dd4ea 322 set_volumes
b9c7b50e 323
680dd4ea 324 rm -f $cidbootstrap
d90671f3 325
680dd4ea
S
326 run_command="cd /pups &&"
327 if [[ ! "false" = $update_pups ]]; then
328 run_command="$run_command git pull &&"
329 fi
330 run_command="$run_command /pups/bin/pups --stdin"
2162f1d4 331
680dd4ea 332 echo $run_command
b9c7b50e 333
680dd4ea 334 env=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key")
c4498636 335
4807b1b8 336 (exec echo "$input" | $docker_path run "${env[@]}" -e DOCKER_HOST_IP=$docker_ip --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
680dd4ea 337 /bin/bash -c "$run_command") \
4807b1b8 338 || ($docker_path rm `cat $cidbootstrap` && rm $cidbootstrap)
88126eba 339
680dd4ea 340 [ ! -e $cidbootstrap ] && echo "FAILED TO BOOTSTRAP" && exit 1
9fb5f2d3 341
680dd4ea 342 sleep 5
2162f1d4 343
4807b1b8
MB
344 $docker_path commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
345 $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
680dd4ea 346}
9fb5f2d3 347
680dd4ea
S
348case "$command" in
349 bootstrap)
680dd4ea 350 run_bootstrap
2dd2e330 351 echo "Successfully bootstrapped, to startup use ./launcher start $config"
4b3aebe1 352 exit 0
5f803fb4 353 ;;
1acce9e4 354
7936ebaa
MB
355 mailtest)
356 run_mailtest
357 exit 0
358 ;;
359
5f803fb4
SS
360 ssh)
361 if [ ! -e $cidfile ]
362 then
363 echo "No cid found"
364 exit 1
365 else
366 cid="`cat $cidfile`"
4807b1b8 367 address="`$docker_path port $cid 22`"
5f803fb4 368 split=(${address//:/ })
38c09f5e 369 exec ssh -o StrictHostKeyChecking=no root@${split[0]} -p ${split[1]}
5f803fb4
SS
370 fi
371 ;;
7e738616 372
5f803fb4 373 stop)
337a89aa
S
374 run_stop
375 exit 0
5f803fb4 376 ;;
7e738616 377
5f803fb4 378 logs)
7e738616 379
5f803fb4
SS
380 if [ ! -e $cidfile ]
381 then
382 echo "No cid found"
383 exit 1
384 else
4807b1b8 385 $docker_path logs `cat $cidfile`
5f803fb4
SS
386 exit 0
387 fi
388 ;;
7e738616 389
337a89aa
S
390 restart)
391 run_stop
392 run_start
393 exit 0
394 ;;
80c11be3 395
337a89aa
S
396 start)
397 run_start
398 exit 0
5f803fb4 399 ;;
7e738616 400
680dd4ea
S
401 rebuild)
402 if [ -e $cidfile ]
403 then
404 echo "Stopping old container"
4807b1b8 405 $docker_path stop -t 10 `cat $cidfile`
680dd4ea
S
406 fi
407
408 run_bootstrap
409
410 if [ -e $cidfile ]
411 then
4807b1b8 412 $docker_path rm `cat $cidfile` && rm $cidfile
680dd4ea
S
413 fi
414
415 run_start
416 exit 0
417 ;;
418
7e738616 419
5f803fb4
SS
420 destroy)
421 if [ -e $cidfile ]
422 then
423 echo "destroying container $cidfile"
4807b1b8
MB
424 $docker_path stop -t 10 `cat $cidfile`
425 $docker_path rm `cat $cidfile` && rm $cidfile
5f803fb4
SS
426 exit 0
427 else
428 echo "nothing to destroy cidfile does not exist"
429 exit 1
430 fi
431 ;;
432esac
7e738616 433
5f803fb4 434usage