Development/VS Code: Difference between revisions

From bwHPC Wiki
Jump to navigation Jump to search
(Connect to jupyter kernel)
 
(21 intermediate revisions by 2 users not shown)
Line 9: Line 9:
[2]: https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-integrated-development-environment
[2]: https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-integrated-development-environment


-----


= VS Code: Remote - SSH =
= VS Code: Remote - SSH =


In order to remotely develop and debug code at KIT’s HPC facilities, you can use the '''Remote - SSH''' extension [3]. The extension allows you to connect your locally installed VS Code with the remote servers. So in contrast to using graphical IDEs within a remote desktop session (RDP, VNC), there are no negative effects like e.g. laggy reactions to your input or blurred display of fonts.
In order to remotely develop and debug code at HPC facilities, you can use the '''Remote - SSH''' extension [3]. The extension allows you to connect your locally installed VS Code with the remote servers. So in contrast to using graphical IDEs within a remote desktop session (RDP, VNC), there are no negative effects like e.g. laggy reactions to your input or blurred display of fonts.


[3]: https://code.visualstudio.com/docs/remote/ssh
[3]: https://code.visualstudio.com/docs/remote/ssh
Line 30: Line 29:
== Connect to login nodes ==
== Connect to login nodes ==


[[File:vscode-remoteexplorer-button.png|vscode-remoteexplorer-button.png|30px]] In order to connect to a remote SSH target, open the Remote-Explorer. Right-click a target and connect in the current or a new window. TOTP and password can be entered in the corresponding input fields that open.
[[File:vscode-remoteexplorer-button.png|vscode-remoteexplorer-button.png|30px]]<br>
In order to connect to a remote SSH target, open the Remote-Explorer. Right-click a target and connect in the current or a new window. TOTP and password can be entered in the corresponding input fields that open.


You are now logged in on the remote server. As usual, you can open a project directory with the standard key binding ++ctrl+k++ ++ctrl+o++. You can now edit and debug code.
You are now logged in on the remote server. As usual, you can open a project directory with the standard key binding Ctrl+k Ctrl+o. You can now edit and debug code.


!!! attention Please remember that you are running and debugging the code on a login node. Do not perform resource-intensive tasks. Furthermore, no GPU resources are available to you.
'''Attention''': Please remember that you are running and debugging the code on a login node. Do not perform resource-intensive tasks. Furthermore, no GPU resources are available to you.


Extensions, which are installed locally, are only usable on your local machine and are not automatically installed remotely. However, as soon as you open the Extensions-Explorer during a remote session, VS Code proposes to install the locally installed extensions remotely.
Extensions, which are installed locally, are only usable on your local machine and are not automatically installed remotely. However, as soon as you open the Extensions-Explorer during a remote session, VS Code proposes to install the locally installed extensions remotely.
Line 40: Line 40:
== Disconnect from login nodes ==
== Disconnect from login nodes ==


[[File:vscode-remoteexplorer-indicator.png|images/vscode-remoteexplorer-indicator.png]]{: width=200px align:left style=“border: 1px solid black;”} If you want to end your remote session, click the green box in the lower left corner. In the input box that opens, select the “Close Remote Connection” option. If you simply close your VS Code window, some server-side components of VS Code will continue to run remotely.
[[File:vscode-remoteexplorer-indicator.png|images/vscode-remoteexplorer-indicator.png|200px]]<br>
If you want to end your remote session, click the green box in the lower left corner. In the input box that opens, select the “Close Remote Connection” option. If you simply close your VS Code window, some server-side components of VS Code will continue to run remotely.



== Access to compute nodes ==
== Access to compute nodes ==
Line 49: Line 49:
= code-server =
= code-server =


The application code-server<ref>https://github.com/cdr/code-server</ref> allows to run the server part of VS Code on any machine, it can be accessed in the web browser. This enables, for example, development and debugging on compute nodes. '''Code-server is available via the Lmod-module <code>devel/code-server</code>'''
The application code-server [4] allows to run the server part of VS Code on any machine, it can be accessed in the web browser. This enables, for example, development and debugging on compute nodes.<br>
'''Code-server is available via the Lmod-module <code>devel/code-server</code>'''

