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