start_jupyter_nb.sh 19 KB
Newer Older
sfux's avatar
sfux committed
1
2
#!/bin/bash

sfux's avatar
sfux committed
3
4
5
6
###############################################################################
#                                                                             #
#  Script to start a jupyter notebook on Euler from a local computer          #
#                                                                             #
sfux's avatar
sfux committed
7
8
9
#  Main author    : Samuel Fux                                                #
#  Contributions  : Jarunan Panyasantisuk, Andrei Plamada, Swen Vermeul,      #
#                   Urban Borsnik, Steven Armstrong, Henry Lütcke             #
sfux's avatar
sfux committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#  Date           : December 2018                                             #
#  Location       : ETH Zurich                                                #
#  Version        : 1.0                                                       #
#  Change history :                                                           #
#                                                                             #
#  26.10.2021    The script was rewritten:                                    #
#                * clean up of the code (naming scheme for variables)         #
#                * replaced multiline echo's with heredoc's                   #
#                * added command line parser for options                      #
#                * added option for config file                               #
#                * added option for working directory of the notebook         #
#                * added choice for software stack (old/new)                  #
#                * added more bsub options                                    #
#                                                                             #
sfux's avatar
sfux committed
24
#  23.07.2021    Added partial support for windows 10 with git-bash           #
sfux's avatar
sfux committed
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
#                                                                             #
#  17.08.2020    Added a section with configuration options to specify        #
#                non-standard locations for keys                              #
#                                                                             #
#  02.04.2020    Added reconnect_info file that contains all information to   #
#                reconnect to a notebook                                      #
#                                                                             #
#  01.10.2019    Added bash and R kernels for jupyter notebooks               #
#                                                                             #
#  24.01.2019    Added option to specify cluster on which the notebook is     #
#                executed                                                     #
#                                                                             #
###############################################################################

###############################################################################
# Configuration options, initalising variables and setting default values     #
###############################################################################

# Version
JNB_VERSION="1.0"

# Script directory
JNB_SCRIPTDIR=$(pwd)

# hostname of the cluster to connect to
JNB_HOSTNAME="euler.ethz.ch"

# order for initializing configuration options
# 1. Defaults values set inside this script
# 2. Command line options overwrite defaults
# 3. Config file options  overwrite command line options

# Configuration file default    : $HOME/.jnb_config
JNB_CONFIG_FILE="$HOME/.jnb_config"

# Username default              : no default
JNB_USERNAME=""

# Number of CPU cores default   : 1 CPU core
JNB_NUM_CPU=1

# Runtime limit default         : 1:00 hour
JNB_RUN_TIME="01:00"

# Memory default                : 1024 MB per core
JNB_MEM_PER_CPU_CORE=1024

# Number of GPUs default        : 0 GPUs
JNB_NUM_GPU=0

# Waiting interval default      : 60 seconds
JNB_WAITING_INTERVAL=60

# SSH key location default      : no default
JNB_SSH_KEY_PATH=""

# Software stack default        : new
JNB_SOFTWARE_STACK="new"

sfux's avatar
sfux committed
84
85
# Workdir default               : no default
JNB_WORKING_DIR=""
sfux's avatar
sfux committed
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

###############################################################################
# Usage instructions                                                          #
###############################################################################

