12a7f4caf19de1765ff983952f5ad5ea5f9ad5b6
[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=$(tempfile)
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=9001:9001
206               --publish=9002:9002
207               --publish=25100:25100
208               --publish=25107:25107
209               --publish=25108:25108
210               --publish=8001:8001
211               --publish=8002:8002"
212     else
213         PUBLIC=""
214     fi
215
216     if [[ "$CONFIG" =~ demo$ ]] ; then
217         if test -d "$ARVBOX_DATA" ; then
218             echo "It looks like you already have a development container named $ARVBOX_CONTAINER."
219             echo "Set environment variable ARVBOX_CONTAINER to set a different name for your demo container"
220             exit 1
221         fi
222
223         if ! (docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q) ; then
224             docker create -v /var/lib/postgresql -v /var/lib/arvados --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
225         fi
226
227         docker run \
228                --detach \
229                --name=$ARVBOX_CONTAINER \
230                --privileged \
231                --volumes-from $ARVBOX_CONTAINER-data \
232                --label "org.arvados.arvbox_config=$CONFIG" \
233                $PUBLIC \
234                arvados/arvbox-demo$TAG
235         updateconf
236         wait_for_arvbox
237     else
238         mkdir -p "$PG_DATA" "$VAR_DATA" "$PASSENGER" "$GEMS" "$PIPCACHE" "$NPMCACHE" "$GOSTUFF" "$RLIBS"
239
240         if ! test -d "$ARVADOS_ROOT" ; then
241             git clone https://github.com/curoverse/arvados.git "$ARVADOS_ROOT"
242         fi
243         if ! test -d "$SSO_ROOT" ; then
244             git clone https://github.com/curoverse/sso-devise-omniauth-provider.git "$SSO_ROOT"
245         fi
246         if ! test -d "$COMPOSER_ROOT" ; then
247             git clone https://github.com/curoverse/composer.git "$COMPOSER_ROOT"
248             git -C "$COMPOSER_ROOT" checkout arvados-fork
249             git -C "$COMPOSER_ROOT" pull
250         fi
251         if ! test -d "$WORKBENCH2_ROOT" ; then
252             git clone https://github.com/curoverse/arvados-workbench2.git "$WORKBENCH2_ROOT"
253         fi
254
255         if [[ "$CONFIG" = test ]] ; then
256
257             mkdir -p $VAR_DATA/test
258
259             if test "$need_setup" = 1 ; then
260                 docker_run_dev \
261                        --detach \
262                        --name=$ARVBOX_CONTAINER \
263                        --privileged \
264                        "--env=SVDIR=/etc/test-service" \
265                        arvados/arvbox-dev$TAG
266
267                 docker exec -ti \
268                        $ARVBOX_CONTAINER \
269                        /usr/local/lib/arvbox/runsu.sh \
270                        /usr/local/lib/arvbox/waitforpostgres.sh
271
272                 docker exec -ti \
273                        $ARVBOX_CONTAINER \
274                        /usr/local/lib/arvbox/runsu.sh \
275                        /var/lib/arvbox/service/sso/run-service --only-setup
276
277                 docker exec -ti \
278                        $ARVBOX_CONTAINER \
279                        /usr/local/lib/arvbox/runsu.sh \
280                        /var/lib/arvbox/service/api/run-service --only-setup
281             fi
282
283             interactive=""
284             if [[ -z "$@" ]] ; then
285                 interactive=--interactive
286             fi
287
288             docker exec -ti \
289                    -e LINES=$(tput lines) \
290                    -e COLUMNS=$(tput cols) \
291                    -e TERM=$TERM \
292                    -e WORKSPACE=/usr/src/arvados \
293                    -e GEM_HOME=/var/lib/gems \
294                    -e CONFIGSRC=/var/lib/arvados/run_tests \
295                    $ARVBOX_CONTAINER \
296                    /usr/local/lib/arvbox/runsu.sh \
297                    /usr/src/arvados/build/run-tests.sh \
298                    --temp /var/lib/arvados/test \
299                    $interactive \
300                    "$@"
301         elif [[ "$CONFIG" = devenv ]] ; then
302             if [[ $need_setup = 1 ]] ; then
303                 docker_run_dev \
304                     --detach \
305                     --name=${ARVBOX_CONTAINER} \
306                     "--env=SVDIR=/etc/devenv-service" \
307                     "--volume=$HOME:$HOME:rw" \
308                     --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \
309                     arvados/arvbox-dev$TAG
310             fi
311             exec docker exec --interactive --tty \
312                  -e LINES=$(tput lines) \
313                  -e COLUMNS=$(tput cols) \
314                  -e TERM=$TERM \
315                  -e "ARVBOX_HOME=$HOME" \
316                  -e "DISPLAY=$DISPLAY" \
317                  --workdir=$PWD \
318                  ${ARVBOX_CONTAINER} \
319                  /usr/local/lib/arvbox/devenv.sh "$@"
320         elif [[ "$CONFIG" =~ dev$ ]] ; then
321             docker_run_dev \
322                    --detach \
323                    --name=$ARVBOX_CONTAINER \
324                    --privileged \
325                    $PUBLIC \
326                    arvados/arvbox-dev$TAG
327             updateconf
328             wait_for_arvbox
329             echo "The Arvados source code is checked out at: $ARVADOS_ROOT"
330             echo "The Arvados testing root certificate is $VAR_DATA/root-cert.pem"
331         else
332             echo "Unknown configuration '$CONFIG'"
333         fi
334     fi
335 }
336
337 update() {
338     CONFIG=$1
339     TAG=$2
340
341     if test -n "$TAG"
342     then
343         if test $(echo $TAG | cut -c1-1) != '-' ; then
344             TAG=":$TAG"
345             shift
346         else
347             unset TAG
348         fi
349     fi
350
351     if echo "$CONFIG" | grep 'demo$' ; then
352         docker pull arvados/arvbox-demo$TAG
353     else
354         docker pull arvados/arvbox-dev$TAG
355     fi
356 }
357
358 stop() {
359     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
360         docker stop $ARVBOX_CONTAINER
361     fi
362
363     VOLUMES=--volumes=true
364     if docker ps -a --filter "status=created" | grep -E "$ARVBOX_CONTAINER$" -q ; then
365         docker rm $VOLUMES $ARVBOX_CONTAINER
366     fi
367     if docker ps -a --filter "status=exited" | grep -E "$ARVBOX_CONTAINER$" -q ; then
368         docker rm $VOLUMES $ARVBOX_CONTAINER
369     fi
370 }
371
372 build() {
373     if ! test -f "$ARVBOX_DOCKER/Dockerfile.base" ;  then
374         echo "Could not find Dockerfile (expected it at $ARVBOX_DOCKER/Dockerfile.base)"
375         exit 1
376     fi
377     if docker --version |grep " 1\.[0-9]\." ; then
378         # Docker version prior 1.10 require -f flag
379         # -f flag removed in Docker 1.12
380         FORCE=-f
381     fi
382     GITHEAD=$(cd $ARVBOX_DOCKER && git log --format=%H -n1 HEAD)
383     docker build --build-arg=arvados_version=$GITHEAD $NO_CACHE -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVBOX_DOCKER"
384     docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
385     if test "$1" = localdemo -o "$1" = publicdemo ; then
386         docker build $NO_CACHE -t arvados/arvbox-demo:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
387         docker tag $FORCE arvados/arvbox-demo:$GITHEAD arvados/arvbox-demo:latest
388     else
389         docker build $NO_CACHE -t arvados/arvbox-dev:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
390         docker tag $FORCE arvados/arvbox-dev:$GITHEAD arvados/arvbox-dev:latest
391     fi
392 }
393
394 check() {
395     case "$1" in
396         localdemo|publicdemo|dev|publicdev|test|devenv)
397             true
398             ;;
399         *)
400             echo "Argument to $subcmd must be one of localdemo, publicdemo, dev, publicdev, test, devenv"
401             exit 1
402         ;;
403     esac
404 }
405
406 subcmd="$1"
407 if test -n "$subcmd" ; then
408     shift
409 fi
410 case "$subcmd" in
411     build)
412         check $@
413         build $@
414         ;;
415
416     rebuild)
417         check $@
418         NO_CACHE=--no-cache build $@
419         ;;
420
421     start|run)
422         check $@
423         run $@
424         ;;
425
426     sh*)
427         exec docker exec --interactive --tty \
428                -e LINES=$(tput lines) \
429                -e COLUMNS=$(tput cols) \
430                -e TERM=$TERM \
431                -e GEM_HOME=/var/lib/gems \
432                $ARVBOX_CONTAINER /bin/bash
433         ;;
434
435     ash*)
436         exec docker exec --interactive --tty \
437                -e LINES=$(tput lines) \
438                -e COLUMNS=$(tput cols) \
439                -e TERM=$TERM \
440                -e GEM_HOME=/var/lib/gems \
441                -u arvbox \
442                -w /usr/src/arvados \
443                $ARVBOX_CONTAINER /bin/bash --login
444         ;;
445
446     pipe)
447         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash -
448         ;;
449
450     stop)
451         stop
452         ;;
453
454     restart)
455         check $@
456         stop
457         run $@
458         ;;
459
460     reboot)
461         check $@
462         stop
463         build $@
464         run $@
465         ;;
466
467     update)
468         check $@
469         stop
470         update $@
471         run $@
472         ;;
473
474     ip)
475         getip
476         ;;
477
478     host)
479         gethost
480         ;;
481
482     open)
483         exec xdg-open http://$(gethost)
484         ;;
485
486     status)
487         echo "Container: $ARVBOX_CONTAINER"
488         if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
489             echo "Cluster id: $(getclusterid)"
490             echo "Status: running"
491             echo "Container IP: $(getip)"
492             echo "Published host: $(gethost)"
493         else
494             echo "Status: not running"
495         fi
496         if test -d "$ARVBOX_DATA" ; then
497             echo "Data: $ARVBOX_DATA"
498         elif docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q ; then
499             echo "Data: $ARVBOX_CONTAINER-data"
500         else
501             echo "Data: none"
502         fi
503         ;;
504
505     reset|destroy)
506         stop
507         if test -d "$ARVBOX_DATA" ; then
508             if test "$subcmd" = destroy ; then
509                 if test "$1" != -f ; then
510                     echo "WARNING!  This will delete your entire arvbox ($ARVBOX_DATA)."
511                     echo "Use destroy -f if you really mean it."
512                     exit 1
513                 fi
514                 set -x
515                 rm -rf "$ARVBOX_DATA"
516             else
517                 if test "$1" != -f ; then
518                     echo "WARNING!  This will delete your arvbox data ($ARVBOX_DATA)."
519                     echo "Code and downloaded packages will be preserved."
520                     echo "Use reset -f if you really mean it."
521                     exit 1
522                 fi
523                 set -x
524                 rm -rf "$ARVBOX_DATA/postgres"
525                 rm -rf "$ARVBOX_DATA/var"
526             fi
527         else
528             if test "$1" != -f ; then
529                 echo "WARNING!  This will delete your data container $ARVBOX_CONTAINER-data.  Use -f if you really mean it."
530                 exit 1
531             fi
532             set -x
533             docker rm "$ARVBOX_CONTAINER-data"
534         fi
535         ;;
536
537     log)
538         if test -n "$1" ; then
539             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"
540         else
541             exec docker exec -ti $ARVBOX_CONTAINER tail $(docker exec -ti $ARVBOX_CONTAINER find -L /etc -path '/etc/service/*/log/main/current' -printf " %p")
542         fi
543         ;;
544
545     cat)
546         if test -n "$1" ; then
547             exec docker exec $ARVBOX_CONTAINER cat "$@"
548         else
549             echo "Usage: $0 $subcmd <files>"
550         fi
551         ;;
552
553     ls)
554         exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM ls "$@"
555         ;;
556
557     sv)
558         if test -n "$1" -a -n "$2" ; then
559             exec docker exec $ARVBOX_CONTAINER sv "$@"
560         else
561             echo "Usage: $0 $subcmd <start|stop|restart> <service>"
562             echo "Available services:"
563             exec docker execa $ARVBOX_CONTAINER ls /etc/service
564         fi
565         ;;
566
567     clone)
568         if test -n "$2" ; then
569             mkdir -p "$ARVBOX_BASE/$2"
570             cp -a "$ARVBOX_BASE/$1/passenger" \
571                "$ARVBOX_BASE/$1/gems" \
572                "$ARVBOX_BASE/$1/pip" \
573                "$ARVBOX_BASE/$1/npm" \
574                "$ARVBOX_BASE/$1/gopath" \
575                "$ARVBOX_BASE/$1/Rlibs" \
576                "$ARVBOX_BASE/$1/arvados" \
577                "$ARVBOX_BASE/$1/sso-devise-omniauth-provider" \
578                "$ARVBOX_BASE/$1/composer" \
579                "$ARVBOX_BASE/$1/workbench2" \
580                "$ARVBOX_BASE/$2"
581             echo "Created new arvbox $2"
582             echo "export ARVBOX_CONTAINER=$2"
583         else
584             echo "clone <from> <to>   clone an arvbox"
585             echo "available arvboxes: $(ls $ARVBOX_BASE)"
586         fi
587         ;;
588
589     root-cert)
590         CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.crt
591         if test -n "$1" ; then
592             CERT="$1"
593         fi
594         docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/root-cert.pem > "$CERT"
595         echo "Certificate copied to $CERT"
596         ;;
597
598     psql)
599         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'
600         ;;
601
602     checkpoint)
603         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'
604         ;;
605
606     restore)
607         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'
608         ;;
609
610     hotreset)
611         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash - <<EOF
612 sv stop api
613 sv stop controller
614 sv stop websockets
615 sv stop keepstore0
616 sv stop keepstore1
617 sv stop keepproxy
618 cd /usr/src/arvados/services/api
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