Skip to content

Commit

Permalink
Merge pull request #11 from eth-cscs/rtdocs
Browse files Browse the repository at this point in the history
Add docs
  • Loading branch information
rsarm committed Jun 14, 2024
2 parents be1ff86 + b2999df commit 47ba246
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 0 deletions.
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
35 changes: 35 additions & 0 deletions docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
36 changes: 36 additions & 0 deletions docs/source/authentication.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Authentication
==============

A single Keycloak client is used for the authentication with both JupyterHub and FirecREST.
As the user logs in JupyterHub, an access token and refresh token are obtained directly from Keycloak.
The access token is used for the authentication with both the hub and FirecREST.
Since access tokens are temporary, before doing any operation requiring authentication (such as FirecREST calls), they are refreshed using the refresh token, which have a longer lifetime.

For the Hub, the refreshing of the access token is done by the authenticator's `refresh_user method <https://github.com/eth-cscs/firecrestspawner/blob/4c5446ea4a77e44129c8eb822456effd6ceb9601/chart/f7t4jhub/files/jupyterhub-config.py#L66-L91>`_, which must be defined in the ``GenericOAuthenticatorCSCS`` class.
It's run time to time as needed depending on the ``c.Authenticator.auth_refresh_age`` parameter.

That's different for the spawner. Any time a firecrest function is called, a new client is created and used to run the command.
Now, any time a client is created, a new access token is requested with the refresh token.
That's done in the spawner itself and it's independent of the credential refreshing for the hub (except that the refresh token is obtained from the *authentication state* of the Hub - see section :ref:`auth-state`)

Right now, creating a new client always makes a request to refresh the access token, but the idea is to check if the current access token is expired or not, to reduce the number of refreshing requests.

.. _auth-state:

Enabling the authentication state
---------------------------------

The access and refresh tokens are kept stored in JupyterHub's `authentication state <https://jupyterhub.readthedocs.io/en/stable/reference/authenticators.html#authentication-state>`_ dictionary.
From there, they are fetched by the spawner and passed to the FirecREST clients which submit, poll and cancel the jobs that run the JupyterLab servers.
By default, JupyterHub doesn't store the authentication state.
That must be enabled in the configuration

.. code-block:: Python
c.Authenticator.enable_auth_state = True
which in turns requires setting ``c.CryptKeeper.keys`` in the JupyterHub and the environment variable ``JUPYTERHUB_CRYPT_KEY`` in the single-user side.

Once that's done, there's only left to add to the configuration the settings for the authentication with keycloak and extend the ``oauthenticator``'s ``GenericOAuthenticator`` class to provide the ``refresh_user`` method, which takes care of refreshing the access token.

The access and refresh tokens are kept stored in JupyterHub's "authentication state"
34 changes: 34 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import os
import sys
sys.path.insert(0, os.path.abspath('../..'))


os.environ['FIRECREST_URL'] = 'dummy'

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'FirecRESTSpawner'
copyright = '2024, CSCS Swiss National Supercomputing Center'
author = 'CSCS Swiss National Supercomputing Center'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ['sphinx.ext.autodoc']

templates_path = ['_templates']
exclude_patterns = []

language = 'Python'

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
70 changes: 70 additions & 0 deletions docs/source/deployment.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Deployment
==========

The deployment has two sides:

- The hub and the proxy:
Users connect to the hub (JupyterHub) and launch JupyterLab servers via FirecREST that will run in compute nodes of HPC clusters.
The proxy routes the communication from the browser to the hub or to the JupyterLab servers.
Besides access to the internet, no special requirements are necessary for where to run the the hub and the proxy.

- The JupyterLab user servers launched in compute nodes of HPC clusters:
These JupyterLab servers (also know as single-user servers within JupyterHub) come and go as users spawn or stop them.
An installation of JupyterLab and other packages must be provided in the HPC cluster.
That could be a native installation somewhere in the system or provided as a container image.
This doesn't need FirecREST and it's not concerned either with JupyterHub's configuration nor the FirecREST's client credentials

Reference deployment at CSCS
----------------------------

At CSCS we run JupyterHub in Kubernetes and from there JupyterLab notebooks are launched via FirecREST ito different HPC clusters.
Each cluster has its own deployment, i.e its own JupyterHub server.

We deploy the hub and proxy using the `f7t4jhub <https://eth-cscs.github.io/firecrestspawner>`_ helm chart that we have prepared.
The chart has been written with CSCS' use case in mind, but we would be glad to make it more general if it were used in other sites.
You can give it a look in the `spawner's rpository <https://github.com/eth-cscs/firecrestspawner/tree/main/chart>`_ or search it from the command line with helm:

.. code-block:: Shell
$> helm repo add f7t4jhub https://eth-cscs.github.io/firecrestspawner
$> helm repo update
$> helm search repo f7t4jhub/f7t4jhub --versions
NAME CHART VERSION APP VERSION DESCRIPTION
f7t4jhub/f7t4jhub 0.6.0 4.1.5 A Helm chart to Deploy JupyterHub with the Fire...
f7t4jhub/f7t4jhub 0.5.2 4.1.5 A Helm chart to Deploy JupyterHub with the Fire...
f7t4jhub/f7t4jhub 0.5.1 4.1.5 A Helm chart to Deploy JupyterHub with the Fire...
f7t4jhub/f7t4jhub 0.5.0 4.1.5 A Helm chart to Deploy JupyterHub with the Fire...
f7t4jhub/f7t4jhub 0.3.0 4.1.5 A Helm chart to Deploy JupyterHub with the Fire...
In our deployments, both the hub and proxy run in their own pods, as that makes possible restarting the hub if needed (to apply a new configuration, for instance) without affecting users that have JupyterLab servers running.
As proxy, we use `configurable-http <https://github.com/jupyterhub/configurable-http-proxy>`_ from the container image ``quay.io/jupyterhub/configurable-http-proxy:4.6.1``.
For the hub, we use the custom container image ``ghcr.io/eth-cscs/f7t4jhub:4.1.5`` which contains JupyterHub and the FirecRESTSpawner.
The corresponding Dockerfile can be found `here <https://github.com/eth-cscs/firecrestspawner/blob/main/dockerfiles/Dockerfile>`_.
JupyterHub's configuration and FirecREST's client credentials are passed via a Kubernetes ConfigMap and Secret, respectively.

.. image:: images/cscs-deployment.png
:alt: Company Logo
:width: 500px
:align: center

At CSCS, the Keycloak client's IDs and secrets to login in JupyterHub are stored in `Vault <https://www.vaultproject.io>`_.
They can be accessed in our kubernetes deployment via a set of secrets:

- The `vault-approle-secret` kubernetes `Secret`, which contains the credentials to access Vault.
This secret is not part of the helm chart. It must be created manually for the namespace where the chart will be deployed.

- A `SecretStore <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/secret-store.yaml>`_, which interacts with the `vault-approle-secret` secret.

- An `ExternalSecret <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/external-secret.yaml>`_ which in turns interacts with the secret store.
The deployment access the Keycloak client's IDs and secrets from this external secret.

This part related to Vault is optional and can be disabled in the chart's ``values.yaml``.

Another item of the chart worth a remark is the `ConfigMap` that provides the `JupyterHub configuration <https://jupyterhub.readthedocs.io/en/stable/tutorial/getting-started/config-basics.html>`_.
The configuration has a lot of parameters that can be tweaked.
However, in practice, only a handful have to be modified from one deployment to another.
Because of that, templating only those parameters should be enough to produce a generic chart that can be used for all deployments by only changing corresponding values in the `values.yaml`.

In our deployments, the required changes are mostly related to the authentication settings and the batch script used by the spawner to submit the JupyterLab servers since the slurm settings may change depending on the cluster.
All parameters related to JupyterHub's configuration are set under `config` in the `values.yaml`.
Binary file added docs/source/images/cscs-deployment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.. FirecRESTSpawner documentation master file, created by
sphinx-quickstart on Thu Jun 13 10:08:06 2024.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to FirecRESTSpawner's documentation!
============================================

.. toctree::
:maxdepth: 2
:caption: Contents:

authentication
deployment
reference


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
9 changes: 9 additions & 0 deletions docs/source/reference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Reference
=========

.. toctree::
:maxdepth: 2
:caption: Contents:

reference_spawners
reference_singleuser
4 changes: 4 additions & 0 deletions docs/source/reference_singleuser.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Single-user server
==================

The library also provides an asynchronous API for the client:
19 changes: 19 additions & 0 deletions docs/source/reference_spawners.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Spawners
========

The library also provides an asynchronous API for the client:

The ``FirecRESTSpawnerBase`` class
**********************************
.. autoclass:: firecrestspawner.spawner.FirecRESTSpawnerBase
:members:
:undoc-members:
:show-inheritance:


The ``SlurmSpawner`` class
****************************
.. autoclass:: firecrestspawner.spawner.SlurmSpawner
:members:
:undoc-members:
:show-inheritance:

0 comments on commit 47ba246

Please sign in to comment.