function display_help {
cat <<-EOF
$0: Script to start a jupyter notebook on Euler from a local computer

Usage: start_jupyter_nb.sh [options]

Options:

        -u | --username       USERNAME         ETH username for SSH connection to Euler
        -n | --numcores       NUM_CPU          Number of CPU cores to be used on the cluster
        -W | --runtime        RUN_TIME         Run time limit for the jupyter notebook in hours and minutes HH:MM
        -m | --memory         MEM_PER_CORE     Memory limit in MB per core

Optional arguments:

        -c | --config         CONFIG_FILE      Configuration file for specifying options
        -g | --numgpu         NUM_GPU          Number of GPUs to be used on the cluster
        -h | --help                            Display help for this script and quit
        -i | --interval       INTERVAL         Time interval for checking if the job on the cluster already started
        -k | --key            SSH_KEY_PATH     Path to SSH key with non-standard name
        -s | --softwarestack  SOFTWARE_STACK   Software stack to be used (old, new)
        -v | --version                         Display version of the script and exit
        -w | --workdir        WORKING_DIR      Working directory for the jupyter notebook

Examlples:

        ./start_jupyter_nb.sh -u sfux -n 4 -W 04:00 -m 2048 -w /cluster/scratch/sfux

        ./start_jupyter_nb.sh --username sfux --numcores 2 --runtime 01:30 --memory 2048 --softwarestack new

        ./start_jupyter_nb.sh -c $HOME/.jnb_config

Format of configuration file:

JNB_USERNAME=""             # ETH username for SSH connection to Euler
JNB_NUM_CPU=1               # Number of CPU cores to be used on the cluster
JNB_NUM_GPU=0               # Number of GPUs to be used on the cluster
JNB_RUN_TIME="01:00"        # Run time limit for the jupyter notebook in hours and minutes HH:MM
JNB_MEM_PER_CPU_CORE=1024   # Memory limit in MB per core
JNB_WAITING_INTERVAL=60     # Time interval to check if the job on the cluster already started
JNB_SSH_KEY_PATH=""         # Path to SSH key with non-standard name
JNB_SOFTWARE_STACK="new"    # Software stack to be used (old, new)
JNB_WORKING_DIR="$HOME"     # Working directory for the jupyter notebook

EOF
exit 1
sfux's avatar
sfux committed
137
138
}

sfux's avatar
sfux committed
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
###############################################################################
# Parse configuration options                                                 #
###############################################################################

while [[ $# -gt 0 ]]
do
        case $1 in
                -h|--help)
                display_help
                ;;
                -v|--version)
                echo -e "start_jupyter_nb.sh version: $JNB_VERSION\n"
                exit
                ;;
                -u|--username)
                JNB_USERNAME=$2
                shift
                shift
                ;;
                -n|--numcores)
                JNB_NUM_CPU=$2
                shift
                shift
                ;;
                -W|--runtime)
                JNB_RUN_TIME=$2
                shift
                shift
                ;;
                -m|--memory)
                JNB_MEM_PER_CPU_CORE=$2
                shift
                shift
                ;;
                -c|--config)
                JNB_CONFIG_FILE=$2
                shift
                shift
                ;;
                -g|--numgpu)
                JNB_NUM_GPU=$2
                shift
                shift
                ;;
                -i|--interval)
                JNB_WAITING_INTERVAL=$2
                shift
                shift
                ;;
                -k|--key)
                JNB_SSH_KEY_PATH=$2
                shift
                shift
                ;;
sfux's avatar
sfux committed
193
                -s|--softwarestack)
sfux's avatar
sfux committed
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
                JNB_SOFTWARE_STACK=$2
                shift
                shift
                ;;
                -w|--workdir)
                JNB_WORKING_DIR=$2
                shift
                shift
                ;;
                *)
                echo -e "Warning: ignoring unknown option $1 \n"
                shift
                ;;
        esac
done

###############################################################################
# Check configuration options                                                 #
###############################################################################

# check if user has a configuration file and source it to initialize options
if [ -f "$JNB_CONFIG_FILE" ]; then
        echo -e "Found configuration file $JNB_CONFIG_FILE"
        echo -e "Initializing configuration from file ${JNB_CONFIG_FILE}:"
        cat "$JNB_CONFIG_FILE"
        source "$JNB_CONFIG_FILE"
sfux's avatar
sfux committed
220
221
fi

sfux's avatar
sfux committed
222
# check that JNB_USERNAME is not an empty string
sfux's avatar
sfux committed
223
224
if [ -z "$JNB_USERNAME" ]
then
sfux's avatar
sfux committed
225
        echo -e "Error: No ETH username is specified, terminating script\n"
sfux's avatar
sfux committed
226
227
228
229
        display_help
else
        echo -e "ETH username: $JNB_USERNAME"
fi
sfux's avatar
sfux committed
230

sfux's avatar
sfux committed
231
# check number of CPU cores
sfux's avatar
sfux committed
232

sfux's avatar
sfux committed
233
# check if JNB_NUM_CPU an integer
sfux's avatar
sfux committed
234
235
236
237
if ! [[ "$JNB_NUM_CPU" =~ ^[0-9]+$ ]]; then
        echo -e "Error: $JNB_NUM_CPU -> Incorrect format. Please specify number of CPU cores as an integer and try again\n"
        display_help
