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