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