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