Merge branch 'master' into 4570-multi-auth-method
[arvados.git] / docker / arvdock
1 #!/bin/bash
2
3 DOCKER=`which docker.io`
4
5 if [[ "$DOCKER" == "" ]]; then
6     DOCKER=`which docker`
7 fi
8
9 COMPUTE_COUNTER=0
10
11 function usage {
12     echo >&2
13     echo >&2 "usage: $0 (start|stop|restart|test) [options]"
14     echo >&2
15     echo >&2 "$0 start/stop/restart options:"
16     echo >&2 "  -d[port], --doc[=port]        Documentation server (default port 9898)"
17     echo >&2 "  -w[port], --workbench[=port]  Workbench server (default port 9899)"
18     echo >&2 "  -s[port], --sso[=port]        SSO server (default port 9901)"
19     echo >&2 "  -a[port], --api[=port]        API server (default port 9900)"
20     echo >&2 "  -c, --compute                 Compute nodes (starts 2)"
21     echo >&2 "  -v, --vm                      Shell server"
22     echo >&2 "  -n, --nameserver              Nameserver"
23     echo >&2 "  -k, --keep                    Keep servers"
24     echo >&2 "  -h, --help                    Display this help and exit"
25     echo >&2
26     echo >&2 "  If no options are given, the action is applied to all servers."
27     echo >&2
28     echo >&2 "$0 test [testname] [testname] ..."
29     echo >&2 "  By default, all tests are run."
30 }
31
32 function ip_address {
33     local container=$1
34     echo `$DOCKER inspect $container  |grep IPAddress |cut -f4 -d\"`
35 }
36
37 function start_container {
38     local args="-d -i -t"
39     if [[ "$1" != '' ]]; then
40       local port="$1"
41       args="$args -p $port"
42     fi
43     if [[ "$2" != '' ]]; then
44       local name="$2"
45       if [[ "$name" == "api_server" ]]; then
46         args="$args --dns=172.17.42.1 --dns-search=compute.dev.arvados --hostname api -P --name $name"
47       elif [[ "$name" == "compute" ]]; then
48         name=$name$COMPUTE_COUNTER
49         # We need --privileged because we run docker-inside-docker on the compute nodes
50         args="$args --dns=172.17.42.1 --dns-search=compute.dev.arvados --hostname compute$COMPUTE_COUNTER -P --privileged --name $name"
51         let COMPUTE_COUNTER=$(($COMPUTE_COUNTER + 1))
52       else
53         args="$args --dns=172.17.42.1 --dns-search=dev.arvados --hostname ${name#_server} --name $name"
54       fi
55     fi
56     if [[ "$3" != '' ]]; then
57       local volume="$3"
58       args="$args -v $volume"
59     fi
60     if [[ "$4" != '' ]]; then
61       local link="$4"
62       args="$args --link $link"
63     fi
64     local image=$5
65
66     `$DOCKER ps |grep -P "$name[^/]" -q`
67     if [[ "$?" == "0" ]]; then
68       echo "You have a running container with name $name -- skipping."
69       return
70     fi
71
72     # Remove any existing container by this name.
73     $DOCKER rm "$name" 2>/dev/null
74
75     echo "Starting container:"
76     #echo "  $DOCKER run --dns=127.0.0.1 $args $image"
77     echo "  $DOCKER run $args $image"
78     container=`$DOCKER run $args $image`
79     if [ "$?" != "0" -o "$container" = "" ]; then
80       echo "Unable to start container"
81       exit 1
82     else
83       echo "Started container: $container"
84     fi
85
86     if [[ "$name" == "doc_server" ]]; then
87       echo
88       echo "*****************************************************************"
89       echo "You can access the Arvados documentation at http://localhost:${port%:*}"
90       echo "*****************************************************************"
91       echo
92     fi
93
94     if [[ "$name" == "workbench_server" ]]; then
95       echo
96       echo "*****************************************************************"
97       echo "You can access the Arvados workbench at http://localhost:${port%:*}"
98       echo "*****************************************************************"
99       echo
100    fi
101
102
103 }
104
105 declare -a keep_volumes
106
107 # Initialize the global `keep_volumes' array. If any keep volumes
108 # already appear to exist (mounted volumes with a top-level "keep"
109 # directory), use them; create temporary volumes if necessary.
110 #
111 function make_keep_volumes () {
112     # Mount a keep volume if we don't already have one
113     for mountpoint in $(cut -d ' ' -f 2 /proc/mounts); do
114       if [[ -d "$mountpoint/keep" && "$mountpoint" != "/" ]]; then
115         keep_volumes+=($mountpoint)
116       fi
117     done
118
119     # Create any keep volumes that do not yet exist.
120     while [ ${#keep_volumes[*]} -lt 2 ]
121     do
122         new_keep=$(mktemp -d)
123         echo >&2 "mounting 2G tmpfs keep volume in $new_keep"
124         sudo mount -t tmpfs -o size=2G tmpfs $new_keep
125         mkdir $new_keep/keep
126         keep_volumes+=($new_keep)
127     done
128 }
129
130 function do_start {
131     local start_doc=false
132     local start_sso=false
133     local start_api=false
134     local start_compute=false
135     local start_workbench=false
136     local start_vm=false
137     local start_nameserver=false
138     local start_keep=false
139
140     # NOTE: This requires GNU getopt (part of the util-linux package on Debian-based distros).
141     local TEMP=`getopt -o d::s::a::cw::nkvh \
142                   --long doc::,sso::,api::,compute,workbench::,nameserver,keep,vm,help \
143                   -n "$0" -- "$@"`
144
145     if [ $? != 0 ] ; then echo "Use -h for help"; exit 1 ; fi
146
147     # Note the quotes around `$TEMP': they are essential!
148     eval set -- "$TEMP"
149
150     while [ $# -ge 1 ]
151     do
152         case $1 in
153             -d | --doc)
154                 case "$2" in
155                     "") start_doc=9898; shift 2 ;;
156                     *)  start_doc=$2; shift 2 ;;
157                 esac
158                 ;;
159             -s | --sso)
160                 case "$2" in
161                     "") start_sso=9901; shift 2 ;;
162                     *)  start_sso=$2; shift 2 ;;
163                 esac
164                 ;;
165             -a | --api)
166                 case "$2" in
167                     "") start_api=9900; shift 2 ;;
168                     *)  start_api=$2; shift 2 ;;
169                 esac
170                 ;;
171             -c | --compute)
172                 start_compute=2
173                 shift
174                 ;;
175             -w | --workbench)
176                 case "$2" in
177                     "") start_workbench=9899; shift 2 ;;
178                     *)  start_workbench=$2; shift 2 ;;
179                 esac
180                 ;;
181             -v | --vm)
182                 start_vm=true
183                 shift
184                 ;;
185             -n | --nameserver)
186                 start_nameserver=true
187                 shift
188                 ;;
189             -k | --keep)
190                 start_keep=true
191                 shift
192                 ;;
193             --)
194                 shift
195                 break
196                 ;;
197             *)
198                 usage
199                 exit 1
200                 ;;
201         esac
202     done
203
204     # If no options were selected, then start all servers.
205     if [[ $start_doc == false &&
206           $start_sso == false &&
207           $start_api == false &&
208           $start_compute == false &&
209           $start_workbench == false &&
210           $start_vm == false &&
211           $start_nameserver == false &&
212           $start_keep == false ]]
213     then
214         start_doc=9898
215         #the sso server is currently not used by default so don't start it unless explicitly requested
216         #start_sso=9901
217         start_api=9900
218         start_compute=2
219         start_workbench=9899
220         start_vm=true
221         start_nameserver=true
222         start_keep=true
223     fi
224
225     if [[ $start_sso != false ]]
226     then
227         start_container "$start_sso:443" "sso_server" '' '' "arvados/sso"
228     fi
229
230     if [[ $start_api != false ]]
231     then
232       if [[ $start_sso != false ]]; then
233         start_container "$start_api:443" "api_server" '' "sso_server:sso" "arvados/api"
234       else
235         start_container "$start_api:443" "api_server" '' '' "arvados/api"
236       fi
237     fi
238
239     if [[ $start_nameserver != false ]]
240     then
241       # We rely on skydock and skydns for dns discovery between the slurm controller and compute nodes,
242       # so make sure they are running
243       $DOCKER ps | grep skydns >/dev/null
244       if [[ "$?" != "0" ]]; then
245         echo "Starting crosbymichael/skydns container..."
246         $DOCKER rm "skydns" 2>/dev/null
247         $DOCKER run -d -p 172.17.42.1:53:53/udp --name skydns crosbymichael/skydns -nameserver 8.8.8.8:53 -domain arvados
248       fi
249       $DOCKER ps | grep skydock >/dev/null
250       if [[ "$?" != "0" ]]; then
251         echo "Starting crosbymichael/skydock container..."
252         $DOCKER rm "skydock" 2>/dev/null
253         $DOCKER run -d -v /var/run/docker.sock:/docker.sock --name skydock crosbymichael/skydock -ttl 30 -environment dev -s /docker.sock -domain arvados -name skydns
254       fi
255     fi
256
257     if [[ $start_compute != false ]]
258     then
259         for i in `seq 0 $(($start_compute - 1))`; do
260           start_container "" "compute" '' "api_server:api" "arvados/compute"
261         done
262     fi
263
264     if [[ $start_keep != false ]]
265     then
266         # create `keep_volumes' array with a list of keep mount points
267         # remove any stale metadata from those volumes before starting them
268         make_keep_volumes
269         for v in ${keep_volumes[*]}
270         do
271             [ -f $v/keep/.metadata.yml ] && sudo rm $v/keep/.metadata.yml
272         done
273         start_container "25107:25107" "keep_server_0" \
274             "${keep_volumes[0]}:/keep-data" \
275             "api_server:api" \
276             "arvados/keep"
277         start_container "25108:25107" "keep_server_1" \
278             "${keep_volumes[1]}:/keep-data" \
279             "api_server:api" \
280             "arvados/keep"
281     fi
282
283     if [[ $start_doc != false ]]
284     then
285         start_container "$start_doc:80" "doc_server" '' '' "arvados/doc"
286     fi
287
288     if [[ $start_vm != false ]]
289     then
290         start_container "" "shell" '' "api_server:api" "arvados/shell"
291     fi
292
293     if [[ $start_workbench != false ]]
294     then
295         start_container "$start_workbench:80" "workbench_server" '' "api_server:api" "arvados/workbench"
296     fi
297
298     if [[ $start_api != false ]]
299     then
300         if [[ -f "api/generated/superuser_token" ]]
301         then
302           if [ -d $HOME/.config/arvados ] || mkdir -p $HOME/.config/arvados
303           then
304             cat >$HOME/.config/arvados/settings.conf <<EOF
305 ARVADOS_API_HOST=$(ip_address "api_server")
306 ARVADOS_API_HOST_INSECURE=yes
307 ARVADOS_API_TOKEN=$(cat api/generated/superuser_token)
308 EOF
309           fi
310         fi
311     fi
312 }
313
314 function do_stop {
315     local stop_doc=""
316     local stop_sso=""
317     local stop_api=""
318     local stop_compute=""
319     local stop_workbench=""
320     local stop_nameserver=""
321     local stop_vm=""
322     local stop_keep=""
323
324     # NOTE: This requires GNU getopt (part of the util-linux package on Debian-based distros).
325     local TEMP=`getopt -o dsacwnkvh \
326                   --long doc,sso,api,compute,workbench,nameserver,keep,vm,help \
327                   -n "$0" -- "$@"`
328
329     if [ $? != 0 ] ; then echo "Use -h for help"; exit 1 ; fi
330
331     # Note the quotes around `$TEMP': they are essential!
332     eval set -- "$TEMP"
333
334     while [ $# -ge 1 ]
335     do
336         case $1 in
337             -d | --doc)
338                 stop_doc=doc_server ; shift ;;
339             -s | --sso)
340                 stop_sso=sso_server ; shift ;;
341             -a | --api)
342                 stop_api=api_server ; shift ;;
343             -c | --compute)
344                 stop_compute=`$DOCKER ps |grep -P "compute\d+" |grep -v api_server |cut -f1 -d ' '` ; shift ;;
345             -w | --workbench)
346                 stop_workbench=workbench_server ; shift ;;
347             -n | --nameserver )
348                 stop_nameserver="skydock skydns" ; shift ;;
349             -v | --vm )
350                 stop_vm="shell" ; shift ;;
351             -k | --keep )
352                 stop_keep="keep_server_0 keep_server_1" ; shift ;;
353             --)
354                 shift
355                 break
356                 ;;
357             *)
358                 usage
359                 exit 1
360                 ;;
361         esac
362     done
363
364     # If no options were selected, then stop all servers.
365     if [[ $stop_doc == "" &&
366           $stop_sso == "" &&
367           $stop_api == "" &&
368           $stop_compute == "" &&
369           $stop_workbench == "" &&
370           $stop_vm == "" &&
371           $stop_nameserver == "" &&
372           $stop_keep == "" ]]
373     then
374         stop_doc=doc_server
375         stop_sso=sso_server
376         stop_api=api_server
377         stop_compute=`$DOCKER ps |grep -P "compute\d+" |grep -v api_server |cut -f1 -d ' '`
378         stop_workbench=workbench_server
379         stop_vm=shell
380         stop_nameserver="skydock skydns"
381         stop_keep="keep_server_0 keep_server_1"
382     fi
383
384     $DOCKER stop $stop_doc $stop_sso $stop_api $stop_compute $stop_workbench $stop_nameserver $stop_keep $stop_vm \
385         2>/dev/null
386 }
387
388 function do_test {
389     local alltests
390     if [ $# -lt 1 ]
391     then
392         alltests="python-sdk api"
393     else
394         alltests="$@"
395     fi
396
397     for testname in $alltests
398     do
399         echo "testing $testname..."
400         case $testname in
401             python-sdk)
402                 do_start --api --keep --sso
403                 export ARVADOS_API_HOST=$(ip_address "api_server")
404                 export ARVADOS_API_HOST_INSECURE=yes
405                 export ARVADOS_API_TOKEN=$(cat api/generated/superuser_token)
406                 python -m unittest discover ../sdk/python
407                 ;;
408             api)
409                 $DOCKER run -t -i arvados/api \
410                     /usr/src/arvados/services/api/script/rake_test.sh
411                 ;;
412             *)
413                 echo >&2 "unknown test $testname"
414                 ;;
415         esac
416     done
417 }
418
419 if [ $# -lt 1 ]
420 then
421   usage
422   exit 1
423 fi
424
425 case $1 in
426     start)
427         shift
428         do_start $@
429         ;;
430     stop)
431         shift
432         do_stop $@
433         ;;
434     restart)
435         shift
436         do_stop $@
437         do_start $@
438         ;;
439     test)
440         shift
441         do_test $@
442         ;;
443     *)
444         usage
445         exit 1
446         ;;
447 esac