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