fi
238

sfux's avatar
sfux committed
239
# check if JNB_NUM_CPU is <= 128
sfux's avatar
sfux committed
240
241
242
if [ "$JNB_NUM_CPU" -gt "128" ]; then
        echo -e "Error: $JNB_NUM_CPU -> Larger than 128. No distributed memory supported, therefore the number of CPU cores needs to be smaller or equal to 128\n"
        display_help
243
244
fi

sfux's avatar
sfux committed
245
246
247
248
249
if [ "$JNB_NUM_CPU" -gt "0" ]; then
        echo -e "Requesting $JNB_NUM_CPU CPU cores for running the jupyter notebook"
fi

# check number of GPUs
sfux's avatar
sfux committed
250

sfux's avatar
sfux committed
251
# check if JNB_NUM_GPU an integer
sfux's avatar
sfux committed
252
253
254
255
if ! [[ "$JNB_NUM_GPU" =~ ^[0-9]+$ ]]; then
        echo -e "Error: $JNB_NUM_GPU -> Incorrect format. Please specify the number of GPU as an integer and try again\n"
        display_help
fi
sfux's avatar
sfux committed
256

sfux's avatar
sfux committed
257
# check if JNB_NUM_GPU is <= 8
sfux's avatar
sfux committed
258
if [ "$JNB_NUM_GPU" -gt "8" ]; then
sfux's avatar
sfux committed
259
        echo -e "Error: No distributed memory supported, therefore number of GPUs needs to be smaller or equal to 8\n"
sfux's avatar
sfux committed
260
261
        display_help
fi
sfux's avatar
sfux committed
262

sfux's avatar
sfux committed
263
264
265
266
267
if [ "$JNB_NUM_GPU" -gt "0" ]; then
        echo -e "Requesting $JNB_NUM_GPU GPUs for running the jupyter notebook"
        JNB_SNUM_GPU="-R \"rusage[ngpus_excl_p=$JNB_NUM_GPU]\""
else
        JNB_SNUM_GPU=""
sfux's avatar
sfux committed
268
fi
sfux's avatar
sfux committed
269

sfux's avatar
sfux committed
270
if [ ! "$JNB_NUM_CPU" -gt "0" -a ! "$JNB_NUM_GPU" -gt "0" ]; then
sfux's avatar
sfux committed
271
        echo -e "Error: No CPU and no GPU resources requested, terminating script"
sfux's avatar
sfux committed
272
        display_help
sfux's avatar
sfux committed
273
fi
sfux's avatar
sfux committed
274

sfux's avatar
sfux committed
275
# check if JNB_RUN_TIME is provided in HH:MM format
sfux's avatar
sfux committed
276
277
278
279
280
281
if ! [[ "$JNB_RUN_TIME" =~ ^[0-9][0-9]:[0-9][0-9]$ ]]; then
        echo -e "Error: $JNB_RUN_TIME -> Incorrect format. Please specify runtime limit in the format HH:MM and try again\n"
        display_help
else
    echo -e "Run time limit set to $JNB_RUN_TIME"
fi
sfux's avatar
sfux committed
282

sfux's avatar
sfux committed
283
# check if JNB_MEM_PER_CPU_CORE is an integer
sfux's avatar
sfux committed
284
285
286
if ! [[ "$JNB_MEM_PER_CPU_CORE" =~ ^[0-9]+$ ]]; then
        echo -e "Error: $JNB_MEM_PER_CPU_CORE -> Memory limit must be an integer, please try again\n"
        display_help
sfux's avatar
sfux committed
287
else
sfux's avatar
sfux committed
288
    echo -e "Memory per core set to $JNB_MEM_PER_CPU_CORE MB"
sfux's avatar
sfux committed
289
fi
sfux's avatar
sfux committed
290

sfux's avatar
sfux committed
291
# check if JNB_WAITING_INTERVAL is an integer
sfux's avatar
sfux committed
292
293
294
295
296
297
if ! [[ "$JNB_WAITING_INTERVAL" =~ ^[0-9]+$ ]]; then
        echo -e "Error: $JNB_WAITING_INTERVAL -> Waiting time interval [seconds] must be an integer, please try again\n"
        display_help
