UPGRADE: docker 0.10 is now out
[discourse_docker.git] / launcher
1 #!/bin/bash
2
3 command=$1
4 config=$2
5 config_file=containers/"$config".yml
6 cidfile=cids/"$config".cid
7 cidbootstrap=cids/"$config"_boostrap.cid
8 local_discourse=local_discourse
9 image=samsaffron/discourse:0.1.2
10 docker_path=`which docker`
11
12 docker_ip=`/sbin/ifconfig | \
13 grep -B1 "inet addr" | \
14 awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \
15 grep docker0 | \
16 awk -F: '{ print $3 }';`
17
18
19 usage () {
20 echo "Usage: launcher COMMAND CONFIG"
21 echo "Commands:"
22 echo " start: Start/initialize a container"
23 echo " stop: Stop a running container"
24 echo " restart: Restart a container"
25 echo " destroy: Stop and remove a container"
26 echo " ssh: Start a bash shell in a running container"
27 echo " logs: Docker logs for container"
28 echo " bootstrap: Bootstrap a container for the config based on a template"
29 echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
30 exit 1
31 }
32
33 prereqs() {
34
35 # 1. docker daemon running?
36 test=`docker info >/dev/null`
37
38 if [[ $? -ne 0 ]] ; then
39 echo "Cannot connect to the docker daemon - verify it is running and you have access"
40 exit 1
41 fi
42
43 # 2. running aufs
44 test=`docker info 2> /dev/null | grep 'Driver: aufs'`
45 if [[ "$test" =~ "aufs" ]] ; then : ; else
46 echo "Your Docker installation is not using aufs"
47 echo "Device mapper and other experimental drivers are unstable"
48 echo
49 echo "Please ensure your kernel is running linux extras and aufs"
50 echo "Please follow the installation guide for Docker here: http://docs.docker.io/en/latest/installation/ubuntulinux/"
51 exit 1
52 fi
53
54 # 3. running docker 0.10+
55 test=`docker --version | grep 0.10`
56
57 if [[ "$test" =~ "0.10" ]] ; then : ; else
58 echo "Your Docker installation is old, please upgrade to 0.10.0 or up"
59 exit 1
60 fi
61
62 # 4. able to attach stderr / out / tty
63 test=`docker run -i --rm -a stdin -a stdout -a stderr $image echo working`
64 if [[ "$test" =~ "working" ]] ; then : ; else
65 echo "Your Docker installation is not working correctly"
66 echo
67 echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
68 exit 1
69 fi
70 }
71
72 prereqs
73
74 get_ssh_pub_key() {
75 if tty -s ; then
76 if [[ ! -e ~/.ssh/id_rsa.pub && ! -e ~/.ssh/id_dsa.pub ]] ; then
77 echo You have no SSH key associated to this profile
78 echo "(This will allow you ssh access into your container)"
79 read -p "Generate SSH key at ~/.ssh/id_rsa.pub? (y/N) " -n 1 -r
80 if [[ $REPLY =~ ^[Yy]$ ]] ; then
81 echo
82 echo Generating SSH key
83 mkdir -p ~/.ssh && ssh-keygen -f ~/.ssh/id_rsa -t rsa -N ''
84 else
85 echo
86 echo WARNING: You may not be able to log in to your container.
87 echo
88 fi
89 fi
90 fi
91
92 ssh_pub_key="$(cat ~/.ssh/id_rsa.pub 2>/dev/null || cat ~/.ssh/id_dsa.pub)"
93 }
94
95
96 install_docker() {
97
98 echo "Docker is not installed, make sure you are running on the 3.8 kernel"
99 echo "The best supported Docker release is Ubuntu 12.04.03 for it run the following"
100 echo
101 echo "sudo apt-get update"
102 echo "sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring"
103 echo "sudo reboot"
104 echo
105
106 echo "sudo sh -c \"wget -qO- https://get.docker.io/gpg | apt-key add -\""
107 echo "sudo sh -c \"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list\""
108 echo "sudo apt-get update"
109 echo "sudo apt-get install lxc-docker"
110
111 exit 1
112 }
113
114 set_volumes() {
115 volumes=`cat $config_file | docker run --rm -i -a stdout -a stdin $image ruby -e \
116 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"`
117 }
118
119 set_template_info() {
120
121 templates=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \
122 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
123
124
125 arrTemplates=(${templates// / })
126 config_data=$(cat $config_file)
127
128 input="hack: true"
129
130
131 for template in "${arrTemplates[@]}"
132 do
133 [ ! -z $template ] && {
134 input="$input _FILE_SEPERATOR_ $(cat $template)"
135 }
136 done
137
138 # we always want our config file last so it takes priority
139 input="$input _FILE_SEPERATOR_ $config_data"
140
141 read -r -d '' env_ruby << 'RUBY'
142 require 'yaml'
143
144 input=STDIN.readlines.join
145 env = {}
146 input.split('_FILE_SEPERATOR_').each do |yml|
147 yml.strip!
148 begin
149 env.merge!(YAML.load(yml)['env'] || {})
150 rescue => e
151 puts yml
152 p e
153 end
154 end
155 puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n")
156 RUBY
157
158 raw=`exec echo "$input" | docker run --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"`
159
160 env=()
161 while read i; do
162 env[${#env[@]}]=$i
163 done <<< "$raw"
164
165 echo "Calculated ENV: ${env[@]}"
166 }
167
168 [ -z $docker_path ] && {
169 install_docker
170 }
171
172
173 [ $# -ne 2 ] && {
174 usage
175 }
176
177 if [ ! -e $config_file ]
178 then
179 echo "Config file was not found, ensure $config_file exists"
180 exit 1
181 fi
182
183
184 run_stop(){
185 if [ ! -e $cidfile ]
186 then
187 echo "No cid found"
188 exit 1
189 else
190 docker stop -t 10 `cat $cidfile`
191 fi
192 }
193
194 run_start(){
195
196 if [ ! -e $cidfile ]
197 then
198 echo "No cid found, creating a new container"
199 ports=`cat $config_file | docker run --rm -i -a stdout -a stdin $image ruby -e \
200 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| '-p ' << p.to_s << ' '}.join"`
201
202 set_template_info
203 set_volumes
204
205 existing=`docker ps -a | awk '{ print $1, $(NF) }' | grep "$config$" | awk '{ print $1 }'`
206 if [ ! -z $existing ]
207 then
208 echo "Found an existing container by its name, recovering cidfile, please rerun"
209 echo $existing > $cidfile
210 exit 1
211 fi
212
213 docker run "${env[@]}" -h "`hostname`-$config" -e DOCKER_HOST_IP=$docker_ip --name $config -t --cidfile $cidfile $ports \
214 -d $volumes $local_discourse/$config /usr/bin/runsvdir -P /etc/service
215
216 exit 0
217 else
218 cid=`cat $cidfile`
219
220 if [ -z $cid ]
221 then
222 echo "Detected empty cid file, deleting, please re-run"
223 rm $cidfile
224 exit 1
225 fi
226
227 found=`docker ps -q -a --no-trunc | grep $cid`
228 if [ -z $found ]
229 then
230 echo "Invalid cid file, deleting, please re-run"
231 rm $cidfile
232 exit 1
233 fi
234
235 echo "cid found, ensuring container is started"
236 docker start `cat $cidfile`
237 exit 0
238 fi
239
240 }
241
242 run_bootstrap(){
243 get_ssh_pub_key
244
245 # Is the image available?
246 # If not, pull it here so the user is aware what's happening.
247 docker history $image >/dev/null 2>&1 || docker pull $image
248
249 set_template_info
250
251 base_image=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \
252 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"`
253
254 update_pups=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \
255 "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"`
256
257 if [[ ! X"" = X"$base_image" ]]; then
258 image=$base_image
259 fi
260
261 set_volumes
262
263 rm -f $cidbootstrap
264
265 run_command="cd /pups &&"
266 if [[ ! "false" = $update_pups ]]; then
267 run_command="$run_command git pull &&"
268 fi
269 run_command="$run_command /pups/bin/pups --stdin"
270
271 echo $run_command
272
273 env=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key")
274
275 (exec echo "$input" | docker run "${env[@]}" -e DOCKER_HOST_IP=$docker_ip --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
276 /bin/bash -c "$run_command") \
277 || (docker rm `cat $cidbootstrap` && rm $cidbootstrap)
278
279 [ ! -e $cidbootstrap ] && echo "FAILED TO BOOTSTRAP" && exit 1
280
281 sleep 5
282
283 docker commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT'
284 docker rm `cat $cidbootstrap` && rm $cidbootstrap
285 }
286
287 case "$command" in
288 bootstrap)
289
290 run_bootstrap
291 echo "Successfully bootstrapped, to startup use ./launcher start $config"
292 exit 0
293 ;;
294
295 ssh)
296 if [ ! -e $cidfile ]
297 then
298 echo "No cid found"
299 exit 1
300 else
301 cid="`cat $cidfile`"
302 address="`docker port $cid 22`"
303 split=(${address//:/ })
304 exec ssh -o StrictHostKeyChecking=no root@${split[0]} -p ${split[1]}
305 fi
306 ;;
307
308 stop)
309 run_stop
310 exit 0
311 ;;
312
313 logs)
314
315 if [ ! -e $cidfile ]
316 then
317 echo "No cid found"
318 exit 1
319 else
320 docker logs `cat $cidfile`
321 exit 0
322 fi
323 ;;
324
325 restart)
326 run_stop
327 run_start
328 exit 0
329 ;;
330
331 start)
332 run_start
333 exit 0
334 ;;
335
336 rebuild)
337 if [ -e $cidfile ]
338 then
339 echo "Stopping old container"
340 docker stop -t 10 `cat $cidfile`
341 fi
342
343 run_bootstrap
344
345 if [ -e $cidfile ]
346 then
347 docker rm `cat $cidfile` && rm $cidfile
348 fi
349
350 run_start
351 exit 0
352 ;;
353
354
355 destroy)
356 if [ -e $cidfile ]
357 then
358 echo "destroying container $cidfile"
359 docker stop -t 10 `cat $cidfile`
360 docker rm `cat $cidfile` && rm $cidfile
361 exit 0
362 else
363 echo "nothing to destroy cidfile does not exist"
364 exit 1
365 fi
366 ;;
367 esac
368
369 usage