Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/env-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Docker automatic build and publish
on:
push:
branches:
- main
- upgrade-hub-singleuser

env:
REGISTRY: ghcr.io
Expand Down
103 changes: 103 additions & 0 deletions vre-singleuser-dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
FROM quay.io/jupyter/scipy-notebook:python-3.11.8
LABEL author="Image based on the work by Muhammad Aditya Hilmy - ESCAPE WP2 2020"
LABEL maintainer="VRE Team @ CERN 23/24 - E. Garcia, G. Guerrieri"
LABEL org.opencontainers.image.source https://github.com/vre-hub/environments
ARG BUILD_DATE
LABEL org.label-schema.build-date=$BUILD_DATE

RUN python -m pip install --upgrade pip

USER $NB_UID

RUN conda install -y -n base mamba \
&& mamba install -y -c conda-forge python-gfal2 \
nodejs \
jupyterlab">4,<5" \
notebook"<7" \
jupyterhub \
jupyterhub-kubespawner \
jsonschema>4 \
jupyterlab_server \
jupyter_server \
traitlets \
nbformat \
ipykernel \
PyJWT \
ipywidgets \
&& conda clean --all -f -yft

# Install jupyterlab extensions
RUN python -m pip install rucio-jupyterlab==1.0.0 \
&& jupyter server extension enable --py rucio_jupyterlab --sys-prefix

RUN python -m pip install swanoauthrenew==1.0.1 \
&& jupyter server extension enable --py swanoauthrenew --sys-prefix

RUN python -m pip install reana-jupyterlab \
&& jupyter server extension enable --py reana_jupyterlab --sys-prefix

RUN git clone https://github.com/vre-hub/zenodo-jupyterlab-extension.git \
&& cd zenodo-jupyterlab-extension \
&& python -m pip install . \
&& jupyter server extension enable --py zenodo_jupyterlab.server --sys-prefix \
&& cd .. \
&& rm -rf zenodo-jupyterlab-extension

# Custom version of reana-client due to the jsonschema problem
RUN python -m pip install git+https://github.com/mdonadoni/reana-client.git@vre-summer-24

USER root

RUN apt update -y \
&& apt install -y build-essential curl voms-clients-java software-properties-common \
&& apt clean -y \
&& rm /opt/conda/bin/voms-proxy-init \
&& ln -s /usr/bin/voms-proxy-init /opt/conda/bin/voms-proxy-init

# ESCAPE grid-security
RUN wget -q -O - https://dist.eugridpma.info/distribution/igtf/current/GPG-KEY-EUGridPMA-RPM-3 | apt-key add -

RUN apt update \
&& add-apt-repository 'deb http://repository.egi.eu/sw/production/cas/1/current egi-igtf core' \
&& apt -y install ca-policy-egi-core

