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