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