else
    echo -e "Setting waiting time interval for checking the start of the job to $JNB_WAITING_INTERVAL seconds"
fi
sfux's avatar
sfux committed
298

sfux's avatar
sfux committed
299
300
301
302
303
304
305
# check which software stack to use
case $JNB_SOFTWARE_STACK in
        old)
        JNB_MODULE_COMMAND="new gcc/4.8.2 r/3.6.0 python/3.6.1 eth_proxy"
        echo -e "Using old software stack (new gcc/4.8.2 r/3.6.0 python/3.6.1 eth_proxy)"
        ;;
        new)
jarunanp's avatar
jarunanp committed
306
307
308
309
310
311
312
        if [ "$JNB_NUM_GPU" -gt "0" ]; then
            JNB_MODULE_COMMAND="gcc/6.3.0 python_gpu/3.8.5 eth_proxy"
            echo -e "Using new software stack (gcc/6.3.0 python_gpu/3.8.5 eth_proxy)"
        else
            JNB_MODULE_COMMAND="gcc/6.3.0 python/3.8.5 eth_proxy"
            echo -e "Using new software stack (gcc/6.3.0 python/3.8.5 eth_proxy)"
        fi  
sfux's avatar
sfux committed
313
314
315
316
317
318
319
        ;;
        *)
        echo -e "Error: $JNB_SOFTWARE_STACK -> Unknown software stack. Software stack either needs to be set to 'new' or 'old'\n"
        display_help
        ;;
esac

sfux's avatar
sfux committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# check if JNB_SSH_KEY_PATH is empty or contains a valid path
if [ -z "$JNB_SSH_KEY_PATH" ]; then
        JNB_SKPATH=""
else
        JNB_SKPATH="-i $JNB_SSH_KEY_PATH"
        echo -e "Using SSH key $JNB_SSH_KEY_PATH"
fi

# check if JNB_WORKING_DIR is empty
if [ -z "$JNB_WORKING_DIR" ]; then
        JNB_SWORK_DIR=""
else
        JNB_SWORK_DIR="--notebook-dir $JNB_WORKING_DIR"
        echo -e "Using $JNB_WORKING_DIR as working directory"
fi

sfux's avatar
sfux committed
336
337
338
339
340
341
# put together string for SSH options
JNB_SSH_OPT="$JNB_SKPATH $JNB_USERNAME@$JNB_HOSTNAME"

###############################################################################
# Check for leftover files                                                    #
###############################################################################
sfux's avatar
sfux committed
342
343

# check if some old files are left from a previous session and delete them
sfux's avatar
sfux committed
344
345

# check for reconnect_info in the current directory on the local computer
sfux's avatar
sfux committed
346
echo -e "Checking for left over files from previous sessions"
sfux's avatar
sfux committed
347
if [ -f $JNB_SCRIPTDIR/reconnect_info ]; then
sfux's avatar
sfux committed
348
        echo -e "Found old reconnect_info file, deleting it ..."
sfux's avatar
sfux committed
349
        rm $JNB_SCRIPTDIR/reconnect_info
sfux's avatar
sfux committed
350
fi
sfux's avatar
sfux committed
351
352
353
354

# check for log files from a previous session in the home directory of the cluster
ssh -T $JNB_SSH_OPT <<ENDSSH
if [ -f /cluster/home/$JNB_USERNAME/jnbinfo ]; then
sfux's avatar
sfux committed
355
        echo -e "Found old jnbinfo file, deleting it ..."
sfux's avatar
sfux committed
356
        rm /cluster/home/$JNB_USERNAME/jnbinfo
sfux's avatar
sfux committed
357
fi
sfux's avatar
sfux committed
358
359
360
361
if [ -f /cluster/home/$JNB_USERNAME/jnbip ]; then
	echo -e "Found old jnbip file, deleting it ..."
        rm /cluster/home/$JNB_USERNAME/jnbip
fi 
sfux's avatar
sfux committed
362
363
ENDSSH

sfux's avatar
sfux committed
364
365
366
367
368
369
370
371
###############################################################################
# Start jupyter notebook on the cluster                                       #
###############################################################################

