researchcloud-items

Installation scripts for SURF ResearchCloud catalog components

View the Project on GitHub UtrechtUniversity/researchcloud-items

Role jupyterhub_app

back to index

Summary

This role allows you to installs any arbritrary webapplication on an existing JupyterHub instance. The application can be either:

In both cases, your application will be spawned by JupyterHub, running as the user logged in to the Hub. This means every user can get their own instance of the app.

This role can be involed multiple time (also in multiple playbooks) to add multiple apps to the Hub.

This role expects JupyterHub to be already installed. You need to tell the role where to find JupyterHub using the jupyterhub_app_venv variable.

Description

This role:

  1. Installs the jupyter-server-proxy extension for JupyterHub.
  2. Either places a configuration file for a JupyterLab server extension wrapping your desired application, or it installs such an extension via pip.
    • If the jupyterhub_app_pip variable (see below) is set, the config file will be ommitted.
  3. Places a configuration file for a ‘standalone’ version of your desired application. The role will place this config file regardless of whether the Hub is running in standalone mode – if it is not, it will simply be ignored.

Unless you are using jupyterhub_app_pip, you need to set the jupyterhub_app_command variable. Based on this variable, this role will generate a default configuration for both a JupyterLab server extension for your app, and a standalone version of your app.

In most cases, jupyterhub_app_pip is the only variable you absolutely need to set: the role will take care of the rest. See an example here.

However, you can also further customize the configuration that wraps your app. See:

Configuring your app as a JupyterLab server extension

By default, this role will generate a default traitlets configuration file for a jupyter-server-proxy app, based on a number of variables (see below):

However, if you want to override the default configuration, you have two choices:

The generated config file will be placed in jupyter_server_config.py in jupyterhub_app_config_dir, where it will be auto-loaded by JupyterLab.

Configuring your app as a standalone server

By default, this role will generate a default traitlets configuration file for a [jupyter-standaloneproxy]((https://jupyter-server-proxy.readthedocs.io/en/latest/standalone.html/) app, based on the jupyterhub_app_command variable. For a minimal configuration, that variable is all you need to configure – the role will take care of the rest.

However, you can override this default using the jupyterhub_app_standalone_config variable. See here for what a standalone config should look like.

This generated config will be placed into the directory standalone inside the directory specified by the jupyterhub_app_config_dir variable.

Variables

Variables the JupyterHub installation

Variables concerning the application

Examples

The three examples in this section effectively accomplish the same thing, wrapping a simple Python http server as a JupyterHub app.

For more complicated applications, you may need to do some additional work in the config files. See e.g. the openvscodeserver playbook.

Example 1

- role: jupyterhub_app
  vars:
    jupyterhub_app_name: Example
    jupyterhub_app_venv: /path/to/jupyterhub/venv # Optional. Can also be set to 'system'
    jupyterhub_app_config_dir: /usr/local/etc/jupyter # Optional. Can be any path in which JupyterHub looks for config files.
    jupyterhub_app_pip_executable: pip #  Optional. Can also set to uv if it's available, for better performance.
    jupyterhub_app_icon_path: /path/to/my/icon.svg # Optional
    jupyterhub_app_category: 'Other' # Optional. Category under which the app will be displayed in JupyterLab
    jupyterhub_app_command:
      - /usr/bin/python3
      - -m
      - http.server
      - -p
      - "{port}" # magic variable that will be replaced by `jupyter-server-proxy` with the port on which the Hub will spawn the instance. See: https://jupyter-server-proxy.readthedocs.io/en/latest/server-process.html#server-process-options

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.

The resulting config for a standalone app will look as follows:

c.StandaloneProxyServer.command = ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']

Example 2: override jupyterhub_app_server

- role: jupyterhub_app
  vars:
    jupyterhub_app_server:
      command: ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']
      launcher_entry:
        title: MyExample
        icon_path: /path/to/icon.svg
        category: Notebook

Example 3: override jupyterhub_app_server_config and jupyterhub_app_standalone_config

- role: jupyterhub_app
  vars:
    jupyterhub_app_server_config: |
      # 'c' is a traitles object that is automatically available in the config file
      c.ServerProxy.servers.update({'command': ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']})
      # ... some more Python code here, do whatever you like
    jupyterhub_app_standalone_config: |
      # 'c' is a traitlets object that is automatically available in the config file
        c.StandaloneProxyServer.command = ['/usr/bin/python3', '-m' 'http.server', '-p', '{unix_socket}']
        c.StandaloneProxyServer.unix_socket = True
      # ... some more Python code here, do whatever you like
      # you can also use the provided convenience functions from `utils.py` here, see the docs for the jupyterhub_standalone_proxy role.

See also

History

2025 Written by Dawa Ometto (Utrecht University)

back to index