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