# run the jupyter notebook job on Euler and save ip, port and the token in the files jnbip and jninfo in the home directory of the user on Euler
echo -e "Connecting to $JNB_HOSTNAME to start jupyter notebook in a batch job"
# FIXME: save jobid in a variable, that the script can kill the batch job at the end
ssh $JNB_SSH_OPT bsub -n $JNB_NUM_CPU -W $JNB_RUN_TIME -R "rusage[mem=$JNB_MEM_PER_CPU_CORE]" $JNB_SNUM_GPU  <<ENDBSUB
sfux's avatar
sfux committed
372
module load $JNB_MODULE_COMMAND
sfux's avatar
sfux committed
373
export XDG_RUNTIME_DIR=
374
JNB_IP_REMOTE="\$(hostname -i)"
375
376
echo "Remote IP:\$JNB_IP_REMOTE" >> /cluster/home/$JNB_USERNAME/jnbip
jupyter notebook --no-browser --ip "\$JNB_IP_REMOTE" $JNB_SWORK_DIR &> /cluster/home/$JNB_USERNAME/jnbinfo
sfux's avatar
sfux committed
377
378
ENDBSUB

sfux's avatar
sfux committed
379
# wait until jupyternotebook has started, poll every $JNB_WAITING_INTERVAL seconds to check if /cluster/home/$JNB_USERNAME/jnbinfo exists
sfux's avatar
sfux committed
380
# once the file exists and is not empty, the notebook has been startet and is listening
sfux's avatar
sfux committed
381
382
383
384
385
386
ssh $JNB_SSH_OPT <<ENDSSH
while ! [ -e /cluster/home/$JNB_USERNAME/jnbinfo -a -s /cluster/home/$JNB_USERNAME/jnbinfo ]; do
        echo 'Waiting for jupyter notebook to start, sleep for $JNB_WAITING_INTERVAL sec'
        sleep $JNB_WAITING_INTERVAL
done
ENDSSH
sfux's avatar
sfux committed
387

sfux's avatar
sfux committed
388
# get remote ip, port and token from files stored on Euler
sfux's avatar
sfux committed
389
echo -e "Receiving ip, port and token from jupyter notebook"
sfux's avatar
sfux committed
390
JNB_REMOTE_IP=$(ssh $JNB_SSH_OPT "cat /cluster/home/$JNB_USERNAME/jnbip | grep -m1 'Remote IP' | cut -d ':' -f 2")
sfux's avatar
sfux committed
391
392
393
394
JNB_REMOTE_PORT=$(ssh $JNB_SSH_OPT "cat /cluster/home/$JNB_USERNAME/jnbinfo | grep -m1 token | cut -d '/' -f 3 | cut -d ':' -f 2")
JNB_TOKEN=$(ssh $JNB_SSH_OPT "cat /cluster/home/$JNB_USERNAME/jnbinfo | grep -m1 token | cut -d '=' -f 2")

# check if the IP, the port and the token are defined
sfux's avatar
sfux committed
395
if  [[ "$JNB_REMOTE_IP" == "" ]]; then
sfux's avatar
sfux committed
396
397
398
399
400
401
cat <<EOF
Error: remote ip is not defined. Terminating script.
* Please check login to the cluster and check with bjobs if the batch job on the cluster is running and terminate it with bkill.
* Please check the /cluster/home/$JNB_USERNAME/jnbinfo for logs regarding the failure to identify the remote ip on the cluster
EOF
exit 1
sfux's avatar
sfux committed
402
403
fi

sfux's avatar
sfux committed
404
if  [[ "$JNB_REMOTE_PORT" == "" ]]; then
sfux's avatar
sfux committed
405
406
407
408
409
410
cat <<EOF
Error: remote port is not defined. Terminating script.
* Please check login to the cluster and check with bjobs if the batch job on the cluster is running and terminate it with bkill.
* Please check the /cluster/home/$JNB_USERNAME/jnbinfo for logs regarding the failure to identify the remote ip on the cluster
EOF
exit 1
sfux's avatar
sfux committed
411
412
fi

sfux's avatar
sfux committed
413
if  [[ "$JNB_TOKEN" == "" ]]; then
sfux's avatar
sfux committed
414
415
416
417
418
419
cat <<EOF
Error: token for the jupyter notebook session is not defined. Terminating script.
* Please check login to the cluster and check with bjobs if the batch job on the cluster is running and terminate it with bkill.
* Please check the /cluster/home/$JNB_USERNAME/jnbinfo for logs regarding the failure to identify the remote ip on the cluster
EOF
exit 1
sfux's avatar
sfux committed
420
421
fi

