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