14660: make "sv restart" work for workbench2, prevent fail loop
[arvados.git] / tools / arvbox / bin / arvbox
1 #!/bin/sh
2 # Copyright (C) The Arvados Authors. All rights reserved.
3 #
4 # SPDX-License-Identifier: AGPL-3.0
5
6 set -e
7
8 if ! test -d /sys/fs/cgroup ; then
9      echo "Arvbox requires cgroups to be mounted at /sys/fs/cgroup in order to use"
10      echo "Docker-in-Docker.  Older operating systems that put cgroups in other"
11      echo "places (such as /cgroup) are not supported."
12      exit 1
13 fi
14
15 if ! which docker >/dev/null 2>/dev/null ; then
16   echo "Arvbox requires Docker.  To install, run the following command as root:"
17   echo "curl -sSL https://get.docker.com/ | sh"
18   exit 1
19 fi
20
21 if test -z "$ARVBOX_DOCKER" ; then
22     if which greadlink >/dev/null 2>/dev/null ; then
23         ARVBOX_DOCKER=$(greadlink -f $(dirname $0)/../lib/arvbox/docker)
24     else
25         ARVBOX_DOCKER=$(readlink -f $(dirname $0)/../lib/arvbox/docker)
26     fi
27 fi
28
29 if test -z "$ARVBOX_CONTAINER" ; then
30     ARVBOX_CONTAINER=arvbox
31 fi
32
33 if test -z "$ARVBOX_BASE" ; then
34     ARVBOX_BASE="$HOME/.arvbox"
35 fi
36
37 if test -z "$ARVBOX_DATA" ; then
38     ARVBOX_DATA="$ARVBOX_BASE/$ARVBOX_CONTAINER"
39 fi
40
41 if test -z "$ARVADOS_ROOT" ; then
42     ARVADOS_ROOT="$ARVBOX_DATA/arvados"
43 fi
44
45 if test -z "$SSO_ROOT" ; then
46     SSO_ROOT="$ARVBOX_DATA/sso-devise-omniauth-provider"
47 fi
48
49 if test -z "$COMPOSER_ROOT" ; then
50     COMPOSER_ROOT="$ARVBOX_DATA/composer"
51 fi
52
53 if test -z "$WORKBENCH2_ROOT" ; then
54     WORKBENCH2_ROOT="$ARVBOX_DATA/workbench2"
55 fi
56
57 PG_DATA="$ARVBOX_DATA/postgres"
58 VAR_DATA="$ARVBOX_DATA/var"
59 PASSENGER="$ARVBOX_DATA/passenger"
60 GEMS="$ARVBOX_DATA/gems"
61 PIPCACHE="$ARVBOX_DATA/pip"
62 NPMCACHE="$ARVBOX_DATA/npm"
63 GOSTUFF="$ARVBOX_DATA/gopath"
64 RLIBS="$ARVBOX_DATA/Rlibs"
65
66 getip() {
67     docker inspect $ARVBOX_CONTAINER | grep \"IPAddress\" | head -n1 | tr -d ' ":,\n' | cut -c10-
68 }
69
70 gethost() {
71     set +e
72     OVERRIDE=$(docker exec -i $ARVBOX_CONTAINER cat /var/run/localip_override 2>/dev/null)
73     CODE=$?
74     set -e
75     if test "$CODE" = 0 ; then
76        echo $OVERRIDE
77     else
78         getip
79     fi
80 }
81
82 getclusterid() {
83     docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/api_uuid_prefix
84 }
85
86 updateconf() {
87     if test -f ~/.config/arvados/$ARVBOX_CONTAINER.conf ; then
88         sed "s/ARVADOS_API_HOST=.*/ARVADOS_API_HOST=$(gethost):8000/" <$HOME/.config/arvados/$ARVBOX_CONTAINER.conf >$HOME/.config/arvados/$ARVBOX_CONTAINER.conf.tmp
89         mv ~/.config/arvados/$ARVBOX_CONTAINER.conf.tmp ~/.config/arvados/$ARVBOX_CONTAINER.conf
90     else
91         mkdir -p $HOME/.config/arvados
92         cat >$HOME/.config/arvados/$ARVBOX_CONTAINER.conf <<EOF
93 ARVADOS_API_HOST=$(gethost):8000
94 ARVADOS_API_TOKEN=
95 ARVADOS_API_HOST_INSECURE=true
96 EOF
97     fi
98 }
99
100 wait_for_arvbox() {
101     FF=/tmp/arvbox-fifo-$$
102     mkfifo $FF
103     docker logs -f $ARVBOX_CONTAINER > $FF &
104     LOGPID=$!
105     while read line ; do
106         echo $line
107         if echo $line | grep "Workbench2 is running at" >/dev/null ; then
108             kill $LOGPID
109         fi
110     done < $FF
111     rm $FF
112     echo
113     if test -n "$localip" ; then
114         echo "export ARVADOS_API_HOST=$localip:8000"
115     else
116         echo "export ARVADOS_API_HOST=$(gethost):8000"
117     fi
118 }
119
120 run() {
121     CONFIG=$1
122     TAG=$2
123
124     shift
125
126     need_setup=1
127
128     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
129         if test "$CONFIG" = test ; then
130             need_setup=0
131         else
132             echo "Container $ARVBOX_CONTAINER is already running"
133             exit 0
134         fi
135     fi
136
137     if test $need_setup = 1 ; then
138         if docker ps -a | grep -E "$ARVBOX_CONTAINER$" -q ; then
139             echo "Container $ARVBOX_CONTAINER already exists but is not running; use restart or reboot"
140             exit 1
141         fi
142     fi
143
144     if test -n "$TAG"
145     then
146         if test $(echo $TAG | cut -c1-1) != '-' ; then
147             TAG=":$TAG"
148             shift
149         else
150             unset TAG
151         fi
152     fi
153
154     if echo "$CONFIG" | grep '^public' ; then
155         if test -n "$ARVBOX_PUBLISH_IP" ; then
156             localip=$ARVBOX_PUBLISH_IP
157         else
158             defaultdev=$(/sbin/ip route|awk '/default/ { print $5 }')
159             localip=$(ip addr show $defaultdev | grep 'inet ' | sed 's/ *inet \(.*\)\/.*/\1/')
160         fi
161         iptemp=$(tempfile)
162         echo $localip > $iptemp
163         chmod og+r $iptemp
164         PUBLIC="--volume=$iptemp:/var/run/localip_override
165               --publish=443:443
166               --publish=3001:3001
167               --publish=8000:8000
168               --publish=8900:8900
169               --publish=9001:9001
170               --publish=9002:9002
171               --publish=25100:25100
172               --publish=25107:25107
173               --publish=25108:25108
174               --publish=8001:8001
175               --publish=8002:8002"
176     else
177         PUBLIC=""
178     fi
179
180     if echo "$CONFIG" | grep 'demo$' ; then
181         if test -d "$ARVBOX_DATA" ; then
182             echo "It looks like you already have a development container named $ARVBOX_CONTAINER."
183             echo "Set ARVBOX_CONTAINER to set a different name for your demo container"
184             exit 1
185         fi
186
187         if ! (docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q) ; then
188             docker create -v /var/lib/postgresql -v /var/lib/arvados --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
189         fi
190
191         docker run \
192                --detach \
193                --name=$ARVBOX_CONTAINER \
194                --privileged \
195                --volumes-from $ARVBOX_CONTAINER-data \
196                $PUBLIC \
197                arvados/arvbox-demo$TAG
198         updateconf
199         wait_for_arvbox
200     else
201         mkdir -p "$PG_DATA" "$VAR_DATA" "$PASSENGER" "$GEMS" "$PIPCACHE" "$NPMCACHE" "$GOSTUFF" "$RLIBS"
202
203
204         if ! test -d "$ARVADOS_ROOT" ; then
205             git clone https://github.com/curoverse/arvados.git "$ARVADOS_ROOT"
206         fi
207         if ! test -d "$SSO_ROOT" ; then
208             git clone https://github.com/curoverse/sso-devise-omniauth-provider.git "$SSO_ROOT"
209         fi
210         if ! test -d "$COMPOSER_ROOT" ; then
211             git clone https://github.com/curoverse/composer.git "$COMPOSER_ROOT"
212         fi
213         if ! test -d "$WORKBENCH2_ROOT" ; then
214             git clone https://github.com/curoverse/arvados-workbench2.git "$WORKBENCH2_ROOT"
215         fi
216
217         if test "$CONFIG" = test ; then
218
219             mkdir -p $VAR_DATA/test
220
221             if test "$need_setup" = 1 ; then
222                 docker run \
223                        --detach \
224                        --name=$ARVBOX_CONTAINER \
225                        --privileged \
226                        "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
227                        "--volume=$SSO_ROOT:/usr/src/sso:rw" \
228                        "--volume=$COMPOSER_ROOT:/usr/src/composer:rw" \
229                        "--volume=$WORKBENCH2_ROOT:/usr/src/workbench2:rw" \
230                        "--volume=$PG_DATA:/var/lib/postgresql:rw" \
231                        "--volume=$VAR_DATA:/var/lib/arvados:rw" \
232                        "--volume=$PASSENGER:/var/lib/passenger:rw" \
233                        "--volume=$GEMS:/var/lib/gems:rw" \
234                        "--volume=$PIPCACHE:/var/lib/pip:rw" \
235                        "--volume=$NPMCACHE:/var/lib/npm:rw" \
236                        "--volume=$GOSTUFF:/var/lib/gopath:rw" \
237                        "--volume=$RLIBS:/var/lib/Rlibs:rw" \
238                        "--env=SVDIR=/etc/test-service" \
239                        arvados/arvbox-dev$TAG
240
241                 docker exec -ti \
242                        $ARVBOX_CONTAINER \
243                        /usr/local/lib/arvbox/runsu.sh \
244                        /usr/local/lib/arvbox/waitforpostgres.sh
245
246                 docker exec -ti \
247                        $ARVBOX_CONTAINER \
248                        /usr/local/lib/arvbox/runsu.sh \
249                        /var/lib/arvbox/service/sso/run-service --only-setup
250
251                 docker exec -ti \
252                        $ARVBOX_CONTAINER \
253                        /usr/local/lib/arvbox/runsu.sh \
254                        /var/lib/arvbox/service/api/run-service --only-setup
255             fi
256
257             docker exec -ti \
258                    $ARVBOX_CONTAINER \
259                    /usr/local/lib/arvbox/runsu.sh \
260                    /usr/src/arvados/build/run-tests.sh \
261                    --temp /var/lib/arvados/test \
262                    WORKSPACE=/usr/src/arvados \
263                    GEM_HOME=/var/lib/gems \
264                    "$@"
265         elif echo "$CONFIG" | grep 'dev$' ; then
266             docker run \
267                    --detach \
268                    --name=$ARVBOX_CONTAINER \
269                    --privileged \
270                    "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
271                    "--volume=$SSO_ROOT:/usr/src/sso:rw" \
272                    "--volume=$COMPOSER_ROOT:/usr/src/composer:rw" \
273                    "--volume=$WORKBENCH2_ROOT:/usr/src/workbench2:rw" \
274                    "--volume=$PG_DATA:/var/lib/postgresql:rw" \
275                    "--volume=$VAR_DATA:/var/lib/arvados:rw" \
276                    "--volume=$PASSENGER:/var/lib/passenger:rw" \
277                    "--volume=$GEMS:/var/lib/gems:rw" \
278                    "--volume=$PIPCACHE:/var/lib/pip:rw" \
279                    "--volume=$NPMCACHE:/var/lib/npm:rw" \
280                    "--volume=$GOSTUFF:/var/lib/gopath:rw" \
281                    "--volume=$RLIBS:/var/lib/Rlibs:rw" \
282                    $PUBLIC \
283                    arvados/arvbox-dev$TAG
284             updateconf
285             wait_for_arvbox
286             echo "The Arvados source code is checked out at: $ARVADOS_ROOT"
287             echo "The Arvados testing root certificate is $VAR_DATA/root-cert.pem"
288         else
289             echo "Unknown configuration '$CONFIG'"
290         fi
291     fi
292 }
293
294 stop() {
295     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
296         docker stop $ARVBOX_CONTAINER
297     fi
298
299     VOLUMES=--volumes=true
300     if docker ps -a --filter "status=created" | grep -E "$ARVBOX_CONTAINER$" -q ; then
301         docker rm $VOLUMES $ARVBOX_CONTAINER
302     fi
303     if docker ps -a --filter "status=exited" | grep -E "$ARVBOX_CONTAINER$" -q ; then
304         docker rm $VOLUMES $ARVBOX_CONTAINER
305     fi
306 }
307
308 build() {
309     if ! test -f "$ARVBOX_DOCKER/Dockerfile.base" ;  then
310         echo "Could not find Dockerfile (expected it at $ARVBOX_DOCKER/Dockerfile.base)"
311         exit 1
312     fi
313     if docker --version |grep " 1\.[0-9]\." ; then
314         # Docker version prior 1.10 require -f flag
315         # -f flag removed in Docker 1.12
316         FORCE=-f
317     fi
318     GITHEAD=$(cd $ARVBOX_DOCKER && git log --format=%H -n1 HEAD)
319     docker build --build-arg=arvados_version=$GITHEAD $NO_CACHE -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVBOX_DOCKER"
320     docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
321     if test "$1" = localdemo -o "$1" = publicdemo ; then
322         docker build $NO_CACHE -t arvados/arvbox-demo:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
323         docker tag $FORCE arvados/arvbox-demo:$GITHEAD arvados/arvbox-demo:latest
324     else
325         docker build $NO_CACHE -t arvados/arvbox-dev:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
326         docker tag $FORCE arvados/arvbox-dev:$GITHEAD arvados/arvbox-dev:latest
327     fi
328 }
329
330 check() {
331     case "$1" in
332         localdemo|publicdemo|dev|publicdev|test)
333             true
334             ;;
335         *)
336             echo "Argument to $subcmd must be one of localdemo, publicdemo, dev, publicdev, test"
337             exit 1
338         ;;
339     esac
340 }
341
342 subcmd="$1"
343 if test -n "$subcmd" ; then
344     shift
345 fi
346 case "$subcmd" in
347     build)
348         check $@
349         build $@
350         ;;
351
352     rebuild)
353         check $@
354         NO_CACHE=--no-cache build $@
355         ;;
356
357     start|run)
358         check $@
359         run $@
360         ;;
361
362     sh*)
363         exec docker exec -ti -e LINES=$(tput lines) -e COLUMNS=$(tput cols) -e TERM=$TERM -e GEM_HOME=/var/lib/gems $ARVBOX_CONTAINER /bin/bash
364         ;;
365
366     pipe)
367         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash -
368         ;;
369
370     stop)
371         stop
372         ;;
373
374     restart)
375         check $@
376         stop
377         run $@
378         ;;
379
380     reboot)
381         check $@
382         stop
383         build $@
384         run $@
385         ;;
386
387     ip)
388         getip
389         ;;
390
391     host)
392         gethost
393         ;;
394
395     open)
396         exec xdg-open http://$(gethost)
397         ;;
398
399     status)
400         echo "Container: $ARVBOX_CONTAINER"
401         if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
402             echo "Cluster id: $(getclusterid)"
403             echo "Status: running"
404             echo "Container IP: $(getip)"
405             echo "Published host: $(gethost)"
406         else
407             echo "Status: not running"
408         fi
409         if test -d "$ARVBOX_DATA" ; then
410             echo "Data: $ARVBOX_DATA"
411         elif docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q ; then
412             echo "Data: $ARVBOX_CONTAINER-data"
413         else
414             echo "Data: none"
415         fi
416         ;;
417
418     reset|destroy)
419         stop
420         if test -d "$ARVBOX_DATA" ; then
421             if test "$subcmd" = destroy ; then
422                 if test "$1" != -f ; then
423                     echo "WARNING!  This will delete your entire arvbox ($ARVBOX_DATA)."
424                     echo "Use destroy -f if you really mean it."
425                     exit 1
426                 fi
427                 set -x
428                 rm -rf "$ARVBOX_DATA"
429             else
430                 if test "$1" != -f ; then
431                     echo "WARNING!  This will delete your arvbox data ($ARVBOX_DATA)."
432                     echo "Code and downloaded packages will be preserved."
433                     echo "Use reset -f if you really mean it."
434                     exit 1
435                 fi
436                 set -x
437                 rm -rf "$ARVBOX_DATA/postgres"
438                 rm -rf "$ARVBOX_DATA/var"
439             fi
440         else
441             if test "$1" != -f ; then
442                 echo "WARNING!  This will delete your data container $ARVBOX_CONTAINER-data.  Use -f if you really mean it."
443                 exit 1
444             fi
445             set -x
446             docker rm "$ARVBOX_CONTAINER-data"
447         fi
448         ;;
449
450     log)
451         if test -n "$1" ; then
452             exec docker exec -ti -e LINES=$(tput lines) -e COLUMNS=$(tput cols) -e TERM=$TERM $ARVBOX_CONTAINER less --follow-name -R +GF "/etc/service/$1/log/main/current"
453         else
454             exec docker exec -ti $ARVBOX_CONTAINER tail $(docker exec -ti $ARVBOX_CONTAINER find -L /etc -path '/etc/service/*/log/main/current' -printf " %p")
455         fi
456         ;;
457
458     cat)
459         if test -n "$1" ; then
460             exec docker exec $ARVBOX_CONTAINER cat "$@"
461         else
462             echo "Usage: $0 $subcmd <files>"
463         fi
464         ;;
465
466     ls)
467         exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM ls "$@"
468         ;;
469
470     sv)
471         if test -n "$1" -a -n "$2" ; then
472             exec docker exec $ARVBOX_CONTAINER sv "$@"
473         else
474             echo "Usage: $0 $subcmd <start|stop|restart> <service>"
475             echo "Available services:"
476             exec docker execa $ARVBOX_CONTAINER ls /etc/service
477         fi
478         ;;
479
480     clone)
481         if test -n "$2" ; then
482             cp -r "$ARVBOX_BASE/$1" "$ARVBOX_BASE/$2"
483             echo "Created new arvbox $2"
484             echo "export ARVBOX_CONTAINER=$2"
485         else
486             echo "clone <from> <to>   clone an arvbox"
487             echo "available arvboxes: $(ls $ARVBOX_BASE)"
488         fi
489         ;;
490
491     *)
492         echo "Arvados-in-a-box                      http://arvados.org"
493         echo
494         echo "build   <config>      build arvbox Docker image"
495         echo "rebuild <config>      build arvbox Docker image, no layer cache"
496         echo "start|run <config> [tag]  start $ARVBOX_CONTAINER container"
497         echo "open       open arvbox workbench in a web browser"
498         echo "shell      enter arvbox shell"
499         echo "ip         print arvbox docker container ip address"
500         echo "host       print arvbox published host"
501         echo "status     print some information about current arvbox"
502         echo "stop       stop arvbox container"
503         echo "restart <config>  stop, then run again"
504         echo "reboot  <config>  stop, build arvbox Docker image, run"
505         echo "reset      delete arvbox arvados data (be careful!)"
506         echo "destroy    delete all arvbox code and data (be careful!)"
507         echo "log <service> tail log of specified service"
508         echo "ls <options>  list directories inside arvbox"
509         echo "cat <files>   get contents of files inside arvbox"
510         echo "pipe       run a bash script piped in from stdin"
511         echo "sv <start|stop|restart> <service> change state of service inside arvbox"
512         echo "clone <from> <to>   clone an arvbox"
513         ;;
514 esac