Merge branch '16314-testuserdb'
[arvados.git] / tools / arvbox / bin / arvbox
1 #!/bin/bash
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     set +e
23     if which greadlink >/dev/null 2>/dev/null ; then
24         ARVBOX_DOCKER=$(greadlink -f $(dirname $0)/../lib/arvbox/docker)
25     else
26         ARVBOX_DOCKER=$(readlink -f $(dirname $0)/../lib/arvbox/docker)
27     fi
28     set -e
29 fi
30
31 if test -z "$ARVBOX_CONTAINER" ; then
32     ARVBOX_CONTAINER=arvbox
33 fi
34
35 if test -z "$ARVBOX_BASE" ; then
36     ARVBOX_BASE="$HOME/.arvbox"
37 fi
38
39 if test -z "$ARVBOX_DATA" ; then
40     ARVBOX_DATA="$ARVBOX_BASE/$ARVBOX_CONTAINER"
41 fi
42
43 if test -z "$ARVADOS_ROOT" ; then
44     ARVADOS_ROOT="$ARVBOX_DATA/arvados"
45 fi
46
47 if test -z "$SSO_ROOT" ; then
48     SSO_ROOT="$ARVBOX_DATA/sso-devise-omniauth-provider"
49 fi
50
51 if test -z "$COMPOSER_ROOT" ; then
52     COMPOSER_ROOT="$ARVBOX_DATA/composer"
53 fi
54
55 if test -z "$WORKBENCH2_ROOT" ; then
56     WORKBENCH2_ROOT="$ARVBOX_DATA/workbench2"
57 fi
58
59 PG_DATA="$ARVBOX_DATA/postgres"
60 VAR_DATA="$ARVBOX_DATA/var"
61 PASSENGER="$ARVBOX_DATA/passenger"
62 GEMS="$ARVBOX_DATA/gems"
63 PIPCACHE="$ARVBOX_DATA/pip"
64 NPMCACHE="$ARVBOX_DATA/npm"
65 GOSTUFF="$ARVBOX_DATA/gopath"
66 RLIBS="$ARVBOX_DATA/Rlibs"
67
68 getip() {
69     docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $ARVBOX_CONTAINER
70 }
71
72 gethost() {
73     set +e
74     OVERRIDE=$(docker exec -i $ARVBOX_CONTAINER cat /var/run/localip_override 2>/dev/null)
75     CODE=$?
76     set -e
77     if test "$CODE" = 0 ; then
78        echo $OVERRIDE
79     else
80         getip
81     fi
82 }
83
84 getclusterid() {
85     docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/api_uuid_prefix
86 }
87
88 updateconf() {
89     if test -f ~/.config/arvados/$ARVBOX_CONTAINER.conf ; then
90         sed "s/ARVADOS_API_HOST=.*/ARVADOS_API_HOST=$(gethost):8000/" <$HOME/.config/arvados/$ARVBOX_CONTAINER.conf >$HOME/.config/arvados/$ARVBOX_CONTAINER.conf.tmp
91         mv ~/.config/arvados/$ARVBOX_CONTAINER.conf.tmp ~/.config/arvados/$ARVBOX_CONTAINER.conf
92     else
93         mkdir -p $HOME/.config/arvados
94         cat >$HOME/.config/arvados/$ARVBOX_CONTAINER.conf <<EOF
95 ARVADOS_API_HOST=$(gethost):8000
96 ARVADOS_API_TOKEN=
97 ARVADOS_API_HOST_INSECURE=true
98 EOF
99     fi
100 }
101
102 wait_for_arvbox() {
103     FF=/tmp/arvbox-fifo-$$
104     mkfifo $FF
105     docker logs -f $ARVBOX_CONTAINER > $FF &
106     LOGPID=$!
107     while read line ; do
108         if [[ $line =~ "ok: down: ready:" ]] ; then
109             kill $LOGPID
110             set +e
111             wait $LOGPID 2>/dev/null
112             set -e
113         else
114             echo $line
115         fi
116     done < $FF
117     rm $FF
118     echo
119     if test -n "$localip" ; then
120         echo "export ARVADOS_API_HOST=$localip:8000"
121     else
122         echo "export ARVADOS_API_HOST=$(gethost):8000"
123     fi
124 }
125
126 docker_run_dev() {
127     docker run \
128            "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
129            "--volume=$SSO_ROOT:/usr/src/sso:rw" \
130            "--volume=$COMPOSER_ROOT:/usr/src/composer:rw" \
131            "--volume=$WORKBENCH2_ROOT:/usr/src/workbench2:rw" \
132            "--volume=$PG_DATA:/var/lib/postgresql:rw" \
133            "--volume=$VAR_DATA:/var/lib/arvados:rw" \
134            "--volume=$PASSENGER:/var/lib/passenger:rw" \
135            "--volume=$GEMS:/var/lib/gems:rw" \
136            "--volume=$PIPCACHE:/var/lib/pip:rw" \
137            "--volume=$NPMCACHE:/var/lib/npm:rw" \
138            "--volume=$GOSTUFF:/var/lib/gopath:rw" \
139            "--volume=$RLIBS:/var/lib/Rlibs:rw" \
140            --label "org.arvados.arvbox_config=$CONFIG" \
141            "$@"
142 }
143
144 running_config() {
145     docker inspect $ARVBOX_CONTAINER -f '{{index .Config.Labels "org.arvados.arvbox_config"}}'
146 }
147
148 run() {
149     CONFIG=$1
150     TAG=$2
151
152     shift
153
154     need_setup=1
155
156     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
157         if [[ $(running_config) != "$CONFIG" ]] ; then
158             echo "Container $ARVBOX_CONTAINER is '$(running_config)' config but requested '$CONFIG'; use restart or reboot"
159             return 1
160         fi
161         if test "$CONFIG" = test -o "$CONFIG" = devenv ; then
162             need_setup=0
163         else
164             echo "Container $ARVBOX_CONTAINER is already running"
165             return 0
166         fi
167     fi
168
169     if test $need_setup = 1 ; then
170         if docker ps -a | grep -E "$ARVBOX_CONTAINER$" -q ; then
171             echo "Container $ARVBOX_CONTAINER already exists but is not running; use restart or reboot"
172             return 1
173         fi
174     fi
175
176     if test -n "$TAG"
177     then
178         if test $(echo $TAG | cut -c1-1) != '-' ; then
179             TAG=":$TAG"
180             shift
181         else
182             if [[ $TAG = '-' ]] ; then
183                 shift
184             fi
185             unset TAG
186         fi
187     fi
188
189     if [[ "$CONFIG" =~ ^public ]] ; then
190         if test -n "$ARVBOX_PUBLISH_IP" ; then
191             localip=$ARVBOX_PUBLISH_IP
192         else
193             defaultdev=$(/sbin/ip route|awk '/default/ { print $5 }')
194             localip=$(ip addr show $defaultdev | grep 'inet ' | sed 's/ *inet \(.*\)\/.*/\1/')
195         fi
196         echo "Public arvbox will use address $localip"
197         iptemp=$(mktemp)
198         echo $localip > $iptemp
199         chmod og+r $iptemp
200         PUBLIC="--volume=$iptemp:/var/run/localip_override
201               --publish=443:443
202               --publish=3001:3001
203               --publish=8000:8000
204               --publish=8900:8900
205               --publish=9000:9000
206               --publish=9002:9002
207               --publish=25101:25101
208               --publish=8001:8001
209               --publish=8002:8002
210               --publish=45000-45020:45000-45020"
211     else
212         PUBLIC=""
213     fi
214
215     if [[ "$CONFIG" =~ demo$ ]] ; then
216         if test -d "$ARVBOX_DATA" ; then
217             echo "It looks like you already have a development container named $ARVBOX_CONTAINER."
218             echo "Set environment variable ARVBOX_CONTAINER to set a different name for your demo container"
219             exit 1
220         fi
221
222         if ! (docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q) ; then
223             docker create -v /var/lib/postgresql -v /var/lib/arvados --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
224         fi
225
226         docker run \
227                --detach \
228                --name=$ARVBOX_CONTAINER \
229                --privileged \
230                --volumes-from $ARVBOX_CONTAINER-data \
231                --label "org.arvados.arvbox_config=$CONFIG" \
232                $PUBLIC \
233                arvados/arvbox-demo$TAG
234         updateconf
235         wait_for_arvbox
236     else
237         mkdir -p "$PG_DATA" "$VAR_DATA" "$PASSENGER" "$GEMS" "$PIPCACHE" "$NPMCACHE" "$GOSTUFF" "$RLIBS"
238
239         if ! test -d "$ARVADOS_ROOT" ; then
240             git clone https://git.arvados.org/arvados.git "$ARVADOS_ROOT"
241         fi
242         if ! test -d "$SSO_ROOT" ; then
243             git clone https://github.com/arvados/sso-devise-omniauth-provider.git "$SSO_ROOT"
244         fi
245         if ! test -d "$COMPOSER_ROOT" ; then
246             git clone https://github.com/arvados/composer.git "$COMPOSER_ROOT"
247             git -C "$COMPOSER_ROOT" checkout arvados-fork
248             git -C "$COMPOSER_ROOT" pull
249         fi
250         if ! test -d "$WORKBENCH2_ROOT" ; then
251             git clone https://github.com/arvados/arvados-workbench2.git "$WORKBENCH2_ROOT"
252         fi
253
254         if [[ "$CONFIG" = test ]] ; then
255
256             mkdir -p $VAR_DATA/test
257
258             if test "$need_setup" = 1 ; then
259                 docker_run_dev \
260                        --detach \
261                        --name=$ARVBOX_CONTAINER \
262                        --privileged \
263                        "--env=SVDIR=/etc/test-service" \
264                        arvados/arvbox-dev$TAG
265
266                 docker exec -ti \
267                        $ARVBOX_CONTAINER \
268                        /usr/local/lib/arvbox/runsu.sh \
269                        /usr/local/lib/arvbox/waitforpostgres.sh
270
271                 docker exec -ti \
272                        $ARVBOX_CONTAINER \
273                        /usr/local/lib/arvbox/runsu.sh \
274                        /var/lib/arvbox/service/sso/run-service --only-setup
275
276                 docker exec -ti \
277                        $ARVBOX_CONTAINER \
278                        /usr/local/lib/arvbox/runsu.sh \
279                        /var/lib/arvbox/service/api/run-service --only-setup
280             fi
281
282             interactive=""
283             if [[ -z "$@" ]] ; then
284                 interactive=--interactive
285             fi
286
287             docker exec -ti \
288                    -e LINES=$(tput lines) \
289                    -e COLUMNS=$(tput cols) \
290                    -e TERM=$TERM \
291                    -e WORKSPACE=/usr/src/arvados \
292                    -e GEM_HOME=/var/lib/gems \
293                    -e CONFIGSRC=/var/lib/arvados/run_tests \
294                    $ARVBOX_CONTAINER \
295                    /usr/local/lib/arvbox/runsu.sh \
296                    /usr/src/arvados/build/run-tests.sh \
297                    --temp /var/lib/arvados/test \
298                    $interactive \
299                    "$@"
300         elif [[ "$CONFIG" = devenv ]] ; then
301             if [[ $need_setup = 1 ]] ; then
302                 docker_run_dev \
303                     --detach \
304                     --name=${ARVBOX_CONTAINER} \
305                     "--env=SVDIR=/etc/devenv-service" \
306                     "--volume=$HOME:$HOME:rw" \
307                     --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \
308                     arvados/arvbox-dev$TAG
309             fi
310             exec docker exec --interactive --tty \
311                  -e LINES=$(tput lines) \
312                  -e COLUMNS=$(tput cols) \
313                  -e TERM=$TERM \
314                  -e "ARVBOX_HOME=$HOME" \
315                  -e "DISPLAY=$DISPLAY" \
316                  --workdir=$PWD \
317                  ${ARVBOX_CONTAINER} \
318                  /usr/local/lib/arvbox/devenv.sh "$@"
319         elif [[ "$CONFIG" =~ dev$ ]] ; then
320             docker_run_dev \
321                    --detach \
322                    --name=$ARVBOX_CONTAINER \
323                    --privileged \
324                    $PUBLIC \
325                    arvados/arvbox-dev$TAG
326             updateconf
327             wait_for_arvbox
328             echo "The Arvados source code is checked out at: $ARVADOS_ROOT"
329             echo "The Arvados testing root certificate is $VAR_DATA/root-cert.pem"
330         else
331             echo "Unknown configuration '$CONFIG'"
332         fi
333     fi
334 }
335
336 update() {
337     CONFIG=$1
338     TAG=$2
339
340     if test -n "$TAG"
341     then
342         if test $(echo $TAG | cut -c1-1) != '-' ; then
343             TAG=":$TAG"
344             shift
345         else
346             unset TAG
347         fi
348     fi
349
350     if echo "$CONFIG" | grep 'demo$' ; then
351         docker pull arvados/arvbox-demo$TAG
352     else
353         docker pull arvados/arvbox-dev$TAG
354     fi
355 }
356
357 stop() {
358     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
359         docker stop $ARVBOX_CONTAINER
360     fi
361
362     VOLUMES=--volumes=true
363     if docker ps -a --filter "status=created" | grep -E "$ARVBOX_CONTAINER$" -q ; then
364         docker rm $VOLUMES $ARVBOX_CONTAINER
365     fi
366     if docker ps -a --filter "status=exited" | grep -E "$ARVBOX_CONTAINER$" -q ; then
367         docker rm $VOLUMES $ARVBOX_CONTAINER
368     fi
369 }
370
371 build() {
372     if ! test -f "$ARVBOX_DOCKER/Dockerfile.base" ;  then
373         echo "Could not find Dockerfile (expected it at $ARVBOX_DOCKER/Dockerfile.base)"
374         exit 1
375     fi
376     if docker --version |grep " 1\.[0-9]\." ; then
377         # Docker version prior 1.10 require -f flag
378         # -f flag removed in Docker 1.12
379         FORCE=-f
380     fi
381     GITHEAD=$(cd $ARVBOX_DOCKER && git log --format=%H -n1 HEAD)
382     docker build --build-arg=arvados_version=$GITHEAD $NO_CACHE -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVBOX_DOCKER"
383     docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
384     if test "$1" = localdemo -o "$1" = publicdemo ; then
385         docker build $NO_CACHE -t arvados/arvbox-demo:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
386         docker tag $FORCE arvados/arvbox-demo:$GITHEAD arvados/arvbox-demo:latest
387     else
388         docker build $NO_CACHE -t arvados/arvbox-dev:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
389         docker tag $FORCE arvados/arvbox-dev:$GITHEAD arvados/arvbox-dev:latest
390     fi
391 }
392
393 check() {
394     case "$1" in
395         localdemo|publicdemo|dev|publicdev|test|devenv)
396             true
397             ;;
398         *)
399             echo "Argument to $subcmd must be one of localdemo, publicdemo, dev, publicdev, test, devenv"
400             exit 1
401         ;;
402     esac
403 }
404
405 subcmd="$1"
406 if test -n "$subcmd" ; then
407     shift
408 fi
409 case "$subcmd" in
410     build)
411         check $@
412         build $@
413         ;;
414
415     rebuild)
416         check $@
417         NO_CACHE=--no-cache build $@
418         ;;
419
420     start|run)
421         check $@
422         run $@
423         ;;
424
425     sh*)
426         exec docker exec --interactive --tty \
427                -e LINES=$(tput lines) \
428                -e COLUMNS=$(tput cols) \
429                -e TERM=$TERM \
430                -e GEM_HOME=/var/lib/gems \
431                $ARVBOX_CONTAINER /bin/bash
432         ;;
433
434     ash*)
435         exec docker exec --interactive --tty \
436                -e LINES=$(tput lines) \
437                -e COLUMNS=$(tput cols) \
438                -e TERM=$TERM \
439                -e GEM_HOME=/var/lib/gems \
440                -u arvbox \
441                -w /usr/src/arvados \
442                $ARVBOX_CONTAINER /bin/bash --login
443         ;;
444
445     pipe)
446         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash -
447         ;;
448
449     stop)
450         stop
451         ;;
452
453     restart)
454         check $@
455         stop
456         run $@
457         ;;
458
459     reboot)
460         check $@
461         stop
462         build $@
463         run $@
464         ;;
465
466     update)
467         check $@
468         stop
469         update $@
470         run $@
471         ;;
472
473     ip)
474         getip
475         ;;
476
477     host)
478         gethost
479         ;;
480
481     open)
482         exec xdg-open http://$(gethost)
483         ;;
484
485     status)
486         echo "Container: $ARVBOX_CONTAINER"
487         if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
488             echo "Cluster id: $(getclusterid)"
489             echo "Status: running"
490             echo "Container IP: $(getip)"
491             echo "Published host: $(gethost)"
492         else
493             echo "Status: not running"
494         fi
495         if test -d "$ARVBOX_DATA" ; then
496             echo "Data: $ARVBOX_DATA"
497         elif docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q ; then
498             echo "Data: $ARVBOX_CONTAINER-data"
499         else
500             echo "Data: none"
501         fi
502         ;;
503
504     reset|destroy)
505         stop
506         if test -d "$ARVBOX_DATA" ; then
507             if test "$subcmd" = destroy ; then
508                 if test "$1" != -f ; then
509                     echo "WARNING!  This will delete your entire arvbox ($ARVBOX_DATA)."
510                     echo "Use destroy -f if you really mean it."
511                     exit 1
512                 fi
513                 set -x
514                 rm -rf "$ARVBOX_DATA"
515             else
516                 if test "$1" != -f ; then
517                     echo "WARNING!  This will delete your arvbox data ($ARVBOX_DATA)."
518                     echo "Code and downloaded packages will be preserved."
519                     echo "Use reset -f if you really mean it."
520                     exit 1
521                 fi
522                 set -x
523                 rm -rf "$ARVBOX_DATA/postgres"
524                 rm -rf "$ARVBOX_DATA/var"
525             fi
526         else
527             if test "$1" != -f ; then
528                 echo "WARNING!  This will delete your data container $ARVBOX_CONTAINER-data.  Use -f if you really mean it."
529                 exit 1
530             fi
531             set -x
532             docker rm "$ARVBOX_CONTAINER-data"
533         fi
534         ;;
535
536     log)
537         if test -n "$1" ; then
538             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"
539         else
540             exec docker exec -ti $ARVBOX_CONTAINER tail $(docker exec -ti $ARVBOX_CONTAINER find -L /etc -path '/etc/service/*/log/main/current' -printf " %p")
541         fi
542         ;;
543
544     cat)
545         if test -n "$1" ; then
546             exec docker exec $ARVBOX_CONTAINER cat "$@"
547         else
548             echo "Usage: $0 $subcmd <files>"
549         fi
550         ;;
551
552     ls)
553         exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM ls "$@"
554         ;;
555
556     sv)
557         if test -n "$1" -a -n "$2" ; then
558             exec docker exec $ARVBOX_CONTAINER sv "$@"
559         else
560             echo "Usage: $0 $subcmd <start|stop|restart> <service>"
561             echo "Available services:"
562             exec docker execa $ARVBOX_CONTAINER ls /etc/service
563         fi
564         ;;
565
566     clone)
567         if test -n "$2" ; then
568             mkdir -p "$ARVBOX_BASE/$2"
569             cp -a "$ARVBOX_BASE/$1/passenger" \
570                "$ARVBOX_BASE/$1/gems" \
571                "$ARVBOX_BASE/$1/pip" \
572                "$ARVBOX_BASE/$1/npm" \
573                "$ARVBOX_BASE/$1/gopath" \
574                "$ARVBOX_BASE/$1/Rlibs" \
575                "$ARVBOX_BASE/$1/arvados" \
576                "$ARVBOX_BASE/$1/sso-devise-omniauth-provider" \
577                "$ARVBOX_BASE/$1/composer" \
578                "$ARVBOX_BASE/$1/workbench2" \
579                "$ARVBOX_BASE/$2"
580             echo "Created new arvbox $2"
581             echo "export ARVBOX_CONTAINER=$2"
582         else
583             echo "clone <from> <to>   clone an arvbox"
584             echo "available arvboxes: $(ls $ARVBOX_BASE)"
585         fi
586         ;;
587
588     root-cert)
589         CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.crt
590         if test -n "$1" ; then
591             CERT="$1"
592         fi
593         docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/root-cert.pem > "$CERT"
594         echo "Certificate copied to $CERT"
595         ;;
596
597     psql)
598         exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados'
599         ;;
600
601     checkpoint)
602         exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec pg_dump --host=localhost --username=arvados --clean arvados_development > /var/lib/arvados/checkpoint.sql'
603         ;;
604
605     restore)
606         exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados --quiet --file=/var/lib/arvados/checkpoint.sql'
607         ;;
608
609     hotreset)
610         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash - <<EOF
611 sv stop api
612 sv stop controller
613 sv stop websockets
614 sv stop keepstore0
615 sv stop keepstore1
616 sv stop keepproxy
617 cd /usr/src/arvados/services/api
618 export DISABLE_DATABASE_ENVIRONMENT_CHECK=1
619 export RAILS_ENV=development
620 bundle exec rake db:drop
621 rm /var/lib/arvados/api_database_setup
622 rm /var/lib/arvados/superuser_token
623 rm /var/lib/arvados/keep0-uuid
624 rm /var/lib/arvados/keep1-uuid
625 rm /var/lib/arvados/keepproxy-uuid
626 sv start api
627 sv start controller
628 sv start websockets
629 sv restart keepstore0
630 sv restart keepstore1
631 sv restart keepproxy
632 EOF
633         ;;
634
635     *)
636         echo "Arvados-in-a-box             https://doc.arvados.org/install/arvbox.html"
637         echo
638         echo "start|run <config> [tag]   start $ARVBOX_CONTAINER container"
639         echo "stop               stop arvbox container"
640         echo "restart <config>   stop, then run again"
641         echo "status             print some information about current arvbox"
642         echo "ip                 print arvbox docker container ip address"
643         echo "host               print arvbox published host"
644         echo "shell              enter shell as root"
645         echo "ashell             enter shell as 'arvbox'"
646         echo "psql               enter postgres console"
647         echo "open               open arvbox workbench in a web browser"
648         echo "root-cert          get copy of root certificate"
649         echo "update  <config>   stop, pull latest image, run"
650         echo "build   <config>   build arvbox Docker image"
651         echo "reboot  <config>   stop, build arvbox Docker image, run"
652         echo "rebuild <config>   build arvbox Docker image, no layer cache"
653         echo "checkpoint         create database backup"
654         echo "restore            restore checkpoint"
655         echo "hotreset           reset database and restart API without restarting container"
656         echo "reset              delete arvbox arvados data (be careful!)"
657         echo "destroy            delete all arvbox code and data (be careful!)"
658         echo "log <service>      tail log of specified service"
659         echo "ls <options>       list directories inside arvbox"
660         echo "cat <files>        get contents of files inside arvbox"
661         echo "pipe               run a bash script piped in from stdin"
662         echo "sv <start|stop|restart> <service> "
663         echo "                   change state of service inside arvbox"
664         echo "clone <from> <to>  clone dev arvbox"
665         ;;
666 esac