[4]: https://github.com/cdr/code-server

[[File:code-server.png|code-server.png|VS Code in web browser: code-server, Source: https://github.com/cdr/code-server">https://github.com/cdr/code-server|700px]]


<figure>
[[File:code-server.png|code-server.png]]{: style=“width: 100%; max-width:700px;”}
<figcaption>
VS Code in web browser: code-server <br><small>Source: <a href="https://github.com/cdr/code-server">https://github.com/cdr/code-server</a></small>
</figcaption>
</figure>


=== Start code-server ===
=== Start code-server ===


!!! danger “Security implications” Please note that by starting <code>code-server</code> you are running a web server that can be accessed by everyone logged in on HoreKa/bwUniCluster.


<pre>- **If password protection is disabled, anybody can access your account and your data.**
- Chose a **secure password**!
- Do **NOT** use `code-server --link`!</pre>
Code-server can be run on either login nodes or compute nodes. In the example shown, an interactive job is started on a GPU partition to run code-server there.
Code-server can be run on either login nodes or compute nodes. In the example shown, an interactive job is started on a GPU partition to run code-server there.


Line 74: Line 69:


<syntaxhighlight lang="console">$ PASSWORD=<mySecret> \
<syntaxhighlight lang="console">$ PASSWORD=<mySecret> \
code-server }
code-server \
--bind-addr 0.0.0.0:8081 \
--bind-addr 0.0.0.0:8081 \
--auth password # Start code-server on port 8081</syntaxhighlight>
--auth password # Start code-server on port 8081</syntaxhighlight>

{| style="background:#FFCCCC; width:100%;"
| '''Security implications'''
Please note that by starting <code>code-server</code> you are running a web server that can be accessed by everyone logged in on HoreKa/bwUniCluster.<br>
* '''If password protection is disabled, anybody can access your account and your data.'''
* Choose a '''secure password'''!
* Do '''NOT''' use <code>code-server --link</code>!
|}


== Connect to code-server ==
== Connect to code-server ==
Line 83: Line 86:


<syntaxhighlight lang="console">$ ssh -L 8081:<computeNodeID>:8081 <userID>@hk.scc.kit.edu</syntaxhighlight>
<syntaxhighlight lang="console">$ ssh -L 8081:<computeNodeID>:8081 <userID>@hk.scc.kit.edu</syntaxhighlight>
You need to enter the <code>computeNodeID</code> of the node on which the interactive Slurm job is running. If you have started code server on a login node, just enter <code>localhost</code>. Now you can open http://127.0.0.1:8081 in your web browser. Eventually, you have to allow your browser to open an insecure (non-https site). The login site looks as follows:
You need to enter the <code>computeNodeID</code> of the node on which the interactive Slurm job is running. If you have started code server on a login node, just enter <code>localhost</code>. Now you can open http://127.0.0.1:8081 in your web browser. Possibly, you have to allow your browser to open an insecure (non-https) site. The login site looks as follows:


[[File:code-server-login.png|Code-server login page.|300px]]


<figure>
[[File:code-server-login.png|code-server-login.png]]{: style=“width: 300px;”}
<figcaption>
Code-server login page.
</figcaption>
</figure>
Enter the password from <code>~/.config/code-server/config.yaml</code> or from the <code>PASSWORD</code> variable. After clicking the “Submit” button, the familiar VS Code interface will open in your browser.
Enter the password from <code>~/.config/code-server/config.yaml</code> or from the <code>PASSWORD</code> variable. After clicking the “Submit” button, the familiar VS Code interface will open in your browser.



<figure>
[[File:code-server-hk.png|code-server-hk.png]]{: style=“width: 100%; max-width:700px;”}
[[File:code-server-hk.png|Code-server running on GPU node of HoreKa.|700px]]

<figcaption>
Code-server running on GPU node of HoreKa.
</figcaption>
</figure>
<span id="end-code-server-session"></span>
== End code-server session ==
== End code-server session ==


If you want to temporarily log out from your code-server session you can open the “Application Menu” in the left side bar and click on “Log out”. To '''terminate''' the code-server session, you have to cancel it in the interactive Slurm job by pressing ++ctrl+c++.
If you want to temporarily log out from your code-server session you can open the “Application Menu” in the left side bar and click on “Log out”. To '''terminate''' the code-server session, you have to cancel it in the interactive Slurm job by pressing ++ctrl+c++.

= Connect to Remote Jupyter Kernel =
Run jupyter kernel on compute node and connect to it via VSCode.

== Simple Use Case ==

# Set a password on Helix for jupyterlab:
#: <syntaxhighlight lang="bash">
jupyter notebook --generate-config
jupyter notebook password
</syntaxhighlight>
# Define a batch script
#: <pre>~/jupyterlab.slurm</pre>
#: <syntaxhighlight lang="bash">
#!/bin/bash

#SBATCH --partition=cpu-single
#SBATCH --job-name=jupyterlab
#SBATCH --time=00:05:00
#SBATCH --ntasks=1
#SBATCH --cpus-per-task 1
##SBATCH --mem-per-cpu=10
#SBATCH --mail-user=my_email_address #my_email_address # to use this generic version, add "alias my_email_address=<yourEmailAddress>" to the ~/.bashrc file
#SBATCH --mail-type=ALL

module load devel/miniconda
source $MINICONDA_HOME/etc/profile.d/conda.sh

PORT=$(( ( RANDOM % 9999 ) + 1024 ))
jupyter lab --no-browser --ip=0.0.0.0 --port=${PORT}
HOSTID=$(squeue -h -o "%A %N %j" | grep jupyterlab | awk '{print $2}')
echo "Connect"
echo "ssh -N -L ${PORT}:${HOSTID}:${PORT} ${USER}@helix.bwservices.uni-heidelberg.de"
echo "Job {$SLURM_JOB_ID} running on node {$SLURM_NODEID} on host {$HOSTID}."

returned_code=$?
echo "> Script completed with exit code ${returned_code}"
exit ${returned_code}
</syntaxhighlight>
# Run a wrapper script to execute the batch script. You could save it together with other utility scripts in a "bin" directory in your home folder.
#: <pre>./bin/run_jupyterlab_simple.sh</pre>
#: <syntaxhighlight lang="bash">

#!/bin/bash

# Define parameters
jobscript=~/jupyterlab.slurm

# Run job
job_id=$(sbatch $jobscript | awk '{print $4}')
echo "jobid: $job_id"

# Outfile name
slurm_out=slurm-${job_id}.out

# Wait for output file
while [ ! -f $slurm_out ]; do
sleep 2;
done

# Wait until url is written in output file
while [ -z ${url} ]; do
sleep 1;
url=$(grep -o 'http[^ ]*' $slurm_out | head -n 1);
done

# Extract hostID and port from output.
url_pattern="http://([a-z0-9]{6}):([1-9]{4})/lab"
if [[ $url =~ $url_pattern ]]; then
hostID=${BASH_REMATCH[1]}
port=${BASH_REMATCH[2]}
echo "To connect with the JupyterLab kernel, please enter the following into your local commandline: "
echo "ssh -N -L $port:$hostID:$port ${USER}@helix.bwservices.uni-heidelberg.de";
fi

echo "Afterwards, you can either"
echo "- use the kernel in VSCode or "
echo "- open JupyterLab with this URL: "
echo " http://127.0.0.1:${port}/lab "
echo "Note: It is normal that the ssh command doesn't end after providing the credentials. Ending the command would mean ending the local connection to the kernel."

#rm $slurm_out
</syntaxhighlight>
# Follow the instructions on the commandline to connect to the Jupyter kernel from your local machine.

== Complex Use Case ==
If you have different use cases for juypterlab, you could use a more flexible wrapper script, for example:

<pre>./bin/run_jupyterlab.sh</pre>

<syntaxhighlight lang="bash">
#!/bin/bash
# Starts a jupyter kernel on a node and provides information on how to connect to it locally.
# If you have only one use case and therefore need only one combination of slurm settings for your jupyter jobs, then you can use the simpler script.
# This script supports explorative analyses by allowing to overwrite parameters via commandline.
# Different job configurations can be defined in advance and then used with a given short name (cpu, gpu,...).

programname=$0
function help {
'''help text'''
echo ""
echo "Starts a jupyterlab kernel"
echo ""
echo "usage example: $programname --param_set cpu"
echo ""
echo " --param_set string name of the parameter set"
echo " (examples: cpu, gpu)"
echo " --jobscript string optional, path of batch script"
echo " (default: ~/jupyterlab.slurm)"
echo " --slurm_out string optional, name of slurm output file"
echo " (default: slurm-${job_id}.out)"
}

# These parameters are set later in the script. Providing them via commandline, overwrites their values set in the script.
jobscript=None
slurm_out=None

# Process parameters
while [ $# -gt 0 ]; do
if [[ $1 == "--help" ]]; then
help
exit 0
# when given -p as parameter, use its value for the variable param_set
elif [[ $1 == "-p" ]]; then
param_set="$2"
shift
elif [[ $1 == "--"* ]]; then
v="${1/--/}"
declare "$v"="$2"
shift
fi
shift
done

function define_param_set(){
'''Define parameter sets for sbatch'''
# Define different sets
cpu=(--partition=cpu-single --mem=2gb)
gpu=(--partition=gpu-single --mem=3gb --gres=gpu:1)

param_set=${1}
param_set=$param_set[@]
param_set=("${!param_set}")

# Add params that are the same for all sets
param_set+=(--ntasks=1)
}

# @param: jobscript, name of the slurm batch script to execute
if [ "$jobscript" = "None" ]; then
jobscript=~/jupyterlab.slurm
fi

# Translate given param_set value to actual set of parameters
define_param_set $param_set
echo "param_set: ${param_set[*]}"

# Run job
job_id=$(sbatch ${param_set[@]} $jobscript | awk '{print $4}')
echo "jobid: $job_id"

# @param: slurm_out, the filename for the slurm output file
if [ "$slurm_out" = "None" ]; then
slurm_out=slurm-${job_id}.out
fi

# Wait for output file
while [ ! -f $slurm_out ]; do
sleep 1;
done

# Wait until url is written in output file
while [ -z ${url} ]; do
sleep 1;
url=$(grep -o 'http[^ ]*' $slurm_out | head -n 1);
done

# Extract hostID and port from output.
url_pattern="http://([a-z0-9]{6}):([1-9]{4})/lab"
if [[ $url =~ $url_pattern ]]; then
hostID=${BASH_REMATCH[1]}
port=${BASH_REMATCH[2]}
echo "To connect with the JupyterLab kernel, please enter the following into your local commandline: "
echo "ssh -N -L $port:$hostID:$port ${USER}@helix.bwservices.uni-heidelberg.de";
fi

echo "Afterwards, you can either"
echo "- use the kernel in VSCode or "
echo "- open JupyterLab with this URL: "
echo " http://127.0.0.1:${port}/lab "
echo "Note: It is normal that the ssh command doesn't end after providing the credentials. Ending the command would mean ending the local connection to the kernel."
#rm $slurm_out
</syntaxhighlight>

Latest revision as of 19:06, 28 February 2025

Visual Studio Code

Visual Studio Code, Source: https://code.visualstudio.com/

Visual Studio Code (VS Code) is an open source source-code editor from Microsoft [1]. It has become one of the most popular IDEs. The functionality of VS Code can easily be extended by installing extensions. These extensions allow for almost arbitrary language support, debugging or remote development. You can install VS Code locally on Windows, macOS and Linux.

[1]: https://github.com/Microsoft/vscode
[2]: https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-integrated-development-environment


VS Code: Remote - SSH

In order to remotely develop and debug code at HPC facilities, you can use the Remote - SSH extension [3]. The extension allows you to connect your locally installed VS Code with the remote servers. So in contrast to using graphical IDEs within a remote desktop session (RDP, VNC), there are no negative effects like e.g. laggy reactions to your input or blurred display of fonts.

[3]: https://code.visualstudio.com/docs/remote/ssh

Installation and configuration

vscode-extensions-button.png
In order to install the Remote - SSH extension, just click on the Extensions (Erweiterungen) button in the left side bar and enter “remote ssh” in the search field. Choose Remote - SSH from the occurring list and click on Install.

vscode-remoteexplorer-button.png
In order to configure remote connections, open the Remote-Explorer extension. On Linux Systems, the file ~/.ssh/config is automatically evaluated. The targets within this file already appear in the left side bar.

vscode-remoteexplorer-add.png
If there are no remote ssh targets defined within this file, you can easily add one by clicking on the + symbol. Make sure that “SSH Targets” is active in the drop down menu of the Remote-Explorer. Enter the connection details <user>@<server>. You will be asked, whether the file ~/.ssh/config should be modified or if another config file should be used or created.

Connect to login nodes

vscode-remoteexplorer-button.png
In order to connect to a remote SSH target, open the Remote-Explorer. Right-click a target and connect in the current or a new window. TOTP and password can be entered in the corresponding input fields that open.

You are now logged in on the remote server. As usual, you can open a project directory with the standard key binding Ctrl+k Ctrl+o. You can now edit and debug code.

Attention: Please remember that you are running and debugging the code on a login node. Do not perform resource-intensive tasks. Furthermore, no GPU resources are available to you.

Extensions, which are installed locally, are only usable on your local machine and are not automatically installed remotely. However, as soon as you open the Extensions-Explorer during a remote session, VS Code proposes to install the locally installed extensions remotely.

Disconnect from login nodes

images/vscode-remoteexplorer-indicator.png
If you want to end your remote session, click the green box in the lower left corner. In the input box that opens, select the “Close Remote Connection” option. If you simply close your VS Code window, some server-side components of VS Code will continue to run remotely.

Access to compute nodes

The workflow described above does not allow debugging on compute nodes that have been requested via an interactive Slurm job, for example. The security settings prevent the login node from being used as a proxy jump host. So there is no way to connect your locally installed VS code to the compute nodes. Debugging GPU codes is therefore also not possible, since this kind of resource is only accessible within Slurm jobs.

code-server

The application code-server [4] allows to run the server part of VS Code on any machine, it can be accessed in the web browser. This enables, for example, development and debugging on compute nodes.
Code-server is available via the Lmod-module devel/code-server

[4]: https://github.com/cdr/code-server

VS Code in web browser: code-server, Source: https://github.com/cdr/code-server">https://github.com/cdr/code-server


Start code-server

Code-server can be run on either login nodes or compute nodes. In the example shown, an interactive job is started on a GPU partition to run code-server there.

$ salloc -p accelerated --gres=gpu:4 --time=30:00 # Start interactive job with 1 GPU
$ module load devel/code-server                   # Load code-server module

When code-server is started, it opens a web server listening on a certain port. The user has to specify the port. It can be chosen freely in the unprivileged range (above 1024). If a port is already assigned, e.g. because several users choose the same port, another port must be chosen.

By starting code-server, you are running a web server that can be accessed by anyone logged in to HoreKa/bwUniCluster. To prevent other people from gaining access to your account and data, this web server is password protected. If no variable PASSWORD is defined, the password in the default config file ~/.config/code-server/config.yaml is used. If you want to define your own password, you can either change it in the config file or export the variable PASSWORD.

$ PASSWORD=<mySecret> \
    code-server \
      --bind-addr 0.0.0.0:8081 \
      --auth password  # Start code-server on port 8081
Security implications

Please note that by starting code-server you are running a web server that can be accessed by everyone logged in on HoreKa/bwUniCluster.

  • If password protection is disabled, anybody can access your account and your data.
  • Choose a secure password!
  • Do NOT use code-server --link!

Connect to code-server

As soon as code-server is running, it can be accessed in the web browser. In order to establish the connection, a SSH tunnel from your local computer to the remote server has to be created via:

$ ssh -L 8081:<computeNodeID>:8081 <userID>@hk.scc.kit.edu

You need to enter the computeNodeID of the node on which the interactive Slurm job is running. If you have started code server on a login node, just enter localhost. Now you can open http://127.0.0.1:8081 in your web browser. Possibly, you have to allow your browser to open an insecure (non-https) site. The login site looks as follows:


Code-server login page.

Enter the password from ~/.config/code-server/config.yaml or from the PASSWORD variable. After clicking the “Submit” button, the familiar VS Code interface will open in your browser.


Code-server running on GPU node of HoreKa.

End code-server session

If you want to temporarily log out from your code-server session you can open the “Application Menu” in the left side bar and click on “Log out”. To terminate the code-server session, you have to cancel it in the interactive Slurm job by pressing ++ctrl+c++.

Connect to Remote Jupyter Kernel

Run jupyter kernel on compute node and connect to it via VSCode.

Simple Use Case

  1. Set a password on Helix for jupyterlab:
        jupyter notebook --generate-config
        jupyter notebook password
    
  2. Define a batch script
    ~/jupyterlab.slurm
    #!/bin/bash
    
    #SBATCH --partition=cpu-single
    #SBATCH --job-name=jupyterlab
    #SBATCH --time=00:05:00
    #SBATCH --ntasks=1
    #SBATCH --cpus-per-task 1
    ##SBATCH --mem-per-cpu=10
    #SBATCH --mail-user=my_email_address #my_email_address # to use this generic version, add "alias my_email_address=<yourEmailAddress>" to the ~/.bashrc file
    #SBATCH --mail-type=ALL
    
    module load devel/miniconda
    source $MINICONDA_HOME/etc/profile.d/conda.sh
    
    PORT=$(( ( RANDOM % 9999 )  + 1024 ))
    jupyter lab --no-browser --ip=0.0.0.0 --port=${PORT}
    HOSTID=$(squeue -h -o "%A %N %j" | grep jupyterlab | awk '{print $2}')
    echo "Connect"
    echo "ssh -N -L ${PORT}:${HOSTID}:${PORT} ${USER}@helix.bwservices.uni-heidelberg.de"
    echo "Job {$SLURM_JOB_ID} running on node {$SLURM_NODEID} on host {$HOSTID}."
    
    returned_code=$?
    echo "> Script completed with exit code ${returned_code}"
    exit ${returned_code}
    
  3. Run a wrapper script to execute the batch script. You could save it together with other utility scripts in a "bin" directory in your home folder.
    ./bin/run_jupyterlab_simple.sh
    #!/bin/bash
    
    # Define parameters
    jobscript=~/jupyterlab.slurm
    
    # Run job
    job_id=$(sbatch $jobscript | awk '{print $4}')
    echo "jobid: $job_id"
    
    # Outfile name
    slurm_out=slurm-${job_id}.out
    
    # Wait for output file
    while [ ! -f $slurm_out ]; do   
        sleep 2; 
    done
    
    # Wait until url is written in output file
    while [ -z ${url} ]; do   
        sleep 1; 
        url=$(grep -o 'http[^ ]*' $slurm_out | head -n 1); 
        done
    
    # Extract hostID and port from output.
    url_pattern="http://([a-z0-9]{6}):([1-9]{4})/lab"
    if [[ $url =~ $url_pattern ]]; then 
        hostID=${BASH_REMATCH[1]}
        port=${BASH_REMATCH[2]}
        echo "To connect with the JupyterLab kernel, please enter the following into your local commandline: "
        echo "ssh -N -L $port:$hostID:$port ${USER}@helix.bwservices.uni-heidelberg.de"; 
    fi
    
    echo "Afterwards, you can either"
    echo "- use the kernel in VSCode or "
    echo "- open JupyterLab with this URL: "
    echo "  http://127.0.0.1:${port}/lab "
    echo "Note: It is normal that the ssh command doesn't end after providing the credentials. Ending the command would mean ending the local connection to the kernel."
    
    #rm $slurm_out
    
  4. Follow the instructions on the commandline to connect to the Jupyter kernel from your local machine.

Complex Use Case

If you have different use cases for juypterlab, you could use a more flexible wrapper script, for example:

./bin/run_jupyterlab.sh
#!/bin/bash
# Starts a jupyter kernel on a node and provides information on how to connect to it locally.
# If you have only one use case and therefore need only one combination of slurm settings for your jupyter jobs, then you can use the simpler script.
# This script supports explorative analyses by allowing to overwrite parameters via commandline.
# Different job configurations can be defined in advance and then used with a given short name (cpu, gpu,...).

programname=$0
function help {
    '''help text'''
    echo ""
    echo "Starts a jupyterlab kernel"
    echo ""
    echo "usage example: $programname --param_set cpu"
    echo ""
    echo "  --param_set string   name of the parameter set"
    echo "                          (examples: cpu, gpu)"
    echo "  --jobscript string   optional, path of batch script"
    echo "                          (default: ~/jupyterlab.slurm)"
    echo "  --slurm_out string   optional, name of slurm output file"
    echo "                          (default: slurm-${job_id}.out)"
}

# These parameters are set later in the script. Providing them via commandline, overwrites their values set in the script.
jobscript=None
slurm_out=None

# Process parameters
while [ $# -gt 0 ]; do
    if [[ $1 == "--help" ]]; then
        help
        exit 0
    # when given -p as parameter, use its value for the variable param_set
    elif [[ $1 == "-p" ]]; then
        param_set="$2"
        shift
    elif [[ $1 == "--"* ]]; then
        v="${1/--/}"
        declare "$v"="$2"
        shift
    fi
    shift
done

function define_param_set(){
    '''Define parameter sets for sbatch'''
    # Define different sets
    cpu=(--partition=cpu-single --mem=2gb)
    gpu=(--partition=gpu-single --mem=3gb --gres=gpu:1)

    param_set=${1}
    param_set=$param_set[@] 
    param_set=("${!param_set}")

    # Add params that are the same for all sets
    param_set+=(--ntasks=1)
}

# @param: jobscript, name of the slurm batch script to execute
if  [ "$jobscript" = "None" ]; then
    jobscript=~/jupyterlab.slurm
fi

# Translate given param_set value to actual set of parameters 
define_param_set $param_set
echo "param_set: ${param_set[*]}"

# Run job
job_id=$(sbatch ${param_set[@]} $jobscript | awk '{print $4}')
echo "jobid: $job_id"

# @param: slurm_out, the filename for the slurm output file
if  [ "$slurm_out" = "None" ]; then
    slurm_out=slurm-${job_id}.out
fi

# Wait for output file
while [ ! -f $slurm_out ]; do   
    sleep 1; 
done

# Wait until url is written in output file
while [ -z ${url} ]; do   
    sleep 1; 
    url=$(grep -o 'http[^ ]*' $slurm_out | head -n 1); 
    done

# Extract hostID and port from output.
url_pattern="http://([a-z0-9]{6}):([1-9]{4})/lab"
if [[ $url =~ $url_pattern ]]; then 
    hostID=${BASH_REMATCH[1]}
    port=${BASH_REMATCH[2]}
    echo "To connect with the JupyterLab kernel, please enter the following into your local commandline: "
    echo "ssh -N -L $port:$hostID:$port ${USER}@helix.bwservices.uni-heidelberg.de"; 
fi

echo "Afterwards, you can either"
echo "- use the kernel in VSCode or "
echo "- open JupyterLab with this URL: "
echo "  http://127.0.0.1:${port}/lab "
echo "Note: It is normal that the ssh command doesn't end after providing the credentials. Ending the command would mean ending the local connection to the kernel."
#rm $slurm_out