# VOMS setup
# wget https://indigo-iam.github.io/escape-docs/voms-config/voms-escape.cloud.cnaf.infn.it.vomses -O /etc/vomses/voms-escape.cloud.cnaf.infn.it.vomses
# wget https://indigo-iam.github.io/escape-docs/voms-config/voms-escape.cloud.cnaf.infn.it.lsc -O /etc/grid-security/vomsdir/escape/voms-escape.cloud.cnaf.infn.it.lsc
RUN mkdir -p /etc/vomses \
&& mkdir -p /etc/grid-security/vomsdir/escape \
&& mkdir -p /etc/grid-security/vomsdir/atlas \
&& mkdir -p /etc/grid-security/vomsdir/cms
COPY voms/vomsdir/escape/* /etc/grid-security/vomsdir/escape
COPY voms/vomsdir/atlas/* /etc/grid-security/vomsdir/atlas
COPY voms/vomsdir/cms/* /etc/grid-security/vomsdir/cms
COPY voms/vomses/* /etc/vomses

# Setup merged CERN CA file on Ubuntu based images.
# This file is contained in the `CERN-bundle.pem` file downloaded using
RUN mkdir /certs \
&& touch /certs/rucio_ca.pem \
&& curl -fsSL 'https://cafiles.cern.ch/cafiles/certificates/CERN%20Root%20Certification%20Authority%202.crt' | openssl x509 -inform DER -out /tmp/cernrootca2.crt \
&& curl -fsSL 'https://cafiles.cern.ch/cafiles/certificates/CERN%20Grid%20Certification%20Authority(1).crt' -o /tmp/cerngridca.crt \
&& curl -fsSL 'https://cafiles.cern.ch/cafiles/certificates/CERN%20Certification%20Authority.crt' -o /tmp/cernca.crt \
&& cat /tmp/cernrootca2.crt >> /certs/rucio_ca.pem \
&& cat /tmp/cerngridca.crt >> /certs/rucio_ca.pem \
&& cat /tmp/cernca.crt >> /certs/rucio_ca.pem \
&& rm /tmp/*.crt \
&& update-ca-certificates

# Setup extension Rucio instance config
COPY configure-vre.py /usr/local/bin/
RUN chmod +x /usr/local/bin/configure-vre.py
COPY configure-vre.sh /usr/local/bin/before-notebook.d/

RUN mkdir -p /opt/rucio/etc \
&& chown -R $NB_UID /opt/rucio/etc

ENV JUPYTER_ENABLE_LAB=yes
ENV JUPYTERHUB_SINGLEUSER_APP=jupyter-server

WORKDIR $HOME
USER $NB_UID

CMD ["start-notebook.py"]
41 changes: 41 additions & 0 deletions vre-singleuser-dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# VRE singleuser BASE python 3.11 iamge

This image based on the original [ESCAPE Data Lake-as-a-Service Singleuser Base Image](https://gitlab.cern.ch/escape-wp2/docker-images/-/tree/master/datalake-singleuser) (restricted acces) which is derived from [quay.io/jupyter/scipy-notebook](https://quay.io/jupyter/scipy-notebook)($\ast$) with some modifications:

1. Python version is `3.11.8`.
2. The followinf JupyterLab extensions are installed:
* [rucio-jupyterlab](https://pypi.org/project/rucio-jupyterlab) v1.0.0.
* The configuration for the Rucio JupyterLab extension is preset to connect with the ESCAPE Data Lake.
* [reana-jupyterlab](https://github.com/vre-hub/reana-jupyterlab-extension) v1.0.0.
* [zenodo-jupyterlab](https://github.com/vre-hub/zenodo-jupyterlab-extension).
* [swanoauthrenew](https://pypi.org/project/swanoauthrenew/) v1.0.1 to enable renewal of tokens.
3. The image is compatible with [rucio-clients](https://pypi.org/project/rucio-clients) `release-34.6.0` - please report any possible bug or error found.
4. ESCAPE `ca-certificates` and [VOMSes](https://indigo-iam.github.io/escape-docs/) files are preinstalled.
5. [python-gfal2](https://anaconda.org/conda-forge/python-gfal2) and `voms-clients-java` is installed to enable direct Rucio Download functionality.

($\ast$) Please note that since Oct 2023, Jupyter stopped pushing images to Docker Hub and start using quay.io

## Using the image as a standalone instance

If you want to take advantage of the extension's capability in your own machine, you can do a simple Docker run:

```sh
docker run -p 8888:8888 docker pull ghcr.io/vre-hub/vre-singleuser-py311:latest
```

You can also override the default environment values (some of which are specific to the ESCAPE instance, such as the service URLs) specified in the [Dockerfile](Dockerfile) within the singleuser extraEnv specification inside the [zero-to-jupyterhub Helm release](https://github.com/vre-hub/vre/tree/main/infrastructure/cluster/flux) of your deployment. Take a closer look at [configure-vre.py](configure-vre.py) to see all the available envs. Refer to [this configuration guide](https://github.com/rucio/jupyterlab-extension/blob/master/CONFIGURATION.md) for details.

## Extending the image

If you want to extend the image and use it as a part of the VRE, there are some things to remember:

1. To custimize the image please have a look to the [Startup Docker Stack documentation Hooks](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#startup-hooks).
2. If you need to add a file, make sure that the container user has the necessary permission to access the file. You can use envs `$NB_UID`, `$NB_GID`, `$NB_USER`, and `$HOME` to get the user ID, group ID, username, and home directory respectively.
3. Make sure that the user and workdir values are set to their original values:

```
WORKDIR $HOME
USER $NB_UID
```

Based on all the previous work done by the ESCAPE Data Lake-as-a-Service group since 2020.
96 changes: 96 additions & 0 deletions vre-singleuser-dev/configure-vre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env python
# Derived from https://gitlab.cern.ch/escape-wp2/docker-images/-/blob/master/datalake-singleuser/bin/configure.py (restricted access).

import os
import json

HOME = '/home/jovyan'

def write_jupyterlab_config():
file_path = HOME + '/.jupyter/jupyter_server_config.json'
if not os.path.isfile(file_path):
os.makedirs(HOME + '/.jupyter/', exist_ok=True)
else:
config_file = open(file_path, 'r')
config_payload = config_file.read()
config_file.close()

try:
config_json = json.loads(config_payload)
except:
config_json = {}

# Looking to the rucio-jupyterlab configuration; https://github.com/rucio/jupyterlab-extension/blob/master/rucio_jupyterlab/config/schema.py#L101
# either ("destination_rse", "rse_mount_path") either ("rucio_ca_cert") are required env vars, even if they are defined in the jhub manifest.
# Adding 'rucio_base_url' too - from debugging experience

instance_config = {
"name": os.getenv('RUCIO_NAME', 'default'),
"display_name": os.getenv('RUCIO_DISPLAY_NAME', 'Default Instance'),
"rucio_base_url": os.getenv('RUCIO_BASE_URL', 'DEFAULT rucio base url'),
"rucio_auth_url": os.getenv('RUCIO_AUTH_URL'),
"rucio_webui_url": os.getenv('RUCIO_WEBUI_URL'),
"rucio_ca_cert": os.getenv('RUCIO_CA_CERT'),
"site_name": os.getenv('RUCIO_SITE_NAME'),
"vo": os.getenv('RUCIO_VO'),
"voms_enabled": os.getenv('RUCIO_VOMS_ENABLED', '0') == '1',
"voms_vomses_path": os.getenv('RUCIO_VOMS_VOMSES_PATH'),
"voms_certdir_path": os.getenv('RUCIO_VOMS_CERTDIR_PATH'),
"voms_vomsdir_path": os.getenv('RUCIO_VOMS_VOMSDIR_PATH'),
"destination_rse": os.getenv('RUCIO_DESTINATION_RSE', 'DEFAULT rse destination'),
"rse_mount_path": os.getenv('RUCIO_RSE_MOUNT_PATH', 'DEFAULT rse mount path'),
"replication_rule_lifetime_days": int(os.getenv('RUCIO_REPLICATION_RULE_LIFETIME_DAYS')) if os.getenv('RUCIO_REPLICATION_RULE_LIFETIME_DAYS') else None,
"path_begins_at": int(os.getenv('RUCIO_PATH_BEGINS_AT', '0')),
"mode": os.getenv('RUCIO_MODE', 'replica'),
"wildcard_enabled": os.getenv('RUCIO_WILDCARD_ENABLED', '0') == '1',
"oidc_auth": os.getenv('RUCIO_OIDC_AUTH'),
"oidc_env_name": os.getenv('RUCIO_OIDC_ENV_NAME'),
"oidc_file_name": os.getenv('RUCIO_OIDC_FILE_NAME'),
}

instance_config = {k: v for k,
v in instance_config.items() if v is not None}
config_json['RucioConfig'] = {
'instances': [instance_config],
"default_instance": os.getenv('RUCIO_DEFAULT_INSTANCE'),
"default_auth_type": os.getenv('RUCIO_DEFAULT_AUTH_TYPE'),
}

config_file = open(file_path, 'w')
config_file.write(json.dumps(config_json, indent=2))
config_file.close()

def write_ipython_config():
file_path = HOME + '/.ipython/profile_default/ipython_kernel_config.json'
extension_module = 'rucio_jupyterlab.kernels.ipython'

if not os.path.isfile(file_path):
os.makedirs(HOME + '/.ipython/profile_default/', exist_ok=True)
else:
config_file = open(file_path, 'r')
config_payload = config_file.read()
config_file.close()

try:
config_json = json.loads(config_payload)
except:
config_json = {}

if 'IPKernelApp' not in config_json:
config_json['IPKernelApp'] = {}

ipkernel_app = config_json['IPKernelApp']

if 'extensions' not in ipkernel_app:
ipkernel_app['extensions'] = []

if extension_module not in ipkernel_app['extensions']:
ipkernel_app['extensions'].append(extension_module)

config_file = open(file_path, 'w')
config_file.write(json.dumps(config_json, indent=2))
config_file.close()

if __name__ == '__main__':
write_jupyterlab_config()
write_ipython_config()
3 changes: 3 additions & 0 deletions vre-singleuser-dev/configure-vre.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
set -e
python /usr/local/bin/configure-vre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/DC=ch/DC=cern/OU=computers/CN=atlas-auth.web.cern.ch
/DC=ch/DC=cern/CN=CERN Grid Certification Authority
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/DC=ch/DC=cern/OU=computers/CN=atlas-auth.cern.ch
/DC=ch/DC=cern/CN=CERN Grid Certification Authority
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/DC=ch/DC=cern/OU=computers/CN=cms-auth.web.cern.ch
/DC=ch/DC=cern/CN=CERN Grid Certification Authority
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/DC=ch/DC=cern/OU=computers/CN=cms-auth.cern.ch
/DC=ch/DC=cern/CN=CERN Grid Certification Authority
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/DC=org/DC=terena/DC=tcs/C=IT/ST=Roma/O=Istituto Nazionale di Fisica Nucleare/CN=voms-escape.cloud.cnaf.infn.it
/C=NL/O=GEANT Vereniging/CN=GEANT eScience SSL CA 4
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"atlas" "voms-atlas-auth.app.cern.ch" "443" "/DC=ch/DC=cern/OU=computers/CN=atlas-auth.web.cern.ch" "atlas" "24"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"cms" "voms-cms-auth.app.cern.ch" "443" "/DC=ch/DC=cern/OU=computers/CN=cms-auth.web.cern.ch" "cms" "24"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"escape" "voms-escape.cloud.cnaf.infn.it" "15000" "/DC=org/DC=terena/DC=tcs/C=IT/ST=Roma/O=Istituto Nazionale di Fisica Nucleare/CN=voms-escape.cloud.cnaf.infn.it" "escape" "24"
Loading