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