Merge branch 'master' into 9369-arv-cwl-docs
[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     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
108         echo "Container $ARVBOX_CONTAINER is already running"
109         exit 0
110     fi
111
112     if docker ps -a | grep -E "$ARVBOX_CONTAINER$" -q ; then
113         echo "Container $ARVBOX_CONTAINER already exists but is not running; use restart or rebuild"
114         exit 1
115     fi
116    
117     if test ! -z "$TAG"
118     then
119         TAG=":$TAG"
120     fi
121
122     if echo "$CONFIG" | grep '^public' ; then
123         if test -n "$ARVBOX_PUBLISH_IP" ; then
124             localip=$ARVBOX_PUBLISH_IP
125         else
126             defaultdev=$(/sbin/ip route|awk '/default/ { print $5 }')
127             localip=$(ip addr show $defaultdev | grep 'inet ' | sed 's/ *inet \(.*\)\/.*/\1/')
128         fi
129         iptemp=$(tempfile)
130         echo $localip > $iptemp
131         chmod og+r $iptemp
132         PUBLIC="--volume=$iptemp:/var/run/localip_override
133               --publish=80:80
134               --publish=8000:8000
135               --publish=8900:8900
136               --publish=9001:9001
137               --publish=9002:9002
138               --publish=25100:25100
139               --publish=25107:25107
140               --publish=25108:25108
141               --publish=8001:8001
142               --publish=8002:8002"
143     else
144         PUBLIC=""
145     fi
146
147     if echo "$CONFIG" | grep 'demo$' ; then
148         if test -d "$ARVBOX_DATA" ; then
149             echo "It looks like you already have a development container named $ARVBOX_CONTAINER."
150             echo "Set ARVBOX_CONTAINER to set a different name for your demo container"
151             exit 1
152         fi
153
154         if ! (docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q) ; then
155             docker create -v /var/lib/postgresql -v /var/lib/arvados --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
156         fi
157
158         docker run \
159                --detach \
160                --name=$ARVBOX_CONTAINER \
161                --privileged \
162                --volumes-from $ARVBOX_CONTAINER-data \
163                $PUBLIC \
164                arvados/arvbox-demo$TAG
165         updateconf
166         wait_for_arvbox
167     else
168         mkdir -p "$PG_DATA" "$VAR_DATA" "$PASSENGER" "$GEMS" "$PIPCACHE" "$GOSTUFF"
169
170
171         if ! test -d "$ARVADOS_ROOT" ; then
172             git clone https://github.com/curoverse/arvados.git "$ARVADOS_ROOT"
173         fi
174         if ! test -d "$SSO_ROOT" ; then
175             git clone https://github.com/curoverse/sso-devise-omniauth-provider.git "$SSO_ROOT"
176         fi
177
178         if test "$CONFIG" = test ; then
179
180             mkdir -p $VAR_DATA/test
181
182             docker run \
183                    --detach \
184                    --name=$ARVBOX_CONTAINER \
185                    --privileged \
186                    "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
187                    "--volume=$SSO_ROOT:/usr/src/sso:rw" \
188                    "--volume=$PG_DATA:/var/lib/postgresql:rw" \
189                    "--volume=$VAR_DATA:/var/lib/arvados:rw" \
190                    "--volume=$PASSENGER:/var/lib/passenger:rw" \
191                    "--volume=$GEMS:/var/lib/gems:rw" \
192                    "--volume=$PIPCACHE:/var/lib/pip:rw" \
193                    "--volume=$GOSTUFF:/var/lib/gopath:rw" \
194                    arvados/arvbox-dev$TAG \
195                    /usr/local/bin/runsvinit -svdir=/etc/test-service
196
197             docker exec -ti \
198                     $ARVBOX_CONTAINER \
199                     /usr/local/lib/arvbox/runsu.sh \
200                     /usr/local/lib/arvbox/waitforpostgres.sh
201
202             docker exec -ti \
203                    $ARVBOX_CONTAINER \
204                    /usr/local/lib/arvbox/runsu.sh \
205                    /var/lib/arvbox/service/sso/run-service --only-setup
206
207             docker exec -ti \
208                    $ARVBOX_CONTAINER \
209                    /usr/local/lib/arvbox/runsu.sh \
210                    /var/lib/arvbox/service/api/run-service --only-setup
211
212             docker exec -ti \
213                    $ARVBOX_CONTAINER \
214                    /usr/local/lib/arvbox/runsu.sh \
215                    /usr/src/arvados/build/run-tests.sh \
216                    --temp /var/lib/arvados/test \
217                    WORKSPACE=/usr/src/arvados \
218                    GEM_HOME=/var/lib/gems \
219                    "$@"
220         elif echo "$CONFIG" | grep 'dev$' ; then
221             docker run \
222                    --detach \
223                    --name=$ARVBOX_CONTAINER \
224                    --privileged \
225                    "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
226                    "--volume=$SSO_ROOT:/usr/src/sso:rw" \
227                    "--volume=$PG_DATA:/var/lib/postgresql:rw" \
228                    "--volume=$VAR_DATA:/var/lib/arvados:rw" \
229                    "--volume=$PASSENGER:/var/lib/passenger:rw" \
230                    "--volume=$GEMS:/var/lib/gems:rw" \
231                    "--volume=$PIPCACHE:/var/lib/pip:rw" \
232                    "--volume=$GOSTUFF:/var/lib/gopath:rw" \
233                    $PUBLIC \
234                    arvados/arvbox-dev$TAG
235             updateconf
236             wait_for_arvbox
237             echo "The Arvados source code is checked out at: $ARVADOS_ROOT"
238         else
239             echo "Unknown configuration '$CONFIG'"
240         fi
241     fi
242 }
243
244 stop() {
245     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
246         docker stop $ARVBOX_CONTAINER
247     fi
248
249     VOLUMES=--volumes=true
250     if docker ps -a --filter "status=created" | grep -E "$ARVBOX_CONTAINER$" -q ; then
251         docker rm $VOLUMES $ARVBOX_CONTAINER
252     fi
253     if docker ps -a --filter "status=exited" | grep -E "$ARVBOX_CONTAINER$" -q ; then
254         docker rm $VOLUMES $ARVBOX_CONTAINER
255     fi
256 }
257
258 build() {
259     if ! test -f "$ARVBOX_DOCKER/Dockerfile.base" ;  then
260         echo "Could not find Dockerfile (expected it at $ARVBOX_DOCKER/Dockerfile.base)"
261         exit 1
262     fi
263     docker build $NO_CACHE -t arvados/arvbox-base -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVBOX_DOCKER"
264     if test "$1" = localdemo -o "$1" = publicdemo ; then
265         docker build $NO_CACHE -t arvados/arvbox-demo -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
266     else
267         docker build $NO_CACHE -t arvados/arvbox-dev -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
268     fi
269 }
270
271 check() {
272     case "$1" in
273         localdemo|publicdemo|dev|publicdev|test)
274             true
275             ;;
276         *)
277             echo "Argument to $subcmd must be one of localdemo, publicdemo, dev, publicdev, test"
278             exit 1
279         ;;
280     esac
281 }
282
283 subcmd="$1"
284 if test -n "$subcmd" ; then
285     shift
286 fi
287 case "$subcmd" in
288     build)
289         check $@
290         build $@
291         ;;
292
293     rebuild)
294         check $@
295         NO_CACHE=--no-cache build $@
296         ;;
297
298     start|run)
299         check $@
300         run $@
301         ;;
302
303     sh*)
304         exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM GEM_HOME=/var/lib/gems /bin/bash
305         ;;
306
307     pipe)
308         exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash -
309         ;;
310
311     stop)
312         stop
313         ;;
314
315     restart)
316         check $@
317         stop
318         run $@
319         ;;
320
321     reboot)
322         check $@
323         stop
324         build $@
325         run $@
326         ;;
327
328     ip)
329         getip
330         ;;
331
332     host)
333         gethost
334         ;;
335
336     open)
337         exec xdg-open http://$(gethost)
338         ;;
339
340     status)
341         echo "Selected: $ARVBOX_CONTAINER"
342         if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
343             echo "Status: running"
344             echo "Container IP: $(getip)"
345             echo "Published host: $(gethost)"
346         else
347             echo "Status: not running"
348         fi
349         if test -d "$ARVBOX_DATA" ; then
350             echo "Data: $ARVBOX_DATA"
351         elif docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q ; then
352             echo "Data: $ARVBOX_CONTAINER-data"
353         else
354             echo "Data: none"
355         fi
356         ;;
357
358     reset|destroy)
359         stop
360         if test -d "$ARVBOX_DATA" ; then
361             if test "$subcmd" = destroy ; then
362                 if test "$1" != -f ; then
363                     echo "WARNING!  This will delete your entire arvbox ($ARVBOX_DATA)."
364                     echo "Use destroy -f if you really mean it."
365                     exit 1
366                 fi
367                 set -x
368                 rm -rf "$ARVBOX_DATA"
369             else
370                 if test "$1" != -f ; then
371                     echo "WARNING!  This will delete your arvbox data ($ARVBOX_DATA)."
372                     echo "Code and downloaded packages will be preserved."
373                     echo "Use reset -f if you really mean it."
374                     exit 1
375                 fi
376                 set -x
377                 rm -rf "$ARVBOX_DATA/postgres"
378                 rm -rf "$ARVBOX_DATA/var"
379             fi
380         else
381             if test "$1" != -f ; then
382                 echo "WARNING!  This will delete your data container $ARVBOX_CONTAINER-data.  Use -f if you really mean it."
383                 exit 1
384             fi
385             set -x
386             docker rm "$ARVBOX_CONTAINER-data"
387         fi
388         ;;
389
390     log)
391         if test -n "$1" ; then
392             exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM less --follow-name -R +GF "/etc/service/$1/log/main/current"
393         else
394             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")
395         fi
396         ;;
397
398     cat)
399         if test -n "$1" ; then
400             exec docker exec -ti $ARVBOX_CONTAINER cat "$@"
401         else
402             echo "Usage: $0 $subcmd <files>"
403         fi
404         ;;
405
406     ls)
407         exec docker exec -ti $ARVBOX_CONTAINER /usr/bin/env TERM=$TERM ls "$@"
408         ;;
409
410     sv)
411         if test -n "$1" -a -n "$2" ; then
412             exec docker exec -ti $ARVBOX_CONTAINER sv "$@"
413         else
414             echo "Usage: $0 $subcmd <start|stop|restart> <service>"
415             echo "Available services:"
416             exec docker exec -ti $ARVBOX_CONTAINER ls /etc/service
417         fi
418         ;;
419
420     clone)
421         if test -n "$2" ; then
422             cp -r "$ARVBOX_BASE/$1" "$ARVBOX_BASE/$2"
423             echo "Created new arvbox $2"
424             echo "export ARVBOX_CONTAINER=$2"
425         else
426             echo "clone <from> <to>   clone an arvbox"
427             echo "available arvboxes: $(ls $ARVBOX_BASE)"
428         fi
429         ;;
430
431     *)
432         echo "Arvados-in-a-box                      http://arvados.org"
433         echo
434         echo "build   <config>      build arvbox Docker image"
435         echo "rebuild <config>      build arvbox Docker image, no layer cache"
436         echo "start|run <config> [tag]  start $ARVBOX_CONTAINER container"
437         echo "open       open arvbox workbench in a web browser"
438         echo "shell      enter arvbox shell"
439         echo "ip         print arvbox docker container ip address"
440         echo "host       print arvbox published host"
441         echo "status     print some information about current arvbox"
442         echo "stop       stop arvbox container"
443         echo "restart <config>  stop, then run again"
444         echo "reboot  <config>  stop, build arvbox Docker image, run"
445         echo "reset      delete arvbox arvados data (be careful!)"
446         echo "destroy    delete all arvbox code and data (be careful!)"
447         echo "log <service> tail log of specified service"
448         echo "ls <options>  list directories inside arvbox"
449         echo "cat <files>   get contents of files inside arvbox"
450         echo "pipe       run a bash script piped in from stdin"
451         echo "sv <start|stop|restart> <service> change state of service inside arvbox"
452         echo "clone <from> <to>   clone an arvbox"
453         ;;
454 esac