From b127b1f940ee378e60ab05b63f5ef55ce87c1bd8 Mon Sep 17 00:00:00 2001 From: Jake Rundall Date: Sat, 6 Jun 2026 15:27:43 -0500 Subject: [PATCH] SVCPLAN-6870: Initial release R 4.6.0 and 4.5.3 are the NCSA-provided options. These are just basic containers with very few packages. There is also the option to BYOC. I'm also trying a dynamic custom_partitions.rb feature to have the submit form show different partitions depending on what the user has access to. --- .gitignore | 3 ++ LICENSE.txt | 22 +++++++++ README.md | 39 ++++++++++++--- form.yml.erb | 93 +++++++++++++++++++++++++++++++++++ icon.png | Bin 0 -> 9018 bytes manifest.yml | 7 +++ submit.yml.erb | 35 ++++++++++++++ template/after.sh.erb | 9 ++++ template/before.sh.erb | 16 ++++++ template/bin/auth | 27 +++++++++++ template/script.sh.erb | 107 +++++++++++++++++++++++++++++++++++++++++ view.html.erb | 20 ++++++++ 12 files changed, 371 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 form.yml.erb create mode 100644 icon.png create mode 100644 manifest.yml create mode 100644 submit.yml.erb create mode 100755 template/after.sh.erb create mode 100755 template/before.sh.erb create mode 100755 template/bin/auth create mode 100755 template/script.sh.erb create mode 100644 view.html.erb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbfbd18 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +.vscode + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4c5b5e8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2016-2018 Ohio Supercomputer Center + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 2910fab..d9b7cef 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,41 @@ A Batch Connect app that launches RStudio Server via a container inside of a Slu ## Creating containers Versioned RStudio containers from the Rocker project seem to work out-of-the-box: -https://rocker-project.org/images/versioned/rstudio.html +[https://rocker-project.org/images/versioned/rstudio.html](https://rocker-project.org/images/versioned/rstudio.html) -`apptainer pull rocker-rstudio-R_4.6.0-RStudio_TBD-20260512-00.sif docker://rocker/rstudio:4.6.0` +Pull down the container: +```bash +apptainer pull rocker-rstudio-R_4.6.0-RStudio_TBD-20260512-00.sif docker://rocker/rstudio:4.6.0 +``` -`apptainer shell` the container and find out what version of RStudio it includes. Then update the name to include that, i.e.`rocker-rstudio-R_4.6.0-RStudio_2026.04.0-526-20260512-00.sif`, i.e., `---R_-RStudio_-YYYYMMDD-##.sif` where YYYYMMDD and ## is some optional increment on the image. +Use `apptainer shell` to investigate the container and find out what version of RStudio it includes. Then update the name to include that, i.e., `--R_-RStudio_--YYYYMMDD-##.sif`, where YYYYMMDD is the date the image was downloaded and ## is some optional increment on the image, e.g., `rocker-rstudio-R_4.6.0-RStudio_2026.04.0-526-20260512-00.sif`. + +If the image is modified, extended, or built by NCSA, then use 'ncsa' as the project/org. + +The images can be given "pretty names" in the app interface, but naming the .sif files in a consistent and comprehensive manner is helpful to maintainers. ## Contributing -1. If necessary (no dev privs in ncsa/mg-OOD-RStudio), fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) +1. Work on the MG cluster, developing and testing your changes using the developer sandbox mode +2. If necessary (no dev privs in ncsa/mg-OOD-RStudio), fork the repository +3. Create your feature/topic branch (`git checkout -b username/ticket_id/short_desc`) +4. Add and commit your changes (`git commit -am 'Add some feature'`) +4. Push to the feature/topic branch (`git push origin username/ticket_id/short_desc`) 5. Create a new Pull Request + +## Publishing containers on the MG cluster + +NCSA staff can share containers in `/usr/local/oodimages/rstudio/` for others to use. Make sure permissions are set to allow everyone to access the .sif file. + +In order for the app to show the container as an option it must be added in `form.yml.erb`. Be sure to verify that you can select the container and successfully launch the app. + +Then put in a PR as described above. After the PR is approved and the branch is merged to `main`, make sure to add an appropriate version tag to the repo. + +Finally, ask an admin to update the Open OnDemand server config to pull in this new release by the tag. + +## Acknowledgments and References + +[https://github.com/sol-eng/singularity-rstudio](https://github.com/sol-eng/singularity-rstudio)\ +[https://discourse.openondemand.org/t/rstudio-when-launched-without-singularity-is-having-strange-troubles-with-authentication/1213/60](https://discourse.openondemand.org/t/rstudio-when-launched-without-singularity-is-having-strange-troubles-with-authentication/1213/60)\ +[https://github.com/OSC/bc_osc_rstudio_server](https://github.com/OSC/bc_osc_rstudio_server) + diff --git a/form.yml.erb b/form.yml.erb new file mode 100644 index 0000000..68f9617 --- /dev/null +++ b/form.yml.erb @@ -0,0 +1,93 @@ +# Batch Connect app configuration file +--- + +cluster: "magnus" + +attributes: + + bc_image: + label: "Select from provided container images or custom" + widget: "select" + value: "R 4.6.0" + options: + - ["R 4.6.0","/usr/local/oodimages/rstudio/rocker-rstudio-R_4.6.0-RStudio_2026.04.0-526-20260512-00.sif",data-hide-bc-custom-image: true,data-set-bc-custom-image: ""] + - ["R 4.5.3","/usr/local/oodimages/rstudio/rocker-rstudio-R_4.5.3-RStudio_2026.04.0-526-20260608-00.sif",data-hide-bc-custom-image: true,data-set-bc-custom-image: ""] + - ["custom","custom"] + # cachable: false + + bc_custom_image: + label: "Select custom container image" + widget: "path_selector" + help: "Enter the path for your own Apptainer .sif image that contains and R and RStudio. Images from the Rocker project (https://rocker-project.org/images/), or extended from those containers, are likely to work." + + bc_reservation: + label: "Name of reservation (leave empty if none)" + widget: "text_field" + value: "" + +# bc_partition: +# label: "Partition" +# widget: "select" +# value: "magnus" +# options: +# - ["debug","debug"] +# - ["gpu","gpu"] +# - ["magnus","magnus"] + + bc_partition: + label: "Partition" + widget: select + value: "magnus" + options: +## <%- CustomPartitions.partitions.each do |a| %> +## - [ "<%= a.strip %>", "<%= a %>" ] +## <%- end -%> + <%- CustomPartitions.partitions.each do |a| %> + - [ "<%= a.strip %>", "<%= a %>" ] + <%- end -%> +# cacheable: false +### help: "The rstudio partition is available to launch small sessions without delay. Sessions there are restricted to 1 core and a maximum of 8 GB of RAM." + + bc_num_slots: + label: "Number of CPUs" + widget: "number_field" + min: "1" +### help: "The rstudio partition only allows single-core sessions." + + bc_num_memory: + label: "Amount of RAM" + widget: "text_field" +### help: "Total memory for the node/session (--mem in Slurm). Use Slurm format, e.g., 4096M, 10G. If left blank, 4505 MB will be allocated per CPU core requested. A minimum of 4 GB is required for each job and lower values will be substituted before submission. The rstudio partition allows a maximum of 8 GB." + help: "Total memory for the node/session (--mem in Slurm). Use Slurm format, e.g., 4096M, 10G. If left blank, 4505 MB will be allocated per CPU core requested. A minimum of 4 GB is required for each job and lower values will be substituted before submission." + + bc_num_gpus: + label: "Number of GPUs" +# widget: "number_field" + widget: "text_field" +# max: "4" +# min: "0" + + bc_num_hours: + label: "Number of hours" + widget: "number_field" + max: "720" + min: "1" + +# working_dir: +# label: "Working Directory" +# data-filepicker: true +# data-target-file-type: dirs # Valid values are: files, dirs, or both +# readonly: false +# help: "Select your project directory; defaults to $HOME" + +form: + - bc_image + - bc_custom_image + - bc_partition + - bc_num_hours + - bc_reservation + - bc_num_slots + - bc_num_memory + - bc_num_gpus +# - working_dir + - bc_email_on_started diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..656d1333969820b9398b3d7b46011330fed0afb2 GIT binary patch literal 9018 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 literal 0 HcmV?d00001 diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..6f54f05 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,7 @@ +--- +name: RStudio Server +category: Interactive Apps +#subcategory: Servers +role: batch_connect +description: | + This app will launch RStudio Server inside of a container running in a Slurm job. diff --git a/submit.yml.erb b/submit.yml.erb new file mode 100644 index 0000000..f3c168b --- /dev/null +++ b/submit.yml.erb @@ -0,0 +1,35 @@ +# Job submission configuration file +--- + +batch_connect: + template: "basic" + conn_params: + - csrftoken + native: +script: + queue_name: "<%= bc_partition %>" + email_on_started: <%= bc_email_on_started %> + native: + - "-N 1" + - "-n <%= bc_num_slots.blank? ? 1 : bc_num_slots.to_i %>" + <%- unless bc_num_memory.blank? %> + # make sure the user has requested at least 4 GB of RAM + <%- if ( bc_num_memory.downcase.end_with?('g') and bc_num_memory[/[0-9]+/].to_i < 4 ) or + ( bc_num_memory.downcase.end_with?('m') and bc_num_memory[/[0-9]+/].to_i < 4096 ) or + ( bc_num_memory.downcase.end_with?('k') and bc_num_memory[/[0-9]+/].to_i < 4194304 ) %> + - "--mem=4G" + <%- else %> + - "--mem=<%= bc_num_memory %>" + <%- end -%> + <%- end -%> + <%- unless bc_num_hours.blank? -%> + - "-t" + - "0-<%= bc_num_hours %>:00:00" + <%- end -%> + <%- unless bc_num_gpus.blank? or bc_num_gpus == 0 -%> + - "--gres=gpu:<%= bc_num_gpus %>" + <%- end -%> + <%- unless bc_reservation.blank? -%> + - "--reservation=<%= bc_reservation %>" + <%- end -%> + diff --git a/template/after.sh.erb b/template/after.sh.erb new file mode 100755 index 0000000..8b7b6a7 --- /dev/null +++ b/template/after.sh.erb @@ -0,0 +1,9 @@ +# Wait for the RStudio Server to start +echo "Waiting for RStudio Server to open port ${port}..." +if wait_until_port_used "${host}:${port}" 120; then + echo "Discovered RStudio Server listening on port ${port}!" +else + echo "Timed out waiting for RStudio Server to open port ${port}!" + clean_up 1 +fi +sleep 2 diff --git a/template/before.sh.erb b/template/before.sh.erb new file mode 100755 index 0000000..bbcaeb2 --- /dev/null +++ b/template/before.sh.erb @@ -0,0 +1,16 @@ +# Export the module function if it exists +[[ $(type -t module) == "function" ]] && export -f module + +# Find available port to run server on +port=$(find_port ${host}) + +# Define a password and export it for RStudio authentication +password="$(create_passwd 16)" +export RSTUDIO_PASSWORD="${password}" + +# create CSRF token +<%- + require 'securerandom' + csrftoken=SecureRandom.uuid +-%> +export csrftoken="<%= csrftoken %>" diff --git a/template/bin/auth b/template/bin/auth new file mode 100755 index 0000000..c3de0ae --- /dev/null +++ b/template/bin/auth @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Confirm username is supplied +if [[ $# -lt 1 ]]; then + echo "Usage: auth USERNAME" + exit 1 +fi +USERNAME="${1}" + +# Confirm password environment variable exists +if [[ -z ${RSTUDIO_PASSWORD} ]]; then + echo "The environment variable RSTUDIO_PASSWORD is not set" + exit 1 +fi + +# Read in the password from user +read -s -p "Password: " PASSWORD +echo "" + +if [[ ${USERNAME} == ${USER} && ${PASSWORD} == ${RSTUDIO_PASSWORD} ]]; then + echo "Successful authentication" + exit 0 +else + echo "Invalid authentication" + exit 1 +fi + diff --git a/template/script.sh.erb b/template/script.sh.erb new file mode 100755 index 0000000..a9d42cd --- /dev/null +++ b/template/script.sh.erb @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +# Load the required environment +setup_env () { + # Additional environment which could be moved into a module + # Change these to suit +export RSTUDIO_SERVER_IMAGE="<% if context.bc_custom_image != '' %><%= context.bc_custom_image %><% else %><%= context.bc_image %><% end %>" +# export APPTAINER_BINDPATH="/etc,/media,/mnt,/opt,/srv,/usr/lib,/lib,/lib64,/usr/apps,/var" + export PATH="$PATH:/usr/lib/rstudio-server/bin" + export APPTAINERENV_PATH="$PATH" + # In Singularity 3.5.x it became necessary to explicitly pass LD_LIBRARY_PATH + # to the singularity process + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/R/4.4.0/lib/R/lib" + # export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/apps/general/spack/sw/linux-rhel8-zen/gcc-11.3.0/r-4.2.0-2liuw4vmic27cmqhyyt6jmvwbezn6mlx/rlib/R/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/curl-8.0.1-u7dljxx4j2vkwnhrbxl5dnigktopsogc/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/expat-2.5.0-37la23gnxetfy3uytrvk47cmtlycoska/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/geos-3.11.2-ipmlasljmvtuoykqyycrtu5gy4zw47cm/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/json-c-0.16-7lokifwb6lzpml5k63adfgzrbrnc3hi2/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/libgeotiff-1.6.0-ql2lodtsyry5cw25ngozc7qtb2jhf6zo/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/libjpeg-turbo-2.1.4-cmeyyk3pssdcvl4i4ijmfeoqiubfvby3/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/libpng-1.6.39-rpbqrtfdirzf3fojuav2it3lpeqmmnye/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/libtiff-4.4.0-q2c2seunvg5ym3qhgdwe3d3mkr72z5lb/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/proj-8.2.1-t3pclijfh275ljxzranxvzs22hlene5j/lib64:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/sqlite-3.40.1-ux7pnanmrgn4dvcm6qwrbvesyfposm56/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/zlib-1.2.13-smcuvhowz7cwxhb5jcy647kjmrnx4tbc/lib:/usr/apps/general/spack/sw/linux-rhel8-zen/gcc-8.5.0/gcc-11.3.0-cwx43q6qt46zl5olgckurx67xtg4nuyd/lib64:/usr/apps/general/spack/sw/linux-rhel8-zen/gcc-8.5.0/glib-2.74.6-4wqjtnm3mebxlldhaxpbh4ptqtaxjmoa/lib:/usr/apps/general/spack/sw/linux-rhel8-zen/gcc-11.3.0/hdf5-1.14.0-5xrz3r365nib6fma73irar6fbrgyzhd4/lib:/usr/apps/general/spack/sw/linux-rhel8-cascadelake/gcc-11.3.0/gdal-3.6.3-tkiuujut7ibrj3ljcof2r7zonydhmqt6/lib64" + export APPTAINERENV_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" +} +setup_env +#echo $APPTAINER_BINDPATH +#echo $APPTAINERENV_PATH +#echo $APPTAINERENV_LD_LIBRARY_PATH + +#export WORKING_DIR="< % = session_dir % >" +export WORKING_DIR=${PWD} + +# +# Start RStudio Server +# + +# PAM auth helper used by RStudio +export RSTUDIO_AUTH="${WORKING_DIR}/bin/auth" + +# Generate an `rsession` wrapper script +export RSESSION_WRAPPER_FILE="$WORKING_DIR/rsession.sh" +( +umask 077 +sed 's/^ \{2\}//' > "$WORKING_DIR/rsession.sh" << EOL + #!/usr/bin/env bash + + # Log all output from this script + export RSESSION_LOG_FILE="$WORKING_DIR/rsession.log" + + exec &>>"\${RSESSION_LOG_FILE}" + set -x + + # rsession.sh doesn't share the same env as the outside script, so these + # need to be set explicitly + export R_LIBS_SITE="${R_LIBS_SITE}" + export RSTUDIO_DATA_HOME="/scratch/rstudio_user_data/${USER}/session_data" + export TZ="US/Eastern" + export HOME="$HOME" + export MODULEPATH_ROOT="$MODULEPATH_ROOT" + export MODULEPATH="$MODULEPATH" + export LMOD_PKG="$LMOD_PKG" + + env + + # Launch the original command + echo "Launching rsession..." + echo "...with args..." + echo "\${@}" + exec rsession --r-libs-user "${R_LIBS_USER}" "\${@}" +EOL +) +chmod 700 "$WORKING_DIR/rsession.sh" + +# Create DB config file +( +umask 077 +sed 's/^ \{2\}//' > "$WORKING_DIR/database.conf" << EOL + provider=sqlite + directory="$WORKING_DIR" + exec rsession --r-libs-user "${R_LIBS_USER}" "\${@}" +EOL +) +chmod 700 "$WORKING_DIR/database.conf" + +# Set working directory to home directory +cd "${HOME}" + +# server log directory in this job's working directory +mkdir -p "${WORKING_DIR}/logs" +( +umask 077 +sed 's/^ \{2\}//' > "$WORKING_DIR/logging.conf" << EOL + [*] + log-dir="${WORKING_DIR}/logs" +EOL +) +chmod 700 "$WORKING_DIR/logging.conf" + +export TMPDIR="$(mktemp -d)" +#TMPDIR="${WORKING_DIR}/tmp" +#mkdir -p $TMPDIR + +mkdir -p "$TMPDIR/rstudio-server" +python3 -c 'from uuid import uuid4; print(uuid4())' > "$TMPDIR/rstudio-server/secure-cookie-key" +chmod 0600 "$TMPDIR/rstudio-server/secure-cookie-key" + +module purge + +set -x +# Launch the RStudio Server +echo "Starting up rserver..." + +apptainer run --no-mount /usr/apps -B "$TMPDIR:/tmp,${WORKING_DIR}/logging.conf:/etc/rstudio/logging.conf" "$RSTUDIO_SERVER_IMAGE" rserver --www-port ${port} --auth-none 0 --auth-pam-helper-path "${RSTUDIO_AUTH}" --auth-encrypt-password 0 --rsession-path "${RSESSION_WRAPPER_FILE}" --server-data-dir="${TMPDIR}/run" --secure-cookie-key-file "${TMPDIR}/rstudio-server/secure-cookie-key" --server-user=$(whoami) --database-config-file="$WORKING_DIR/database.conf" + +echo 'Singularity has exited...' diff --git a/view.html.erb b/view.html.erb new file mode 100644 index 0000000..b491615 --- /dev/null +++ b/view.html.erb @@ -0,0 +1,20 @@ + +
+ "> + + + + + +