forked from nickjer/singularity-r
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrstudio_adv
executable file
·815 lines (695 loc) · 22.8 KB
/
rstudio_adv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
#!/bin/bash
set -ue
# Required environment variables, provide before calling/sourceing this script.
# Per default, these are provided by the "rstudio" script of this container.
#
# Directory (host path) that shall be mounted as the project directory
# inside the container. If the current working directory deviates from the
# project dir, changing the working directory accordingly inside the
# container is attempted
: ${PROJECT_DIR}
# Path where the project directory is mounted inside the container
: "${BIND_PROJECT_TO}"
# Path to the container SIF file
: "${CONTAINER}"
# Path (host system) where the session data of different RStudio Server
# sessions is stored. Per session, a subfolder is created that is mounted to
# ~/.rstudio inside the container. Also, the .pid files are created here,
# holding information about network port, host machine and more.
: "${DIR_RUN}"
# IP adress to bind the server to. Probably this is "127.0.0.1". Binding to
# non-localhost adresses has security implications as the connection is not
# encrypted.
: "${ADDRESS}"
# Minimum and maximum of the port range to scan for a free port for a newly
# started RStudio Server
: "${PORT_MIN}"
: "${PORT_MAX}"
# Arrays that can be set. Do not check for presence because in bash,
# empty arrays look like unset variables...
# Array of arguments that are forwarded to "singularity instance". If no
# instance is started (function cexec()), they are forwarded to singularity
# exec
# : "${ARGS_INSTANCE[@]}"
# Array of arguments that are forwarded to singularity exec, for example when
# executing the rserver binary in the container or the cexec() function
# : "${ARGS_EXEC[@]}"
thisdir="$(dirname "${BASH_SOURCE[0]}")"
help(){
cat <<EOF
Usage: rstudio COMMAND [COMMAND ARGS...]
rstudio COMMAND --help
rstudio --help
Manage RStudio Server sessions in this folder.
Commands:
start Start a new RStudio server session.
list Show the running sessions.
stop Stop a running RStudio server instance.
exec Execute a commmand inside the container.
shell Open a shell in a running RStudio instance.
passwd Set the password to access RStudio.
shell Start a bash shell in the given running instance
create Create a new session.
delete Delete a session.
--help Show this help.
Show help for individual commands by appending "--help", e.g.
"./rstudio start --help"
To stop a running RStudio session, use 'rstudio list' to find the
PID and then call 'kill PID', (replacing PID)
EOF
}
# Print a message to standard error
msg(){
if [ "$#" -gt 0 ]; then
printf "$@" >&2
fi
echo >&2
}
die(){ msg "$@" >&2; exit 1; }
get_wd_in_container(){
# Returns: "." if $1 matches with $PROJECT_DIR, "relative/path" if $1
# is a subfolder of the project dir, and "" if $1 is not inside the
# project dir
# If the working dir is inside the project directory, determine the
# corresponding directory inside the container
local p="${PROJECT_DIR}"
local w="${1}"
# normalize trailing slashes
while [ "${p: -1}" = "/" ]; do p="${p%/}"; done
while [ "${w: -1}" = "/" ]; do w="${w%/}"; done
p="${p}/"
w="${w}/"
# each path now has exactly one slash at the end. This makes sure that
# /home/user/myproject is not counted as subfolder of /home/user/my
if [ ! "${w::${#p}}" = "$p" ]; then
echo ""
return
fi
w="${BIND_PROJECT_TO}/${w:${#p}}"
echo "$w"
}
list(){
local verbose=
while [ $# -gt 0 ]; do
c="$1"
if [ "$c" = "-v" ]; then
local verbose="yes"
shift 1
else
msg "Wrong usage of 'list' command, see ./rstudio --help"
exit 1
fi
done
shopt -s nullglob
local rundirs=("$DIR_RUN"/*.rstudio)
shopt -u nullglob
if [ ${#rundirs[@]} = 0 ]; then
msg "\nNo RStudio sessions running in this directory.\n"
return 0
fi
if [ "$verbose" = "yes" ]; then
local fmt="%10s %6s %16s %20s %20s %s\n"
printf "$fmt" "ID" "PID" "instance" "address" "hostname" "status"
else
local fmt="%10s %20s %30s %s\n"
printf "$fmt" "ID" "address" "hostname" "status"
fi
for f in "${rundirs[@]}"; do
local id="${f:${#DIR_RUN}:-8}" # strip off directory name and ".pid"
local id="${id:1}" # strip off leading "/"
get_instance_by_id "$id" # -> sets id, pidfile, runfile, PID, instancename, address, hostname, tmpdir, status
if [ "$verbose" = "yes" ]; then
printf "$fmt" "$id" "${PID:--}" "${instancename:--}" "${address:--}" "${hostname:--}" "$status"
else
printf "$fmt" "$id" "${address:--}" "${hostname:--}" "$status"
fi
done
}
create(){
while [ $# -gt 0 ]; do
case "$1" in
--help)
msg "Create a new session. A session has a folder in \"$DIR_RUN\" that"
msg "persists across restarts and contains information like the list"
msg "of open files or last used projects. It does not store code that"
msg "is written using RStudio"
exit 0
;;
--*) msg "Unknown option $1"; exit 1; ;;
--) shift; break; ;;
*) break; ;;
esac
done
local id="${1-default}"
if [[ "$id" = "" || "$id" =~ [^a-zA-Z0-9] ]]; then
msg "Container ID must be alphanumeric and not empty"
exit 1
fi
local rundir="$DIR_RUN/${id}.rstudio"
local pidfile="$DIR_RUN/${id}.pid"
if [ -e "$rundir" ]; then
msg "Instance \"$id\" already exists. Choose a different name"
exit 1
fi
mkdir -p "$rundir"
touch "$pidfile"
}
# Returns values by SETTING GLOBAL VARIABLES:
# pidfile, rundir, PID, instancename, address, hostname, tmpdir
#
get_instance_by_id(){
local reqstatus # required status by command line argument
unset pidfile rundir PID instancename address hostname tmpdir
if [ "${1-}" = "-r" ]; then
reqstatus="running"
shift
elif [ "${1-}" = "-s" ]; then
reqstatus="stopped"
shift
else
reqstatus="any"
fi
local id="$1"
if [[ -z "$id" || "$id" =~ [^a-zA-Z0-9] ]]; then
msg "Container ID must be alphanumeric and not empty"
exit 1
fi
declare -g pidfile rundir
pidfile="$DIR_RUN/${id}.pid"
rundir="$DIR_RUN/${id}.rstudio"
if [ ! -d "$rundir" ]; then
msg ""
msg "RStudio instance with ID '$id' not found. Run ./rstudio list"
msg "for a list of running instances."
msg ""
exit 1
fi
if [ ! -e "$pidfile" ]; then
PID= ; instancename= ; address= ; hostname= ; tmpdir= ; status="non-existent"
else
# Expect that "read" returns an error exit code if the pidfile is
# empty
# This needs bash>=4.2
declare -g PID instancename address hostname tmpdir
set +e
# Reading in each variable separately avoids splitting by whitespace
{ read PID; read instancename; read address; read hostname; read tmpdir; } < "$pidfile"
set -e
if [ -z "$PID" ]; then
status="stopped"
# If the instance runs on this machine, test if it is functional
elif [ "$(uname -n)" = "$hostname" ]; then
# 0 = valid, 1 = no such PID
local pid_valid="$(kill -s 0 "$PID" 2>/dev/null; echo $?; )"
# 1 = no instance, 2 = instance exists
local has_instance="$(singularity instance list "$instancename" | wc -l)"
if [ "$pid_valid" = 0 -a "$has_instance" = 2 ]; then
status=running;
elif [ "$pid_valid" = 1 -a "$has_instance" = 2 ]; then
status="running (BARE INSTANCE)";
else
status="CRASHED"
fi
else
status="unknown (other machine)"
fi
fi
if [[ "$reqstatus" = "running" ]]; then
if [[ "$status" != "running" ]]; then
msg "Instance \"$id\" is not running, but status is: $status"
if [[ $status = "unknown (other machine)" ]]; then
msg ""
msg "This instance is not running on this machine."
msg "%-20s %s" "This machine:" "$(uname -n)"
msg "%-20s %s" "Instance $id runs on:" "$hostname"
msg ""
fi
exit 1
fi
# if watchdog/cleanup process (this script when start() is called) does not exist
if ! kill -s 0 "$PID" 2>/dev/null; then
msg "Instance \"$id\" was terminated uncleanly. Please"
msg "1. Check whether the Singularity instance \"$instancename\""
msg " still exists and terminate it using \"singularity instance stop\"."
msg "2. Remove the temporary directory \"$tmpdir\""
msg "3. Remove the file \"$pidfile\""
fi
fi
if [ "$reqstatus" = "stopped" ]; then
if [[ "$status" != "stopped" && "$status" != "non-existent" ]]; then
msg "Instance \"$id\" is already running on $hostname,"
msg "RStudio address: \"${address:-(none)}\"."
exit 1
fi
fi
}
cexec(){
# Internal argument: which command to perform
mode="$1" # exec or shell
shift
local wd_inside=""
local id=""
while [ "$#" -gt 0 ]; do
case "$1" in
--help)
msg "Usage: exec [options] [--] COMMAND [ARGS...]"
msg " shell [options]"
msg ""
msg "exec: Execute the given command within the container."
msg "shell: Launch an interactive shell (bash -l) within the container"
msg
msg "Options:"
msg " --instance | -i"
msg " Execute the command in a Singularity instance. This saves startup time"
msg " when executing this command many times and cleans up parallel worker"
msg " processes when they are not shut down cleanly by the executed command"
msg " once the instance is shut down (use './rstudio stop' for that)"
msg " --env VAR1=VALUE1,VAR2=VALUE2 | --env-file FILE"
msg " Set environment variables for the command. See the Singularity/Apptainer"
msg " help on the topic 'Environment and Metadata'."
msg " --pwd"
msg " Set the working directory for the command. Default: Current working dir."
msg ""
msg " COMMAND [ARGS...]"
msg " The command and its potential arguments to execute. Default: bash"
exit 0
;;
--instance|-i)
id="$2"
shift 2
;;
--pwd)
if [ -z "${2-}" ]; then msg "Missing argument to --pwd"; exit 1; fi
wd_inside="${2}"
shift 2
;;
--env|--env-file)
ARGS_EXEC+=( "$1" "$2" ) # forward to Singularity
shift 2
;;
--*)
echo "Unknown argument '$1'" >&2
exit 1
;;
--) shift; break; ;;
*) break; ;;
esac
done
echo $@
if [[ $mode = "cexec" && "$#" = 0 ]]; then
die "Command needed (see '$mode --help')"
elif [[ $mode = "shell" && $# -gt 0 ]]; then
die "Extranenous command line arguments '$@'. See '$mode --help'"
fi
# When running without an instance, the instance arguments, such as
# which directories to bind, must be given to the "singularity exec" call instead
if [[ ! -z "$id" ]]; then
args=( "${ARGS_EXEC[@]+"${ARGS_EXEC[@]}"}" )
if [ ! -d "$DIR_RUN/${id}.rstudio" ]; then
msg "Creating instance \"$id\""
create "$id"
fi
get_instance_by_id "$id" # -> sets id, pidfile, rundir, PID, instancename, address, hostname, tmpdir, status
if [[ $status == "non-existent" ]]; then
msg "Creating instance \"$id\""
create "$id"
fi
if [[ $status != "running" ]]; then
get_instance_by_id -s "$id" # make sure it is stopped properly (or just created)
start --no-rstudio "$id"
get_instance_by_id -r "$id"
fi
sing="instance://$instancename" # singularity container instance
else
sing="$CONTAINER" # singularity container file
fi
if [ -z "$wd_inside" ]; then
wd_inside="$(get_wd_in_container "$PWD")"
fi
if [ "$wd_inside" = "" ]; then
echo "The current working directory '$PWD' is not inside the project directory '$PROJECT_DIR'"
exit 1
fi
ARGS_EXEC+=( --pwd "$wd_inside" )
if [[ $mode = "shell" ]]; then
local cmd=( bash -l );
else
# -c '$@' -> execute what is given as command args.
# why repeat $1 explicitly before $@? See bash -c manual. Second argument
# after -c is used to set the command name ($0) and is not forwarded
local cmd=(bash -l -c '"$@"' "$1" "$@" )
fi
# strange idiom "${arr[@]+"${arr[@]}"}" to guard against the case that arr is
# empty which means for bash<4.4 that it does not exist at all and thus gives
# an error because of set -u at the script beginning.....
if [[ -z "$id" ]]; then
# Run without a Singularity instance
singularity exec \
"${ARGS_INSTANCE[@]+"${ARGS_INSTANCE[@]}"}" \
"${ARGS_EXEC[@]+"${ARGS_EXEC[@]}"}" \
"$CONTAINER" "${cmd[@]}"
else
# Run within a singularity instance
ARGS_INSTANCE+=(
-B "$rundir/var-lib:/var/lib/rstudio-server"
-B "$rundir/rstudio:$BIND_PROJECT_TO/.local/share/rstudio" )
singularity exec }
-W "$tmpdir" \
-B "$tmpdir:/var/run" \
"${ARGS_EXEC[@]+"${ARGS_EXEC[@]}"}" \
"instance://$instancename" "${cmd[@]}"
fi
}
delete(){
if [ "$#" == 0 -o "${1-}" == "--help" ]; then
msg "Usage: rstudio delete INSTANCENAME"
if [ "${1-}" == "--help" ]; then
msg ""
msg "Delete the given container instance. This removes information like"
msg "the list of open files or projects and unsaved files. It does not delete"
msg "saved code or data. Technically, this command removes the folder"
msg "\"$DIR_RUN/INSTANCENAME.rstudio\" and \"INSTANCENAME.pid\"."
msg ""
exit 0
else
exit 1
fi
fi
local id="${1}"
get_instance_by_id "$id" # -> sets id, pidfile, rundir, PID, instancename, address, hostname, tmpdir, status
case "$status" in
"CRASHED"|"stopped") : ; ;; # ok, we can delete
"running") die "Cannot delete \"$id\" because it is running on $hostname"; ;;
"non-existent") die "Instance \"$id\" does not exist."; ;;
"unknown (other machine)") get_instance_by_id -s ; ;; # re-use error message from that function
*) die "Cannot delete \"$id\"; Status \"$status\""; ;;
esac
rm -r "$rundir"
rm "$pidfile"
}
rstudio_passwd(){
if [ ! $# = 0 ]; then
msg "Usage: rstudio passwd"
msg "Use --help for more info."
# --help is handled by rstudio_passwd program
exit 1
fi
cexec exec /usr/lib/rstudio-server/bin/rstudio_passwd "$@"
}
make_temp(){
local tmpdir="$(command mktemp -d -t rstudio-XXXXXXXX)"
# We delete this directory afterwards, so its important that $tmpdir
# really has the path to an empty, temporary dir, and nothing else!
# (for example empty string or home dir)
if [[ ! "$tmpdir" || ! -d "$tmpdir" ]]; then
echo "Error: Could not create temp dir $tmpdir"
exit 1
fi
# check if temp dir is empty
local tmpcontent="$(ls -A "$tmpdir")"
if [ ! -z "$tmpcontent" ]; then
echo "Error: Temp dir '$tmpdir' is not empty"
exit 1
fi
echo "$tmpdir"
}
start(){
local logfile="/dev/null"
local fg="false"
local rstudio="true"
while [ "$#" -gt 0 ]; do
case "$1" in
--log)
if [ "$logfile" = "-" ]; then logfile="/dev/stdout"; fi
logfile="$2"
msg "logging to $logfile"
shift 2
;;
--help)
cat <<EOF
Usage: rstudio start [ID]
Start the given RStudio session. Provide an arbitrary name as ID when running
multiple sessions (Default: "default"). If a session of the given name does
not exist, it is created. A temporaray directory is created and assigned to the
session. A free port is searched and printed to the screen. A singularity
instance is created and RStudio Server is started therein.
Options:
--log FILE Write log output to this file. Use --log - to write to
standard output. Default: no log (/dev/null)
--fg Keep the server running in the foreground. This
disables effects of --log. Status output is forwarded
to the terminal.
--no-rstudio
Do not start RStudio server. Useful to execute multiple
command-line scripts while only taking the time to start
a single Singularity instance
EOF
exit 0
;;
--fg) fg=true; shift; ;;
--no-rstudio) rstudio=false; shift ; ;;
--) shift; break; ;;
*) break; ;;
esac
done
local id="${1-default}"
cd "$PROJECT_DIR" # Server always starts from the project dir.
if [[ ! -e ".rstudio-passwd" ||
"$(cat ".rstudio-passwd" | wc -l)" = 0 ]]; then
cat <<EOF
You need to set a password for RStudio first! You can do this at any time
by calling ./rstudio passwd
EOF
echo -n "Do you want to set the RStudio password now? [y/N] " >&2
local answer
read answer
if [[ $answer =~ [yY] ]]; then
rstudio_passwd
else
exit 1
fi
fi
if [ "$rstudio" = "true" ]; then
local port=$(singularity -s exec "$CONTAINER" /usr/bin/find_port "$ADDRESS" "$PORT_MIN" "$PORT_MAX")
fi
local outerpid="$BASHPID"
local waitforchild="true"
hdl_usr1(){
waitforchild="false"
}
trap hdl_usr1 USR1
runner(){
trap "kill -USR1 $outerpid; rstudio_cleanup" EXIT
set +e
start_instance "$id"
if [[ $? != 0 ]]; then rstudio_cleanup; die "Instance failed to start"; fi
set -e
kill -USR1 "$outerpid" # tell the parent that we're done with starting the instance
trap "rstudio_cleanup" EXIT
if [ "$rstudio" = "true" ]; then
start_rstudio "$id" "$port"
else
get_instance_by_id -r "$id"
singularity exec "instance://$instancename" sleep infinity
fi
}
runner < /dev/null &
disown "$!"
# wait for child that it starts up the Singularity instance
while [[ $waitforchild == "true" ]]; do
sleep 1
done
}
# id: name of the RStudio instance
start_rstudio(){
local id="$1"
local port="$2"
local sendusr1to="${3-}"
get_instance_by_id -r "$id" # -> sets id, pidfile, rundir, PID, instancename, address, hostname, tmpdir, status
if [ ! -d "$DIR_RUN/${id}.rstudio" ]; then
msg "Creating instance \"$id\""
create "$id"
fi
msg ""
msg "Starting RStudio Server on http://$ADDRESS:$port"
msg ""
msg "To log in to RStudio, use your user name and the"
msg "RStudio password for this project."
msg "Call './rstudio passwd' to change the RStudio password."
# Save PID and other infos about the started instance and
# start RStudio server
local pid=$BASHPID
local hostname="$(uname -n)"
cat <<EOF >"$runfile"
$pid
$instancename
$ADDRESS:$port
$hostname
$tmpdir
EOF
set +e
SINGULARITYENV_RSTUDIO_PASSWORD_FILE="$BIND_PROJECT_TO/.rstudio-passwd" \
singularity exec \
"${ARGS_EXEC[@]+"${ARGS_EXEC[@]}"}" \
--pwd "$BIND_PROJECT_TO" \
"instance://$instancename" \
rserver \
--www-address $ADDRESS \
--www-port $port \
--auth-none 0 \
--server-daemonize=no \
--server-user="$USER" \
--auth-pam-helper rstudio_auth_file \
> "$logfile"
set -e
local code=$?
echo "rserver exited with code $code" >> "$logfile"
return "$code"
}
start_instance(){
if [ ! -d "$DIR_RUN/${id}.rstudio" ]; then
msg "Creating instance \"$id\""
create "$id"
fi
get_instance_by_id -s "$id" # -> sets id, pidfile, rundir, PID, instancename, address, hostname, tmpdir, status
# Create a temporary directory
tmpdir="$(make_temp)"
msg "Starting instance \"$id\""
# Start Singularity instance
local instancename="$(basename "$tmpdir")"
runfile="$DIR_RUN/${id}.pid" # declare global, for rstudio_cleanup if things go wrong
local rundir="$DIR_RUN/${id}.rstudio"
if [ ! -d "$rundir" ]; then
create "$id";
msg "Created new container \"$id\""
fi
# Mount RStudio-specific folders. They are created by start_rstudio().
# create them if they don't exist, as rstudio might be started
# in this container later.
mkdir -p "$rundir"
mkdir -p "$rundir/var-lib"
mkdir -p "$rundir/rstudio"
ARGS_INSTANCE+=(
-B "$rundir/var-lib:/var/lib/rstudio-server"
-B "$rundir/rstudio:$BIND_PROJECT_TO/.local/share/rstudio" )
set +e
singularity instance start \
-W "$tmpdir" \
-B "$tmpdir:/var/run" \
"${ARGS_INSTANCE[@]}" \
"$CONTAINER" \
"$instancename"
if [ ! $? = 0 ]; then
set -e
msg "Instance failed to start"
return 1
fi
set -e
# Save PID and other infos. Leave one line free, it will be for $ADRESS:$PORT,
# start_rstudio() will write them.
local pid=$BASHPID
local hostname="$(uname -n)"
cat <<EOF >"$runfile"
$pid
$instancename
$hostname
$tmpdir
EOF
}
# Delete the temporary directory after the end of the script
# GLOBALS: $tmpdir, $runfile, $instancename
# Set these globals e.g. by using get_instance_id() before calling this function
# It does not do it by itself to be able to clean up instances which failed to
# be completely set up (e.g. instance is running but .pid file could not be written)
rstudio_cleanup(){
set +e
if [[ ! -z "$instancename" ]]; then
if singularity instance list | tail -n+2 | grep -q "^$instancename"; then
singularity instance stop "$instancename"
fi
if [[ "$?" == 0 ]]; then echo > "$pidfile"; fi # clear instance info from pidfile
fi
# Remove temporary directories
if [[ ! -z "${tmpdir-}" && -d "${tmpdir-}" ]]; then rm -rf "$tmpdir"; fi
if [[ ! -z "${runfile-}" && -f "${runfile-}" ]]; then echo > "$runfile"; fi
}
stop(){
while [ "$#" -gt 0 ]; do
case "$1" in
--help)
msg "Usage: rstudio stop [ID]"
msg ""
msg "Stop the RStudio instance given by <ID>. If you did not set "
msg "a session name when you started RStudio the instance name is"
msg "probably \"default\"."
msg ""
msg "Run './rstudio list' to get a list of all running instances"
msg "and their IDs".
msg ""
exit 0
;;
--*)
msg "Unknown argument \"$1\""
exit 1
;;
*)
break
;;
esac
done
if [ ! "$#" -gt 0 ]; then
msg "Container ID is missing."
msg ""
msg "Usage: rstudio stop ID"
msg "Use \"./rstudio stop --help for help"
msg "Use \"./rstudio list\" to get a list of IDs"
exit 1
fi
local id="${1}"
get_instance_by_id "$1" # -> sets id, pidfile, rundir, PID, instancename, address, hostname, tmpdir, status
# singularity instance stop "$instancename"
case "$status" in
non-existent)
die "Instance with ID \"$id\" does not exist"
;;
running)
kill "$PID"
;;
"running (BARE INSTANCE)"|CRASHED)
msg "The instance \"$id\" (singularity instance \"$instancename\" crashed."
msg "Re-trying clean shutdown or cleanup"
set -x
rstudio_cleanup
;;
"unknown (other machine)")
get_instance_by_id -r "$id" # reuse the error message in that function
;;
*)
die "Cannot stop instance \"$id\". Status is \"$status\"";
;;
esac
}
if [ $# = 0 ]; then
msg ""
msg "Available commands: "
msg " list, start, stop, exec, passwd, shell create, delete."
msg ""
msg "Type \"./rstudio --help\" for more info."
msg ""
exit 1
else
cmd="$1"
shift
fi
case $cmd in
list) list "$@"; ;;
start) start "$@"; ;;
stop) stop "$@"; ;;
exec) cexec cexec "$@" ; ;;
passwd) rstudio_passwd "$@"; ;;
shell) cexec shell "$@" ; ;;
create) create "$@"; ;;
delete) delete "$@"; ;;
--help) help; ;;
*) msg "Unknown argument. Use --help to show the help for this command"
esac