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