sfux's avatar
sfux committed
422
423
424
425
# print information about IP, port and token
echo -e "Remote IP address: $JNB_REMOTE_IP"
echo -e "Remote port: $JNB_REMOTE_PORT"
echo -e "Jupyter token: $JNB_TOKEN"
sfux's avatar
sfux committed
426
427
428

# get a free port on local computer
echo -e "Determining free port on local computer"
sfux's avatar
sfux committed
429
JNB_LOCAL_PORT=$(python -c 'import socket; s=socket.socket(); s.bind(("",0)); print(s.getsockname()[1]); s.close()')
sfux's avatar
sfux committed
430
# FIXME: check if there is a solution that does not require python (as some Windows computers don't have a usable Python installed by default)
sfux's avatar
sfux committed
431
432
433
434
# if python is not available, one could use
# JNB_LOCAL_PORT=$((3 * 2**14 + RANDOM % 2**14))
# as a replacement. No guarantee that the port is unused, but so far best non-Python solution

sfux's avatar
sfux committed
435
echo -e "Using local port: $JNB_LOCAL_PORT"
sfux's avatar
sfux committed
436

sfux's avatar
sfux committed
437
# write reconnect_info file
sfux's avatar
sfux committed
438
439
440
441
442
443
444
445
446
cat <<EOF > $JNB_SCRIPTDIR/reconnect_info
Restart file
Remote IP address : $JNB_REMOTE_IP
Remote port       : $JNB_REMOTE_PORT
Local port        : $JNB_LOCAL_PORT
Jupyter token     : $JNB_TOKEN
SSH tunnel        : ssh $JNB_SSH_OPT -L $JNB_LOCAL_PORT:$JNB_REMOTE_IP:$JNB_REMOTE_PORT -N &
URL               : http://localhost:$JNB_LOCAL_PORT/?token=$JNB_TOKEN
EOF
sfux's avatar
sfux committed
447

448
# setup SSH tunnel from local computer to compute node via login node
sfux's avatar
sfux committed
449
# FIXME: check if the tunnel can be managed via this script (opening, closing) by using a control socket from SSH
sfux's avatar
sfux committed
450
echo -e "Setting up SSH tunnel for connecting the browser to the jupyter notebook"
sfux's avatar
sfux committed
451
ssh $JNB_SSH_OPT -L $JNB_LOCAL_PORT:$JNB_REMOTE_IP:$JNB_REMOTE_PORT -N &
sfux's avatar
sfux committed
452

453
454
# SSH tunnel is started in the background, pause 5 seconds to make sure
# it is established before starting the browser
sfux's avatar
sfux committed
455
sleep 5
456
457

# save url in variable
sfux's avatar
sfux committed
458
JNB_URL=http://localhost:$JNB_LOCAL_PORT/?token=$JNB_TOKEN
sfux's avatar
sfux committed
459
echo -e "Starting browser and connecting it to jupyter notebook"
sfux's avatar
sfux committed
460
echo -e "Connecting to url $JNB_URL"
sfux's avatar
sfux committed
461

sfux's avatar
sfux committed
462
# start local browser if possible
Andrei Plamada's avatar
Andrei Plamada committed
463
if [[ "$OSTYPE" == "linux-gnu" ]]; then
sfux's avatar
sfux committed
464
        xdg-open $JNB_URL
Andrei Plamada's avatar
Andrei Plamada committed
465
elif [[ "$OSTYPE" == "darwin"* ]]; then
sfux's avatar
sfux committed
466
        open $JNB_URL
sfux's avatar
sfux committed
467
elif [[ "$OSTYPE" == "msys" ]]; then # Git Bash on Windows 10
sfux's avatar
sfux committed
468
        start $JNB_URL
sfux's avatar
sfux committed
469
else
sfux's avatar
sfux committed
470
        echo -e "Your operating system does not allow to start the browser automatically."
sfux's avatar
sfux committed
471
        echo -e "Please open $JNB_URL in your browser."
sfux's avatar
sfux committed
472
fi