Skip to content
Open
4 changes: 2 additions & 2 deletions docs/roles/jupyterhub_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ The resulting config for a JupyterLab server extension will look as follows:
settings = { "Example":
{'command': ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}'], 'launcher_entry': {'icon_path': '/path/to/my/icon.svg', 'category': 'Other'}
}
c.ServerProxy.servers.update({
}) # use update instead of assignment so multiple apps can be added to the config.
c.ServerProxy.servers.update(settings
) # use update instead of assignment so multiple apps can be added to the config.
```

The resulting config for a standalone app will look as follows:
Expand Down
10 changes: 8 additions & 2 deletions docs/roles/rstudio.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
[back to index](../index.md#Roles)

## Summary
Installs R-studio on Ubuntu 20.04 and 22.04
Installs RStudio Desktop or Server.

## Requires
Ubuntu 20.04 or 22.04 and an installation of R (e.g. by executing the r-workbench playbook first)
- Ubuntu >= 20.04
- Untested supported for RHEL-like Linux

## Description
Installation is done using apt and the debian package available [here](https://posit.co/download/rstudio-desktop/).

## Variables

- `rstudio_kind`: String. Whether to install the desktop or server version of RStudio. Default: `desktop` (set to `server` alternatively).

## History
2022 Written by Sytse Groenwold (Universiteit Utrecht)
2024 Updated by Jelle Treep (Utrecht University)
2025 Updated by Dawa Ometto (Utrecht University)

[back to index](../index.md#Roles)
29 changes: 29 additions & 0 deletions molecule/playbook-rstudio_server/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
platforms:
- name: workspace-src-ubuntu_jammy-nginx
image: ghcr.io/utrechtuniversity/src-test-workspace:ubuntu_jammy-nginx
command: /sbin/init
pre_build_image: true
published_ports:
- 8080:80
registry:
url: $DOCKER_REGISTRY
credentials:
username: $DOCKER_USER
password: $DOCKER_PW
provisioner:
name: ansible
env:
components:
- name: jupyterhub
path: jupyterhub.yml
parameters:
jupyter_auth: noauth
jupyter_activate_remote_user_auth: true # mock SRAM auth by enabling remote user auth in JupyterHub config, despite setting auth to noauth.
jupyter_proxy_config: "{ proxy_set_header: { REMOTE_USER: '$$http_user'} }"
- name: rstudio
path: rstudio_server.yml
parameters:
rstudio_base_path: "/rstudio"
rstudio_standalone: 'false'
jupyterhub_app_pip_executable: uv_pip
22 changes: 22 additions & 0 deletions molecule/playbook-rstudio_server/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
- name: Verify
hosts: all
gather_facts: false
tasks:
- name: Test rstudio
ansible.builtin.uri:
url: http://localhost/hub/spawn/testuser?next=%2Fhub%2Fuser%2Ftestuser%2Frstudio%2F
method: GET
headers:
user: testuser # mock SRAM login
return_content: true
follow_redirects: true
register: rstudio_login
retries: 6
delay: 5


- name: Assert content correct
ansible.builtin.assert:
that:
- '"Posit" in rstudio_login.content'
2 changes: 2 additions & 0 deletions playbooks/roles/jupyterhub_app/meta/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ galaxy_info:
- name: EL
versions:
- all # not tested for specific versions
dependencies:
- role: system_python
1 change: 1 addition & 0 deletions playbooks/roles/rstudio/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
---
r_version: 4.0.5
rstudio_kind: desktop
2 changes: 1 addition & 1 deletion playbooks/roles/rstudio/molecule/default/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ provisioner:
role_name_check: 1
platforms:
- name: workspace-src-ubuntu_desktop
image: ghcr.io/utrechtuniversity/src-test-workspace:ubuntu_focal-desktop
image: ghcr.io/utrechtuniversity/src-test-workspace:ubuntu_jammy-desktop
pre_build_image: true
registry:
url: $DOCKER_REGISTRY
Expand Down
10 changes: 10 additions & 0 deletions playbooks/roles/rstudio/molecule/server/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- name: Converge
hosts: all
gather_facts: true
tasks:
- name: Testing rstudio role
ansible.builtin.include_role:
name: rstudio
vars:
rstudio_kind: server
18 changes: 18 additions & 0 deletions playbooks/roles/rstudio/molecule/server/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
provisioner:
name: ansible
playbooks:
converge: ./converge.yml
prepare: ./prepare.yml
env:
ANSIBLE_ROLES_PATH: ../../../
role_name_check: 1
platforms:
- name: workspace-src-ubuntu_desktop
image: ghcr.io/utrechtuniversity/src-test-workspace:ubuntu_jammy
pre_build_image: true
registry:
url: $DOCKER_REGISTRY
credentials:
username: $DOCKER_USER
password: $DOCKER_PW
11 changes: 2 additions & 9 deletions playbooks/roles/rstudio/tasks/debian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@
name: r-base-dev
state: present

- name: Install RStudio for Ubuntu 20
when: ansible_distribution == "Ubuntu" and ansible_distribution_version == "20.04"
- name: Install RStudio
ansible.builtin.apt:
deb: https://download1.rstudio.org/electron/focal/amd64/rstudio-2024.04.2-764-amd64.deb
state: present

- name: Install RStudio for Ubuntu 22
when: ansible_distribution == "Ubuntu" and ansible_distribution_version == "22.04"
ansible.builtin.apt:
deb: https://download1.rstudio.org/electron/jammy/amd64/rstudio-2025.05.0-496-amd64.deb
deb: "{{ rstudio_links['Ubuntu'][ansible_distribution_release][rstudio_kind] }}"
state: present
4 changes: 2 additions & 2 deletions playbooks/roles/rstudio/tasks/redhat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
name: epel-release
state: present

- name: Install R
- name: Install R and RStudio
ansible.builtin.package:
name:
- R
- https://s3.amazonaws.com/rstudio-ide-build/desktop/rhel8/x86_64/rstudio-2022.02.0-443-x86_64.rpm
- "{{ rstudio_links['RedHat'][rstudio_kind] }}"
state: present
13 changes: 13 additions & 0 deletions playbooks/roles/rstudio/vars/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
rstudio_links:
Ubuntu:
focal:
desktop: https://download1.rstudio.org/electron/focal/amd64/rstudio-2024.04.2-764-amd64.deb
jammy:
desktop: https://download1.rstudio.org/electron/jammy/amd64/rstudio-2025.09.2-418-amd64.deb
server: https://download2.rstudio.org/server/jammy/amd64/rstudio-server-2025.09.2-418-amd64.deb
noble:
desktop: https://download1.rstudio.org/electron/jammy/amd64/rstudio-2025.09.2-418-amd64.deb
server: https://download2.rstudio.org/server/jammy/amd64/rstudio-server-2025.09.2-418-amd64.deb
RedHat:
desktop: https://download1.rstudio.org/electron/rhel9/x86_64/rstudio-2025.09.2-418-x86_64.rpm
server: https://download2.rstudio.org/server/rhel9/x86_64/rstudio-server-rhel-2025.09.2-418-x86_64.rpm
68 changes: 68 additions & 0 deletions playbooks/rstudio_server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
- name: Install RStudio Server in JupyterHub
hosts: localhost
gather_facts: true
vars:
_rstudio_fqdn: "{{ ('molecule-notest' in ansible_skip_tags) | ternary('localhost', rstudio_fqdn) }}"
_rstudio_base_path: "{{ rstudio_base_path | default('/', true) }}"
_rstudio_jupyter_venv_path: "{{ rstudio_jupyter_venv_path | default('/usr/local/jupyterhub', true) }}"
_rstudio_standalone: "{{ rstudio_standalone | default(false, true) | bool }}" # should be set to true unless a previous component has already installed JupyterHub.
pre_tasks:
- name: Get installed R kernels
when: not _rstudio_standalone
block:
- name: Get all kernels
ansible.builtin.command: "{{ _rstudio_jupyter_venv_path }}/bin/jupyter kernelspec list --json"
register: all_kernels_json
changed_when: false

- name: Get R kernels
ansible.builtin.set_fact:
all_r_kernels: "{{ (all_kernels_json.stdout | from_json)['kernelspecs'].values() | map(attribute='spec') | selectattr('language', 'equalto', 'R') | list }}"
roles:
- role: rstudio
vars:
rstudio_kind: server
- role: jupyterhub_standalone_proxy
when: _rstudio_standalone
# install jupyterhub and rstudio as a standalone app.
vars:
jupyterhub_uri: "{{ _rstudio_base_path }}"
jhsp_external_addr: "{{ _rstudio_fqdn }}"
- role: jupyterhub_app
vars:
jupyterhub_app_name: rstudio
jupyterhub_app_venv: "{{ _rstudio_jupyter_venv_path | default('') }}"
jupyterhub_app_config_dir: "{{ rstudio_jupyter_config_dir | default('') }}"
jupyterhub_app_pip_executable: "{{ rstudio_pip_cmd | default('uv_pip', true) }}"
jupyterhub_app_server_config: |
from jupyter_rsession_proxy import setup_rserver
c.ServerProxy.servers.update({
{% for server in all_r_kernels | default([]) %}
"rstudio{{ loop.index }}": setup_rserver(prefix="rstudio{{ loop.index }}", r_path="{{ server['argv'][0] }}", launcher_title="RStudio ({{ server['display_name']}})"),
{% endfor %}
})
jupyterhub_app_standalone_config: |
from utils import *
from jupyter_rsession_proxy import setup_rserver
patch_check_origin() # apply monkeypatch for custom CORS allowlist for websockets

config = setup_rserver(prefix="")
c.StandaloneProxyServer.unix_socket = True
c.StandaloneProxyServer.command = config['command']
c.StandaloneProxyServer.rewrite_response = config['rewrite_response']
c.StandaloneProxyServer.timeout = config['timeout']
c.StandaloneProxyServer.environment = config['environment']

tasks:
- name: Install jupyter-rsession-proxy
notify: Restart JupyterHub
ansible.builtin.pip:
name: git+https://github.com/dometto/jupyter-rsession-proxy.git@multiple_servers
state: present
virtualenv: "{{ _rstudio_jupyter_venv_path }}"
handlers:
- name: Restart JupyterHub
ansible.builtin.service:
state: restarted
name: jupyterhub
Loading