Generate App Hub's configuration¶
This notebook aim to produce a config.yml
file to generate all the configuration needs to be set for deployment of App Hub on a remote cluster using Devops tools.
This Notebook can be used for the following requirements:
- Initial dependencies
- Create the configuration for kubernetes'
PV
s, andPVC
s(e.g. workspace volume, and calrissian volume) - Generate the configuration for kubernetes' config maps
- Creation of different Profiles
Table of Content:
Initial dependencies¶
!pip install apphub-configurator
import yaml
from apphub_configurator.models import *
from pathlib import Path
import os
import json
from pprint import pprint
current_dir = Path(os.getcwd())
parent_dir = current_dir.parent
current_dir
PosixPath('/home/t2/Desktop/p/EOEPCA/application-hub-context/apphub-configurator/examples')
Configuration¶
storage_class_rwo = "managed-nfs-storage"
storage_class_rwx = "managed-nfs-storage"
workspace_volume_size = "50Gi"
calrissian_volume_size = "50Gi"
Volumes¶
In this section, the user will provide the data class objects for creation of volume:
- Volume for workspace
- Volume for calrissian These two configuration will be use
Workspace Volume¶
In this section, the user will providing the configuration of a kubernetes Volume for development environment (i.e workspace). It is important to mention that this volume must keep data persistently. therefore, the user set persist=True
workspace_volume = Volume( # type: ignore
name="workspace-volume",
size=workspace_volume_size,
claim_name="workspace-claim",
mount_path="/workspace",
storage_class=storage_class_rwo,
access_modes=["ReadWriteOnce"],
volume_mount=VolumeMount(name="workspace-volume", mount_path="/workspace"), # type: ignore
persist=True,
)
workspace_volume
Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)
Calrissian Volume¶
In this section, the user will configure a Kubernetes Volume for Calrissian jobs. Since the job runs within Calrissian and does not require data retention on the Calrissian pod, therefore the user should set persist=False
.
calrissian_volume = Volume( # type: ignore
name="calrissian-volume",
claim_name="calrissian-claim",
size=calrissian_volume_size,
storage_class=storage_class_rwx,
access_modes=["ReadWriteMany"],
volume_mount=VolumeMount(name="calrissian-volume", mount_path="/calrissian"), # type: ignore
persist=False,
)
calrissian_volume
Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False)
ConfigMaps¶
In this section, the user will provide the configuration for some kubernetes configmaps that is commonly used in this notebook including:
- bash login Configmap
- bash rc Configmap
- QGIS Configmap
- Stage-in/out Configmap These configmaps will be mounted as files on different pods.
bash login Configmap¶
This configmap file aims to configure the Terminal across different profiles.
bash_login_file_path = os.path.join(parent_dir, "config-maps/bash-login")
with open(bash_login_file_path, "r") as f:
content = f.read()
bash_login_cm = ConfigMap( # type: ignore
name="bash-login",
key="bash-login",
content=content,
readonly=True,
persist=False,
mount_path="/workspace/.bash_login",
)
bash_login_cm
ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)
bash-rc Configmap¶
This section explains how we configure a Kubernetes ConfigMap to manage the .bashrc
file inside a pod. This config map will:
- It provides useful aliases and environment settings for users.
- It ensures a consistent environment across different pods.
bash_rc_cm_file_path = os.path.join(parent_dir, "config-maps/bash-rc")
with open(bash_rc_cm_file_path, "r") as f:
content = f.read()
bash_rc_cm = ConfigMap( # type: ignore
name="bash-rc",
key="bash-rc",
content=content,
readonly=True,
persist=False,
mount_path="/workspace/.bashrc",
)
bash_rc_cm
ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)
QGIS Configmap¶
The cell below will provide a Configmap configuration for QGIS setup.
init_qgis_file_path = os.path.join(parent_dir, "config-maps/init-qgis.sh")
with open(init_qgis_file_path, "r") as f:
content = f.read()
init_qgis_cm = ConfigMap( # type: ignore
name="init",
key="init",
content=content,
readonly=True,
persist=False,
mount_path="/opt/init/.init.sh",
)
init_qgis_cm
ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, content='mkdir -p /workspace/.config/autostart\n\n\ncat <<EOF > /workspace/.config/autostart/qgis.desktop \n[Desktop Entry]\nEncoding=UTF-8\nVersion=0.9.4\nType=Application\nName=qgis\nComment=qgis\nExec=qgis\nOnlyShowIn=XFCE;\nRunHook=0\nStartupNotify=false\nTerminal=false\nHidden=false\nEOF', persist=False)
Stage-in/out Configmap¶
The cell below will provide a Configmap configuration for stage-in/out for e-learning profile.
init_stac_file_path = os.path.join(parent_dir, "config-maps/init-stac.sh")
with open(init_stac_file_path, "r") as f:
content = f.read()
init_stac_cm = ConfigMap( # type: ignore
name="init",
key="init",
content=content,
readonly=True,
persist=False,
mount_path="/opt/init/.init.sh",
)
init_stac_cm
ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, content='set -x \n\ncd /workspace\n\ngit clone \'https://github.com/eoap/stac-eoap.git\'\n\ncode-server --install-extension ms-python.python \ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nmkdir -p /workspace/User/\n\necho \'{"workbench.colorTheme": "Visual Studio Dark"}\' > /workspace/User/settings.json\n\npython -m venv /workspace/.venv\nsource /workspace/.venv/bin/activate\n/workspace/.venv/bin/python -m pip install --no-cache-dir stactools rasterio requests stac-asset click-logging tabulate tqdm pystac-client ipykernel loguru scikit-image rio_stac boto3==1.35.23\n\n/workspace/.venv/bin/python -m pip install --index-url https://test.pypi.org/simple cwl-wrapper\n\n/workspace/.venv/bin/python -m ipykernel install --user --name stac_env --display-name "Python (STAC)"\n\nexport AWS_DEFAULT_REGION="us-east-1"\nexport AWS_ACCESS_KEY_ID="test"\nexport AWS_SECRET_ACCESS_KEY="test"\naws s3 mb s3://results --endpoint-url=http://localstack:4566\n\nexit 0', persist=False)
init_cm_file_path = os.path.join(parent_dir, "config-maps/init.sh")
with open(init_cm_file_path, "r") as f:
content = f.read()
init_coder_cm = ConfigMap(
name="init",
key="init",
content=content,
readonly=True,
persist=False,
mount_path="/opt/init/.init.sh",
default_mode="0660",
)
init_coder_cm
ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)
Profiles¶
In the following section, the user will generate the configuration for different profiles on a remote cluster including:
profiles = []
Coder¶
In the cell below, the user configures two code-server profiles to be deployed on a remote cluster. One profile (medium) has more resources than the other (small). Two Kubernetes Volumes, discussed in the Volume section, are assigned, and a ConfigMap is mounted.
coders = {
"coder1": {
"display_name": "Code Server Small",
"slug": "ellip_studio_coder_slug_s",
"cpu_limit": 2,
"mem_limit": "8G",
},
"coder2": {
"display_name": "Code Server Medium",
"slug": "ellip_studio_coder_slug_m",
"cpu_limit": 4,
"mem_limit": "12G",
},
}
for key, value in coders.items():
coder_definition = ProfileDefinition( # type: ignore
display_name=value["display_name"],
slug=value["slug"],
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_limit=value["cpu_limit"],
mem_limit=value["mem_limit"],
image="eoepca/pde-code-server:develop",
),
)
coder_profile = Profile( # type: ignore
id=f"profile_studio_{key}",
groups=["group-a", "group-b"],
definition=coder_definition,
node_selector={},
volumes=[calrissian_volume, workspace_volume],
config_maps=[
bash_rc_cm,
],
pod_env_vars={
"HOME": "/workspace",
"CONDA_ENVS_PATH": "/workspace/.envs",
},
)
profiles.append(coder_profile)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
Coder with init.sh¶
In the cell below, the user configures the code-server with a new profile, which extends the existing coder profile. The init container is responsible for executing a Bash script to initialize the code-server pod. In this case, the script init.sh
runs during pod initialization to clone a Git repository and install extensions on the deployed code-server.
init_context_volume_mount = InitContainerVolumeMount( # type: ignore
mount_path="/opt/init/.init.sh", name="init", sub_path="init"
)
init_container = InitContainer( # type: ignore
name="init-file-on-volume",
image="eoepca/pde-code-server:develop",
command=["sh", "-c", "sh /opt/init/.init.sh"],
volume_mounts=[
VolumeMount(name="workspace-volume", mount_path="/workspace"), # type: ignore
init_context_volume_mount,
],
)
eoepca_demo_init_script_profile = Profile( # type: ignore
id=f"profile_demo_init_script",
groups=["group-a", "group-b"],
definition=ProfileDefinition( # type: ignore
display_name="Coder demo init script",
description="This profile is used to demonstrate the use of an init script",
slug="eoepca_demo_init_script",
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_guarantee=1,
cpu_limit=2,
mem_guarantee="4G",
mem_limit="6G",
image="eoepca/pde-code-server:develop",
),
),
node_selector={},
volumes=[calrissian_volume, workspace_volume],
config_maps=[init_coder_cm],
pod_env_vars={
"HOME": "/workspace",
"CONDA_ENVS_PATH": "/workspace/.envs",
"CONDARC": "/workspace/.condarc",
"XDG_RUNTIME_DIR": "/workspace/.local",
"CODE_SERVER_WS": "/workspace/mastering-app-package",
},
init_containers=[init_container],
)
profiles.append(eoepca_demo_init_script_profile)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
JupyterLab¶
In the cell below, the user adds a JupyterLab profile to the stack of profiles. The workspace volume is mounted to persist user files, and necessary environment variables are set to ensure a smooth user experience.
image = "jupyter/scipy-notebook"
eoepca_jupyter_lab_profile = Profile( # type: ignore
id="profile_jupyter_lab",
groups=["group-c"],
definition=ProfileDefinition( # type: ignore
display_name="Jupyter Lab",
description="Jupyter Lab with Python 3.11",
slug="eoepca_jupyter_lab",
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_guarantee=1,
cpu_limit=2,
mem_guarantee="4G",
mem_limit="6G",
image=image,
),
),
node_selector={},
volumes=[workspace_volume],
config_maps=[],
pod_env_vars={
"HOME": "/workspace",
"XDG_RUNTIME_DIR": "/workspace/.local",
"XDG_CONFIG_HOME": "/workspace/.config",
},
)
profiles.append(eoepca_jupyter_lab_profile)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab', description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='jupyter/scipy-notebook', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
JupyterLab Plus¶
JupyterLab Plus is an extended version of the JupyterLab profile with additional features and capabilities. The Docker image for this profile is hosted on a private Docker registry, requiring the user to configure a pull secret to authenticate and successfully pull the JupyterLab Plus image on the remote cluster.
image_pull_secret = ImagePullSecret( # type: ignore
name="cr-config",
persist=False,
data="ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9",
)
image = "cr.terradue.com/eoepca-plus/scipy-notebook@sha256:f339a9fa98d3d0c1fa8d7cc850e7f5a46845781f49bee86aacba059669d02d54"
image = "eoepca/iat-jupyterlab:develop"
eoepca_jupyter_lab_profile_2 = Profile( # type: ignore
id="profile_jupyter_lab_2",
groups=["group-c"],
definition=ProfileDefinition( # type: ignore
display_name="Jupyter Lab - profile 2",
description="Jupyter Lab with Python 3.11 private image - demoes the use of an image pull secret",
slug="eoepca_jupyter_lab_2",
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_guarantee=1,
cpu_limit=2,
mem_guarantee="4G",
mem_limit="6G",
image=image,
),
),
node_selector={},
volumes=[workspace_volume],
config_maps=[],
pod_env_vars={
"HOME": "/workspace",
"XDG_RUNTIME_DIR": "/workspace/.local",
"XDG_CONFIG_HOME": "/workspace/.config",
},
image_pull_secrets=[image_pull_secret],
)
profiles.append(eoepca_jupyter_lab_profile_2)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab', description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='jupyter/scipy-notebook', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab_2', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab - profile 2', description='Jupyter Lab with Python 3.11 private image - demoes the use of an image pull secret', slug='eoepca_jupyter_lab_2', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/iat-jupyterlab:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
E-Learning¶
This profile is an extended version of code-server, configured to initialize with an init container using init.sh. It also mounts several ConfigMaps, including bash-rc, bash-login, and stage-in/out. Additionally, key Kubernetes objects such as Role, RoleBinding, and Service are defined using a Kubernetes manifest. This manifest ultimately exposes LocalStack as a Service, allowing users to emulate AWS locally.
localstack_manifest_path = os.path.join(parent_dir, "manifests/manifest.yaml")
with open(localstack_manifest_path, "r") as f:
content = yaml.safe_load_all(f.read())
localstack_manifest = Manifest( # type: ignore
name="manifests",
key="manifests",
readonly=True,
persist=False,
content=[e for e in content],
)
image = "docker.io/eoepca/pde-code-server@sha256:f57a3d5eabcae667e0db6e84a57b0c07c692c88f0fb5c8f6900ab8d5e38fcd40"
coder_profile_stac = Profile( # type: ignore
id=f"profile_studio_coder_stac",
groups=["group-a", "group-b"],
definition=ProfileDefinition( # type: ignore
display_name="Understanding STAC for input/output data modelling",
description="Understand the role of STAC in input/output data manifests in EO data processing workflows",
slug="eoepca_coder_slug_stac",
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_guarantee=1,
cpu_limit=2,
mem_guarantee="4G",
mem_limit="6G",
image=image,
),
),
node_selector={},
volumes=[workspace_volume],
config_maps=[init_stac_cm, bash_rc_cm, bash_login_cm],
pod_env_vars={
"HOME": "/workspace",
"CONDA_ENVS_PATH": "/workspace/.envs",
"CONDARC": "/workspace/.condarc",
"XDG_RUNTIME_DIR": "/workspace/.local",
"XDG_RUNTIME_DIR": "/workspace/.local",
"XDG_CONFIG_HOME": "/workspace/.local",
"XDG_DATA_HOME": "/workspace/.local/share/",
"CWLTOOL_OPTIONS": "--podman",
"CODE_SERVER_WS": "/workspace/stac-eoap",
"AWS_DEFAULT_REGION": "us-east-1",
"AWS_ACCESS_KEY_ID": "test",
"AWS_SECRET_ACCESS_KEY": "test",
},
role_bindings=[],
init_containers=[init_container],
image_pull_secrets=[image_pull_secret],
manifests=[localstack_manifest],
)
profiles.append(coder_profile_stac)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab', description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='jupyter/scipy-notebook', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab_2', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab - profile 2', description='Jupyter Lab with Python 3.11 private image - demoes the use of an image pull secret', slug='eoepca_jupyter_lab_2', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/iat-jupyterlab:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder_stac', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Understanding STAC for input/output data modelling', description='Understand the role of STAC in input/output data manifests in EO data processing workflows', slug='eoepca_coder_slug_stac', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='docker.io/eoepca/pde-code-server@sha256:f57a3d5eabcae667e0db6e84a57b0c07c692c88f0fb5c8f6900ab8d5e38fcd40', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, content='set -x \n\ncd /workspace\n\ngit clone \'https://github.com/eoap/stac-eoap.git\'\n\ncode-server --install-extension ms-python.python \ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nmkdir -p /workspace/User/\n\necho \'{"workbench.colorTheme": "Visual Studio Dark"}\' > /workspace/User/settings.json\n\npython -m venv /workspace/.venv\nsource /workspace/.venv/bin/activate\n/workspace/.venv/bin/python -m pip install --no-cache-dir stactools rasterio requests stac-asset click-logging tabulate tqdm pystac-client ipykernel loguru scikit-image rio_stac boto3==1.35.23\n\n/workspace/.venv/bin/python -m pip install --index-url https://test.pypi.org/simple cwl-wrapper\n\n/workspace/.venv/bin/python -m ipykernel install --user --name stac_env --display-name "Python (STAC)"\n\nexport AWS_DEFAULT_REGION="us-east-1"\nexport AWS_ACCESS_KEY_ID="test"\nexport AWS_SECRET_ACCESS_KEY="test"\naws s3 mb s3://results --endpoint-url=http://localstack:4566\n\nexit 0', persist=False), ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False), ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.local', 'XDG_DATA_HOME': '/workspace/.local/share/', 'CWLTOOL_OPTIONS': '--podman', 'CODE_SERVER_WS': '/workspace/stac-eoap', 'AWS_DEFAULT_REGION': 'us-east-1', 'AWS_ACCESS_KEY_ID': 'test', 'AWS_SECRET_ACCESS_KEY': 'test'}, default_url=None, node_selector={}, role_bindings=[], image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=[Manifest(name='manifests', key='manifests', content=[{'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': {'name': 'localstack'}}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'Role', 'metadata': {'name': 'localstack'}, 'rules': [{'apiGroups': [''], 'resources': ['pods'], 'verbs': ['*']}, {'apiGroups': [''], 'resources': ['pods/log'], 'verbs': ['get']}, {'apiGroups': [''], 'resources': ['pods/exec'], 'verbs': ['get', 'create']}, {'apiGroups': [''], 'resources': ['services'], 'verbs': ['get', 'list']}]}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'RoleBinding', 'metadata': {'name': 'localstack'}, 'subjects': [{'kind': 'ServiceAccount', 'name': 'localstack'}], 'roleRef': {'kind': 'Role', 'name': 'localstack', 'apiGroup': 'rbac.authorization.k8s.io'}}, {'apiVersion': 'v1', 'kind': 'Service', 'metadata': {'name': 'localstack'}, 'spec': {'type': 'ClusterIP', 'ports': [{'name': 'edge', 'port': 4566, 'targetPort': 4566}, {'name': 'external-service-port-4510', 'port': 4510, 'targetPort': 'ext-svc-4510'}, {'name': 'external-service-port-4511', 'port': 4511, 'targetPort': 'ext-svc-4511'}, {'name': 'external-service-port-4512', 'port': 4512, 'targetPort': 'ext-svc-4512'}, {'name': 'external-service-port-4513', 'port': 4513, 'targetPort': 'ext-svc-4513'}, {'name': 'external-service-port-4514', 'port': 4514, 'targetPort': 'ext-svc-4514'}, {'name': 'external-service-port-4515', 'port': 4515, 'targetPort': 'ext-svc-4515'}, {'name': 'external-service-port-4516', 'port': 4516, 'targetPort': 'ext-svc-4516'}, {'name': 'external-service-port-4517', 'port': 4517, 'targetPort': 'ext-svc-4517'}, {'name': 'external-service-port-4518', 'port': 4518, 'targetPort': 'ext-svc-4518'}, {'name': 'external-service-port-4519', 'port': 4519, 'targetPort': 'ext-svc-4519'}, {'name': 'external-service-port-4520', 'port': 4520, 'targetPort': 'ext-svc-4520'}, {'name': 'external-service-port-4521', 'port': 4521, 'targetPort': 'ext-svc-4521'}, {'name': 'external-service-port-4522', 'port': 4522, 'targetPort': 'ext-svc-4522'}, {'name': 'external-service-port-4523', 'port': 4523, 'targetPort': 'ext-svc-4523'}, {'name': 'external-service-port-4524', 'port': 4524, 'targetPort': 'ext-svc-4524'}, {'name': 'external-service-port-4525', 'port': 4525, 'targetPort': 'ext-svc-4525'}, {'name': 'external-service-port-4526', 'port': 4526, 'targetPort': 'ext-svc-4526'}, {'name': 'external-service-port-4527', 'port': 4527, 'targetPort': 'ext-svc-4527'}, {'name': 'external-service-port-4528', 'port': 4528, 'targetPort': 'ext-svc-4528'}, {'name': 'external-service-port-4529', 'port': 4529, 'targetPort': 'ext-svc-4529'}, {'name': 'external-service-port-4530', 'port': 4530, 'targetPort': 'ext-svc-4530'}, {'name': 'external-service-port-4531', 'port': 4531, 'targetPort': 'ext-svc-4531'}, {'name': 'external-service-port-4532', 'port': 4532, 'targetPort': 'ext-svc-4532'}, {'name': 'external-service-port-4533', 'port': 4533, 'targetPort': 'ext-svc-4533'}, {'name': 'external-service-port-4534', 'port': 4534, 'targetPort': 'ext-svc-4534'}, {'name': 'external-service-port-4535', 'port': 4535, 'targetPort': 'ext-svc-4535'}, {'name': 'external-service-port-4536', 'port': 4536, 'targetPort': 'ext-svc-4536'}, {'name': 'external-service-port-4537', 'port': 4537, 'targetPort': 'ext-svc-4537'}, {'name': 'external-service-port-4538', 'port': 4538, 'targetPort': 'ext-svc-4538'}, {'name': 'external-service-port-4539', 'port': 4539, 'targetPort': 'ext-svc-4539'}, {'name': 'external-service-port-4540', 'port': 4540, 'targetPort': 'ext-svc-4540'}, {'name': 'external-service-port-4541', 'port': 4541, 'targetPort': 'ext-svc-4541'}, {'name': 'external-service-port-4542', 'port': 4542, 'targetPort': 'ext-svc-4542'}, {'name': 'external-service-port-4543', 'port': 4543, 'targetPort': 'ext-svc-4543'}, {'name': 'external-service-port-4544', 'port': 4544, 'targetPort': 'ext-svc-4544'}, {'name': 'external-service-port-4545', 'port': 4545, 'targetPort': 'ext-svc-4545'}, {'name': 'external-service-port-4546', 'port': 4546, 'targetPort': 'ext-svc-4546'}, {'name': 'external-service-port-4547', 'port': 4547, 'targetPort': 'ext-svc-4547'}, {'name': 'external-service-port-4548', 'port': 4548, 'targetPort': 'ext-svc-4548'}, {'name': 'external-service-port-4549', 'port': 4549, 'targetPort': 'ext-svc-4549'}, {'name': 'external-service-port-4550', 'port': 4550, 'targetPort': 'ext-svc-4550'}, {'name': 'external-service-port-4551', 'port': 4551, 'targetPort': 'ext-svc-4551'}, {'name': 'external-service-port-4552', 'port': 4552, 'targetPort': 'ext-svc-4552'}, {'name': 'external-service-port-4553', 'port': 4553, 'targetPort': 'ext-svc-4553'}, {'name': 'external-service-port-4554', 'port': 4554, 'targetPort': 'ext-svc-4554'}, {'name': 'external-service-port-4555', 'port': 4555, 'targetPort': 'ext-svc-4555'}, {'name': 'external-service-port-4556', 'port': 4556, 'targetPort': 'ext-svc-4556'}, {'name': 'external-service-port-4557', 'port': 4557, 'targetPort': 'ext-svc-4557'}, {'name': 'external-service-port-4558', 'port': 4558, 'targetPort': 'ext-svc-4558'}, {'name': 'external-service-port-4559', 'port': 4559, 'targetPort': 'ext-svc-4559'}], 'selector': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}}, {'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': {'name': 'localstack'}, 'spec': {'replicas': 1, 'strategy': {'type': 'RollingUpdate'}, 'selector': {'matchLabels': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'template': {'metadata': {'labels': {'app': 'localstack-{{ spawner.user.name }}', 'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'spec': {'serviceAccountName': 'localstack', 'securityContext': {}, 'containers': [{'name': 'localstack', 'securityContext': {}, 'image': 'localstack/localstack:latest', 'imagePullPolicy': 'IfNotPresent', 'ports': [{'name': 'edge', 'containerPort': 4566, 'protocol': 'TCP'}, {'name': 'ext-svc-4510', 'containerPort': 4510, 'protocol': 'TCP'}, {'name': 'ext-svc-4511', 'containerPort': 4511, 'protocol': 'TCP'}, {'name': 'ext-svc-4512', 'containerPort': 4512, 'protocol': 'TCP'}, {'name': 'ext-svc-4513', 'containerPort': 4513, 'protocol': 'TCP'}, {'name': 'ext-svc-4514', 'containerPort': 4514, 'protocol': 'TCP'}, {'name': 'ext-svc-4515', 'containerPort': 4515, 'protocol': 'TCP'}, {'name': 'ext-svc-4516', 'containerPort': 4516, 'protocol': 'TCP'}, {'name': 'ext-svc-4517', 'containerPort': 4517, 'protocol': 'TCP'}, {'name': 'ext-svc-4518', 'containerPort': 4518, 'protocol': 'TCP'}, {'name': 'ext-svc-4519', 'containerPort': 4519, 'protocol': 'TCP'}, {'name': 'ext-svc-4520', 'containerPort': 4520, 'protocol': 'TCP'}, {'name': 'ext-svc-4521', 'containerPort': 4521, 'protocol': 'TCP'}, {'name': 'ext-svc-4522', 'containerPort': 4522, 'protocol': 'TCP'}, {'name': 'ext-svc-4523', 'containerPort': 4523, 'protocol': 'TCP'}, {'name': 'ext-svc-4524', 'containerPort': 4524, 'protocol': 'TCP'}, {'name': 'ext-svc-4525', 'containerPort': 4525, 'protocol': 'TCP'}, {'name': 'ext-svc-4526', 'containerPort': 4526, 'protocol': 'TCP'}, {'name': 'ext-svc-4527', 'containerPort': 4527, 'protocol': 'TCP'}, {'name': 'ext-svc-4528', 'containerPort': 4528, 'protocol': 'TCP'}, {'name': 'ext-svc-4529', 'containerPort': 4529, 'protocol': 'TCP'}, {'name': 'ext-svc-4530', 'containerPort': 4530, 'protocol': 'TCP'}, {'name': 'ext-svc-4531', 'containerPort': 4531, 'protocol': 'TCP'}, {'name': 'ext-svc-4532', 'containerPort': 4532, 'protocol': 'TCP'}, {'name': 'ext-svc-4533', 'containerPort': 4533, 'protocol': 'TCP'}, {'name': 'ext-svc-4534', 'containerPort': 4534, 'protocol': 'TCP'}, {'name': 'ext-svc-4535', 'containerPort': 4535, 'protocol': 'TCP'}, {'name': 'ext-svc-4536', 'containerPort': 4536, 'protocol': 'TCP'}, {'name': 'ext-svc-4537', 'containerPort': 4537, 'protocol': 'TCP'}, {'name': 'ext-svc-4538', 'containerPort': 4538, 'protocol': 'TCP'}, {'name': 'ext-svc-4539', 'containerPort': 4539, 'protocol': 'TCP'}, {'name': 'ext-svc-4540', 'containerPort': 4540, 'protocol': 'TCP'}, {'name': 'ext-svc-4541', 'containerPort': 4541, 'protocol': 'TCP'}, {'name': 'ext-svc-4542', 'containerPort': 4542, 'protocol': 'TCP'}, {'name': 'ext-svc-4543', 'containerPort': 4543, 'protocol': 'TCP'}, {'name': 'ext-svc-4544', 'containerPort': 4544, 'protocol': 'TCP'}, {'name': 'ext-svc-4545', 'containerPort': 4545, 'protocol': 'TCP'}, {'name': 'ext-svc-4546', 'containerPort': 4546, 'protocol': 'TCP'}, {'name': 'ext-svc-4547', 'containerPort': 4547, 'protocol': 'TCP'}, {'name': 'ext-svc-4548', 'containerPort': 4548, 'protocol': 'TCP'}, {'name': 'ext-svc-4549', 'containerPort': 4549, 'protocol': 'TCP'}, {'name': 'ext-svc-4550', 'containerPort': 4550, 'protocol': 'TCP'}, {'name': 'ext-svc-4551', 'containerPort': 4551, 'protocol': 'TCP'}, {'name': 'ext-svc-4552', 'containerPort': 4552, 'protocol': 'TCP'}, {'name': 'ext-svc-4553', 'containerPort': 4553, 'protocol': 'TCP'}, {'name': 'ext-svc-4554', 'containerPort': 4554, 'protocol': 'TCP'}, {'name': 'ext-svc-4555', 'containerPort': 4555, 'protocol': 'TCP'}, {'name': 'ext-svc-4556', 'containerPort': 4556, 'protocol': 'TCP'}, {'name': 'ext-svc-4557', 'containerPort': 4557, 'protocol': 'TCP'}, {'name': 'ext-svc-4558', 'containerPort': 4558, 'protocol': 'TCP'}, {'name': 'ext-svc-4559', 'containerPort': 4559, 'protocol': 'TCP'}], 'livenessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'readinessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'resources': {}, 'env': [{'name': 'DEBUG', 'value': '0'}, {'name': 'EXTERNAL_SERVICE_PORTS_START', 'value': '4510'}, {'name': 'EXTERNAL_SERVICE_PORTS_END', 'value': '4560'}, {'name': 'LOCALSTACK_K8S_SERVICE_NAME', 'value': 'localstack'}, {'name': 'LOCALSTACK_K8S_NAMESPACE', 'valueFrom': {'fieldRef': {'fieldPath': 'metadata.namespace'}}}, {'name': 'LAMBDA_RUNTIME_EXECUTOR', 'value': 'docker'}, {'name': 'LAMBDA_K8S_IMAGE_PREFIX', 'value': 'localstack/lambda-'}, {'name': 'LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT', 'value': '60'}, {'name': 'OVERRIDE_IN_DOCKER', 'value': '1'}]}], 'volumes': []}}}}, {'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': {'name': 'my-config'}, 'data': {'ENV_VAR1': 'value1', 'ENV_VAR2': 'value2'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'my-secret'}, 'type': 'Opaque', 'data': {'SECRET_KEY1': 'dmFsdWUx', 'SECRET_KEY2': 'dmFsdWUy'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'aws-credentials-{{ spawner.user.name }}'}, 'type': 'Opaque', 'data': {'credentials': 'W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPUFTSUFJT1NGT0ROTjdFWEFNUExFCmF3c19zZWNyZXRfYWNjZXNzX2tleT13SmFsclhVdG5GRU1JL0s3TURFTkcvYlB4UmZpQ1lFWEFNUExFS0VZCmF3c19zZXNzaW9uX3Rva2VuPUlRb0piM2pySmdCV05FTE5Hb2xHSkxFT3RTVEFOR1k0TFlPNUk0SzVOUlZFS1pPTkNTTk1HRlNUS1FNSUxXUjJPUzAwRklDRTExSlg='}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'data-by-name', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'data-by-name', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': 'secret-value', 'remoteRef': {'key': 'secret-one', 'property': 'the-key'}}]}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'eoepca-plus-secret-ro', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'eoepca-plus-secret-ro', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': '.dockerconfigjson', 'remoteRef': {'key': 'eoepca-plus-secret-ro', 'property': '.dockerconfigjson'}}]}}], persist=False)], env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
QGIS¶
This profile is configured to deploy the QGIS application on the App Hub, enabling users to visualize and analyze Earth observation data directly within the platform. The deployment ensures that QGIS is configured with the necessary resources, storage, and dependencies to support geospatial analysis, map rendering, and data processing. By integrating QGIS into the App Hub, users can seamlessly interact with satellite imagery, vector layers, and raster data for advanced geospatial analysis.
image = "eoepca/iga-remote-desktop-qgis:1.1.3"
qgis_profile = Profile( # type: ignore
id="profile_studio_desktop_qgis",
groups=["group-a", "group-b"],
definition=ProfileDefinition( # type: ignore
display_name="QGIS on a Remote Desktop",
description="Spatial visualization and decision-making tools for everyone",
slug="eoepca_desktop_qgis",
default=False,
kubespawner_override=KubespawnerOverride( # type: ignore
cpu_limit=2,
mem_limit="2G",
image=image,
),
),
node_selector={},
volumes=[workspace_volume],
config_maps=[bash_rc_cm, bash_login_cm],
pod_env_vars={"HOME": "/workspace"},
default_url="desktop",
init_containers=[],
)
profiles.append(qgis_profile)
profiles
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab', description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='jupyter/scipy-notebook', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab_2', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab - profile 2', description='Jupyter Lab with Python 3.11 private image - demoes the use of an image pull secret', slug='eoepca_jupyter_lab_2', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/iat-jupyterlab:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder_stac', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Understanding STAC for input/output data modelling', description='Understand the role of STAC in input/output data manifests in EO data processing workflows', slug='eoepca_coder_slug_stac', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='docker.io/eoepca/pde-code-server@sha256:f57a3d5eabcae667e0db6e84a57b0c07c692c88f0fb5c8f6900ab8d5e38fcd40', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, content='set -x \n\ncd /workspace\n\ngit clone \'https://github.com/eoap/stac-eoap.git\'\n\ncode-server --install-extension ms-python.python \ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nmkdir -p /workspace/User/\n\necho \'{"workbench.colorTheme": "Visual Studio Dark"}\' > /workspace/User/settings.json\n\npython -m venv /workspace/.venv\nsource /workspace/.venv/bin/activate\n/workspace/.venv/bin/python -m pip install --no-cache-dir stactools rasterio requests stac-asset click-logging tabulate tqdm pystac-client ipykernel loguru scikit-image rio_stac boto3==1.35.23\n\n/workspace/.venv/bin/python -m pip install --index-url https://test.pypi.org/simple cwl-wrapper\n\n/workspace/.venv/bin/python -m ipykernel install --user --name stac_env --display-name "Python (STAC)"\n\nexport AWS_DEFAULT_REGION="us-east-1"\nexport AWS_ACCESS_KEY_ID="test"\nexport AWS_SECRET_ACCESS_KEY="test"\naws s3 mb s3://results --endpoint-url=http://localstack:4566\n\nexit 0', persist=False), ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False), ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.local', 'XDG_DATA_HOME': '/workspace/.local/share/', 'CWLTOOL_OPTIONS': '--podman', 'CODE_SERVER_WS': '/workspace/stac-eoap', 'AWS_DEFAULT_REGION': 'us-east-1', 'AWS_ACCESS_KEY_ID': 'test', 'AWS_SECRET_ACCESS_KEY': 'test'}, default_url=None, node_selector={}, role_bindings=[], image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=[Manifest(name='manifests', key='manifests', content=[{'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': {'name': 'localstack'}}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'Role', 'metadata': {'name': 'localstack'}, 'rules': [{'apiGroups': [''], 'resources': ['pods'], 'verbs': ['*']}, {'apiGroups': [''], 'resources': ['pods/log'], 'verbs': ['get']}, {'apiGroups': [''], 'resources': ['pods/exec'], 'verbs': ['get', 'create']}, {'apiGroups': [''], 'resources': ['services'], 'verbs': ['get', 'list']}]}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'RoleBinding', 'metadata': {'name': 'localstack'}, 'subjects': [{'kind': 'ServiceAccount', 'name': 'localstack'}], 'roleRef': {'kind': 'Role', 'name': 'localstack', 'apiGroup': 'rbac.authorization.k8s.io'}}, {'apiVersion': 'v1', 'kind': 'Service', 'metadata': {'name': 'localstack'}, 'spec': {'type': 'ClusterIP', 'ports': [{'name': 'edge', 'port': 4566, 'targetPort': 4566}, {'name': 'external-service-port-4510', 'port': 4510, 'targetPort': 'ext-svc-4510'}, {'name': 'external-service-port-4511', 'port': 4511, 'targetPort': 'ext-svc-4511'}, {'name': 'external-service-port-4512', 'port': 4512, 'targetPort': 'ext-svc-4512'}, {'name': 'external-service-port-4513', 'port': 4513, 'targetPort': 'ext-svc-4513'}, {'name': 'external-service-port-4514', 'port': 4514, 'targetPort': 'ext-svc-4514'}, {'name': 'external-service-port-4515', 'port': 4515, 'targetPort': 'ext-svc-4515'}, {'name': 'external-service-port-4516', 'port': 4516, 'targetPort': 'ext-svc-4516'}, {'name': 'external-service-port-4517', 'port': 4517, 'targetPort': 'ext-svc-4517'}, {'name': 'external-service-port-4518', 'port': 4518, 'targetPort': 'ext-svc-4518'}, {'name': 'external-service-port-4519', 'port': 4519, 'targetPort': 'ext-svc-4519'}, {'name': 'external-service-port-4520', 'port': 4520, 'targetPort': 'ext-svc-4520'}, {'name': 'external-service-port-4521', 'port': 4521, 'targetPort': 'ext-svc-4521'}, {'name': 'external-service-port-4522', 'port': 4522, 'targetPort': 'ext-svc-4522'}, {'name': 'external-service-port-4523', 'port': 4523, 'targetPort': 'ext-svc-4523'}, {'name': 'external-service-port-4524', 'port': 4524, 'targetPort': 'ext-svc-4524'}, {'name': 'external-service-port-4525', 'port': 4525, 'targetPort': 'ext-svc-4525'}, {'name': 'external-service-port-4526', 'port': 4526, 'targetPort': 'ext-svc-4526'}, {'name': 'external-service-port-4527', 'port': 4527, 'targetPort': 'ext-svc-4527'}, {'name': 'external-service-port-4528', 'port': 4528, 'targetPort': 'ext-svc-4528'}, {'name': 'external-service-port-4529', 'port': 4529, 'targetPort': 'ext-svc-4529'}, {'name': 'external-service-port-4530', 'port': 4530, 'targetPort': 'ext-svc-4530'}, {'name': 'external-service-port-4531', 'port': 4531, 'targetPort': 'ext-svc-4531'}, {'name': 'external-service-port-4532', 'port': 4532, 'targetPort': 'ext-svc-4532'}, {'name': 'external-service-port-4533', 'port': 4533, 'targetPort': 'ext-svc-4533'}, {'name': 'external-service-port-4534', 'port': 4534, 'targetPort': 'ext-svc-4534'}, {'name': 'external-service-port-4535', 'port': 4535, 'targetPort': 'ext-svc-4535'}, {'name': 'external-service-port-4536', 'port': 4536, 'targetPort': 'ext-svc-4536'}, {'name': 'external-service-port-4537', 'port': 4537, 'targetPort': 'ext-svc-4537'}, {'name': 'external-service-port-4538', 'port': 4538, 'targetPort': 'ext-svc-4538'}, {'name': 'external-service-port-4539', 'port': 4539, 'targetPort': 'ext-svc-4539'}, {'name': 'external-service-port-4540', 'port': 4540, 'targetPort': 'ext-svc-4540'}, {'name': 'external-service-port-4541', 'port': 4541, 'targetPort': 'ext-svc-4541'}, {'name': 'external-service-port-4542', 'port': 4542, 'targetPort': 'ext-svc-4542'}, {'name': 'external-service-port-4543', 'port': 4543, 'targetPort': 'ext-svc-4543'}, {'name': 'external-service-port-4544', 'port': 4544, 'targetPort': 'ext-svc-4544'}, {'name': 'external-service-port-4545', 'port': 4545, 'targetPort': 'ext-svc-4545'}, {'name': 'external-service-port-4546', 'port': 4546, 'targetPort': 'ext-svc-4546'}, {'name': 'external-service-port-4547', 'port': 4547, 'targetPort': 'ext-svc-4547'}, {'name': 'external-service-port-4548', 'port': 4548, 'targetPort': 'ext-svc-4548'}, {'name': 'external-service-port-4549', 'port': 4549, 'targetPort': 'ext-svc-4549'}, {'name': 'external-service-port-4550', 'port': 4550, 'targetPort': 'ext-svc-4550'}, {'name': 'external-service-port-4551', 'port': 4551, 'targetPort': 'ext-svc-4551'}, {'name': 'external-service-port-4552', 'port': 4552, 'targetPort': 'ext-svc-4552'}, {'name': 'external-service-port-4553', 'port': 4553, 'targetPort': 'ext-svc-4553'}, {'name': 'external-service-port-4554', 'port': 4554, 'targetPort': 'ext-svc-4554'}, {'name': 'external-service-port-4555', 'port': 4555, 'targetPort': 'ext-svc-4555'}, {'name': 'external-service-port-4556', 'port': 4556, 'targetPort': 'ext-svc-4556'}, {'name': 'external-service-port-4557', 'port': 4557, 'targetPort': 'ext-svc-4557'}, {'name': 'external-service-port-4558', 'port': 4558, 'targetPort': 'ext-svc-4558'}, {'name': 'external-service-port-4559', 'port': 4559, 'targetPort': 'ext-svc-4559'}], 'selector': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}}, {'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': {'name': 'localstack'}, 'spec': {'replicas': 1, 'strategy': {'type': 'RollingUpdate'}, 'selector': {'matchLabels': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'template': {'metadata': {'labels': {'app': 'localstack-{{ spawner.user.name }}', 'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'spec': {'serviceAccountName': 'localstack', 'securityContext': {}, 'containers': [{'name': 'localstack', 'securityContext': {}, 'image': 'localstack/localstack:latest', 'imagePullPolicy': 'IfNotPresent', 'ports': [{'name': 'edge', 'containerPort': 4566, 'protocol': 'TCP'}, {'name': 'ext-svc-4510', 'containerPort': 4510, 'protocol': 'TCP'}, {'name': 'ext-svc-4511', 'containerPort': 4511, 'protocol': 'TCP'}, {'name': 'ext-svc-4512', 'containerPort': 4512, 'protocol': 'TCP'}, {'name': 'ext-svc-4513', 'containerPort': 4513, 'protocol': 'TCP'}, {'name': 'ext-svc-4514', 'containerPort': 4514, 'protocol': 'TCP'}, {'name': 'ext-svc-4515', 'containerPort': 4515, 'protocol': 'TCP'}, {'name': 'ext-svc-4516', 'containerPort': 4516, 'protocol': 'TCP'}, {'name': 'ext-svc-4517', 'containerPort': 4517, 'protocol': 'TCP'}, {'name': 'ext-svc-4518', 'containerPort': 4518, 'protocol': 'TCP'}, {'name': 'ext-svc-4519', 'containerPort': 4519, 'protocol': 'TCP'}, {'name': 'ext-svc-4520', 'containerPort': 4520, 'protocol': 'TCP'}, {'name': 'ext-svc-4521', 'containerPort': 4521, 'protocol': 'TCP'}, {'name': 'ext-svc-4522', 'containerPort': 4522, 'protocol': 'TCP'}, {'name': 'ext-svc-4523', 'containerPort': 4523, 'protocol': 'TCP'}, {'name': 'ext-svc-4524', 'containerPort': 4524, 'protocol': 'TCP'}, {'name': 'ext-svc-4525', 'containerPort': 4525, 'protocol': 'TCP'}, {'name': 'ext-svc-4526', 'containerPort': 4526, 'protocol': 'TCP'}, {'name': 'ext-svc-4527', 'containerPort': 4527, 'protocol': 'TCP'}, {'name': 'ext-svc-4528', 'containerPort': 4528, 'protocol': 'TCP'}, {'name': 'ext-svc-4529', 'containerPort': 4529, 'protocol': 'TCP'}, {'name': 'ext-svc-4530', 'containerPort': 4530, 'protocol': 'TCP'}, {'name': 'ext-svc-4531', 'containerPort': 4531, 'protocol': 'TCP'}, {'name': 'ext-svc-4532', 'containerPort': 4532, 'protocol': 'TCP'}, {'name': 'ext-svc-4533', 'containerPort': 4533, 'protocol': 'TCP'}, {'name': 'ext-svc-4534', 'containerPort': 4534, 'protocol': 'TCP'}, {'name': 'ext-svc-4535', 'containerPort': 4535, 'protocol': 'TCP'}, {'name': 'ext-svc-4536', 'containerPort': 4536, 'protocol': 'TCP'}, {'name': 'ext-svc-4537', 'containerPort': 4537, 'protocol': 'TCP'}, {'name': 'ext-svc-4538', 'containerPort': 4538, 'protocol': 'TCP'}, {'name': 'ext-svc-4539', 'containerPort': 4539, 'protocol': 'TCP'}, {'name': 'ext-svc-4540', 'containerPort': 4540, 'protocol': 'TCP'}, {'name': 'ext-svc-4541', 'containerPort': 4541, 'protocol': 'TCP'}, {'name': 'ext-svc-4542', 'containerPort': 4542, 'protocol': 'TCP'}, {'name': 'ext-svc-4543', 'containerPort': 4543, 'protocol': 'TCP'}, {'name': 'ext-svc-4544', 'containerPort': 4544, 'protocol': 'TCP'}, {'name': 'ext-svc-4545', 'containerPort': 4545, 'protocol': 'TCP'}, {'name': 'ext-svc-4546', 'containerPort': 4546, 'protocol': 'TCP'}, {'name': 'ext-svc-4547', 'containerPort': 4547, 'protocol': 'TCP'}, {'name': 'ext-svc-4548', 'containerPort': 4548, 'protocol': 'TCP'}, {'name': 'ext-svc-4549', 'containerPort': 4549, 'protocol': 'TCP'}, {'name': 'ext-svc-4550', 'containerPort': 4550, 'protocol': 'TCP'}, {'name': 'ext-svc-4551', 'containerPort': 4551, 'protocol': 'TCP'}, {'name': 'ext-svc-4552', 'containerPort': 4552, 'protocol': 'TCP'}, {'name': 'ext-svc-4553', 'containerPort': 4553, 'protocol': 'TCP'}, {'name': 'ext-svc-4554', 'containerPort': 4554, 'protocol': 'TCP'}, {'name': 'ext-svc-4555', 'containerPort': 4555, 'protocol': 'TCP'}, {'name': 'ext-svc-4556', 'containerPort': 4556, 'protocol': 'TCP'}, {'name': 'ext-svc-4557', 'containerPort': 4557, 'protocol': 'TCP'}, {'name': 'ext-svc-4558', 'containerPort': 4558, 'protocol': 'TCP'}, {'name': 'ext-svc-4559', 'containerPort': 4559, 'protocol': 'TCP'}], 'livenessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'readinessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'resources': {}, 'env': [{'name': 'DEBUG', 'value': '0'}, {'name': 'EXTERNAL_SERVICE_PORTS_START', 'value': '4510'}, {'name': 'EXTERNAL_SERVICE_PORTS_END', 'value': '4560'}, {'name': 'LOCALSTACK_K8S_SERVICE_NAME', 'value': 'localstack'}, {'name': 'LOCALSTACK_K8S_NAMESPACE', 'valueFrom': {'fieldRef': {'fieldPath': 'metadata.namespace'}}}, {'name': 'LAMBDA_RUNTIME_EXECUTOR', 'value': 'docker'}, {'name': 'LAMBDA_K8S_IMAGE_PREFIX', 'value': 'localstack/lambda-'}, {'name': 'LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT', 'value': '60'}, {'name': 'OVERRIDE_IN_DOCKER', 'value': '1'}]}], 'volumes': []}}}}, {'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': {'name': 'my-config'}, 'data': {'ENV_VAR1': 'value1', 'ENV_VAR2': 'value2'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'my-secret'}, 'type': 'Opaque', 'data': {'SECRET_KEY1': 'dmFsdWUx', 'SECRET_KEY2': 'dmFsdWUy'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'aws-credentials-{{ spawner.user.name }}'}, 'type': 'Opaque', 'data': {'credentials': 'W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPUFTSUFJT1NGT0ROTjdFWEFNUExFCmF3c19zZWNyZXRfYWNjZXNzX2tleT13SmFsclhVdG5GRU1JL0s3TURFTkcvYlB4UmZpQ1lFWEFNUExFS0VZCmF3c19zZXNzaW9uX3Rva2VuPUlRb0piM2pySmdCV05FTE5Hb2xHSkxFT3RTVEFOR1k0TFlPNUk0SzVOUlZFS1pPTkNTTk1HRlNUS1FNSUxXUjJPUzAwRklDRTExSlg='}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'data-by-name', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'data-by-name', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': 'secret-value', 'remoteRef': {'key': 'secret-one', 'property': 'the-key'}}]}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'eoepca-plus-secret-ro', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'eoepca-plus-secret-ro', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': '.dockerconfigjson', 'remoteRef': {'key': 'eoepca-plus-secret-ro', 'property': '.dockerconfigjson'}}]}}], persist=False)], env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_desktop_qgis', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='QGIS on a Remote Desktop', description='Spatial visualization and decision-making tools for everyone', slug='eoepca_desktop_qgis', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='2G', mem_guarantee=None, image='eoepca/iga-remote-desktop-qgis:1.1.3', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False), ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace'}, default_url='desktop', node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)]
Write Configuration¶
In the code below, the user inspects all the configurations made in the previous section and then generates a config.yaml file. This file contains the complete configuration of the App Hub, including the different profiles defined for deployment. The config.yaml
serves as the configuration blueprint, allowing the user to easily apply and share the profiles across different environments or clusters.
pprint(profiles)
config = Config(profiles=profiles) # type: ignore
pprint(f'config: {config}')
eoepca_demo_config_path = str(Path(current_dir).parent.parent / 'eoepca-demo' / 'config.yml')
with open(eoepca_demo_config_path, "w") as file:
yaml.dump(config.model_dump(), file)
[Profile(id='profile_studio_coder1', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Small', description=None, slug='ellip_studio_coder_slug_s', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Code Server Medium', description=None, slug='ellip_studio_coder_slug_m', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Coder demo init script', description='This profile is used to demonstrate the use of an init script', slug='eoepca_demo_init_script', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, content="set -x\n\ncd /workspace\n\ngit clone 'https://github.com/eoap/mastering-app-package.git'\n\ncode-server --install-extension ms-python.python\ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nexit 0\n", persist=False)], volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], volume_mount=VolumeMount(name='calrissian-volume', mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab', description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='jupyter/scipy-notebook', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_jupyter_lab_2', groups=['group-c'], definition=ProfileDefinition(display_name='Jupyter Lab - profile 2', description='Jupyter Lab with Python 3.11 private image - demoes the use of an image pull secret', slug='eoepca_jupyter_lab_2', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='eoepca/iat-jupyterlab:develop', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, default_url=None, node_selector={}, role_bindings=None, image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_coder_stac', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='Understanding STAC for input/output data modelling', description='Understand the role of STAC in input/output data manifests in EO data processing workflows', slug='eoepca_coder_slug_stac', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', image='docker.io/eoepca/pde-code-server@sha256:f57a3d5eabcae667e0db6e84a57b0c07c692c88f0fb5c8f6900ab8d5e38fcd40', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='init', key='init', mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, content='set -x \n\ncd /workspace\n\ngit clone \'https://github.com/eoap/stac-eoap.git\'\n\ncode-server --install-extension ms-python.python \ncode-server --install-extension redhat.vscode-yaml\ncode-server --install-extension sbg-rabix.benten-cwl\ncode-server --install-extension ms-toolsai.jupyter\n\nln -s /workspace/.local/share/code-server/extensions /workspace/extensions\n\nmkdir -p /workspace/User/\n\necho \'{"workbench.colorTheme": "Visual Studio Dark"}\' > /workspace/User/settings.json\n\npython -m venv /workspace/.venv\nsource /workspace/.venv/bin/activate\n/workspace/.venv/bin/python -m pip install --no-cache-dir stactools rasterio requests stac-asset click-logging tabulate tqdm pystac-client ipykernel loguru scikit-image rio_stac boto3==1.35.23\n\n/workspace/.venv/bin/python -m pip install --index-url https://test.pypi.org/simple cwl-wrapper\n\n/workspace/.venv/bin/python -m ipykernel install --user --name stac_env --display-name "Python (STAC)"\n\nexport AWS_DEFAULT_REGION="us-east-1"\nexport AWS_ACCESS_KEY_ID="test"\nexport AWS_SECRET_ACCESS_KEY="test"\naws s3 mb s3://results --endpoint-url=http://localstack:4566\n\nexit 0', persist=False), ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False), ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': '/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': '/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.local', 'XDG_DATA_HOME': '/workspace/.local/share/', 'CWLTOOL_OPTIONS': '--podman', 'CODE_SERVER_WS': '/workspace/stac-eoap', 'AWS_DEFAULT_REGION': 'us-east-1', 'AWS_ACCESS_KEY_ID': 'test', 'AWS_SECRET_ACCESS_KEY': 'test'}, default_url=None, node_selector={}, role_bindings=[], image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], init_containers=[InitContainer(name='init-file-on-volume', image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh /opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', mount_path='/workspace'), InitContainerVolumeMount(name='init', mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=[Manifest(name='manifests', key='manifests', content=[{'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': {'name': 'localstack'}}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'Role', 'metadata': {'name': 'localstack'}, 'rules': [{'apiGroups': [''], 'resources': ['pods'], 'verbs': ['*']}, {'apiGroups': [''], 'resources': ['pods/log'], 'verbs': ['get']}, {'apiGroups': [''], 'resources': ['pods/exec'], 'verbs': ['get', 'create']}, {'apiGroups': [''], 'resources': ['services'], 'verbs': ['get', 'list']}]}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'RoleBinding', 'metadata': {'name': 'localstack'}, 'subjects': [{'kind': 'ServiceAccount', 'name': 'localstack'}], 'roleRef': {'kind': 'Role', 'name': 'localstack', 'apiGroup': 'rbac.authorization.k8s.io'}}, {'apiVersion': 'v1', 'kind': 'Service', 'metadata': {'name': 'localstack'}, 'spec': {'type': 'ClusterIP', 'ports': [{'name': 'edge', 'port': 4566, 'targetPort': 4566}, {'name': 'external-service-port-4510', 'port': 4510, 'targetPort': 'ext-svc-4510'}, {'name': 'external-service-port-4511', 'port': 4511, 'targetPort': 'ext-svc-4511'}, {'name': 'external-service-port-4512', 'port': 4512, 'targetPort': 'ext-svc-4512'}, {'name': 'external-service-port-4513', 'port': 4513, 'targetPort': 'ext-svc-4513'}, {'name': 'external-service-port-4514', 'port': 4514, 'targetPort': 'ext-svc-4514'}, {'name': 'external-service-port-4515', 'port': 4515, 'targetPort': 'ext-svc-4515'}, {'name': 'external-service-port-4516', 'port': 4516, 'targetPort': 'ext-svc-4516'}, {'name': 'external-service-port-4517', 'port': 4517, 'targetPort': 'ext-svc-4517'}, {'name': 'external-service-port-4518', 'port': 4518, 'targetPort': 'ext-svc-4518'}, {'name': 'external-service-port-4519', 'port': 4519, 'targetPort': 'ext-svc-4519'}, {'name': 'external-service-port-4520', 'port': 4520, 'targetPort': 'ext-svc-4520'}, {'name': 'external-service-port-4521', 'port': 4521, 'targetPort': 'ext-svc-4521'}, {'name': 'external-service-port-4522', 'port': 4522, 'targetPort': 'ext-svc-4522'}, {'name': 'external-service-port-4523', 'port': 4523, 'targetPort': 'ext-svc-4523'}, {'name': 'external-service-port-4524', 'port': 4524, 'targetPort': 'ext-svc-4524'}, {'name': 'external-service-port-4525', 'port': 4525, 'targetPort': 'ext-svc-4525'}, {'name': 'external-service-port-4526', 'port': 4526, 'targetPort': 'ext-svc-4526'}, {'name': 'external-service-port-4527', 'port': 4527, 'targetPort': 'ext-svc-4527'}, {'name': 'external-service-port-4528', 'port': 4528, 'targetPort': 'ext-svc-4528'}, {'name': 'external-service-port-4529', 'port': 4529, 'targetPort': 'ext-svc-4529'}, {'name': 'external-service-port-4530', 'port': 4530, 'targetPort': 'ext-svc-4530'}, {'name': 'external-service-port-4531', 'port': 4531, 'targetPort': 'ext-svc-4531'}, {'name': 'external-service-port-4532', 'port': 4532, 'targetPort': 'ext-svc-4532'}, {'name': 'external-service-port-4533', 'port': 4533, 'targetPort': 'ext-svc-4533'}, {'name': 'external-service-port-4534', 'port': 4534, 'targetPort': 'ext-svc-4534'}, {'name': 'external-service-port-4535', 'port': 4535, 'targetPort': 'ext-svc-4535'}, {'name': 'external-service-port-4536', 'port': 4536, 'targetPort': 'ext-svc-4536'}, {'name': 'external-service-port-4537', 'port': 4537, 'targetPort': 'ext-svc-4537'}, {'name': 'external-service-port-4538', 'port': 4538, 'targetPort': 'ext-svc-4538'}, {'name': 'external-service-port-4539', 'port': 4539, 'targetPort': 'ext-svc-4539'}, {'name': 'external-service-port-4540', 'port': 4540, 'targetPort': 'ext-svc-4540'}, {'name': 'external-service-port-4541', 'port': 4541, 'targetPort': 'ext-svc-4541'}, {'name': 'external-service-port-4542', 'port': 4542, 'targetPort': 'ext-svc-4542'}, {'name': 'external-service-port-4543', 'port': 4543, 'targetPort': 'ext-svc-4543'}, {'name': 'external-service-port-4544', 'port': 4544, 'targetPort': 'ext-svc-4544'}, {'name': 'external-service-port-4545', 'port': 4545, 'targetPort': 'ext-svc-4545'}, {'name': 'external-service-port-4546', 'port': 4546, 'targetPort': 'ext-svc-4546'}, {'name': 'external-service-port-4547', 'port': 4547, 'targetPort': 'ext-svc-4547'}, {'name': 'external-service-port-4548', 'port': 4548, 'targetPort': 'ext-svc-4548'}, {'name': 'external-service-port-4549', 'port': 4549, 'targetPort': 'ext-svc-4549'}, {'name': 'external-service-port-4550', 'port': 4550, 'targetPort': 'ext-svc-4550'}, {'name': 'external-service-port-4551', 'port': 4551, 'targetPort': 'ext-svc-4551'}, {'name': 'external-service-port-4552', 'port': 4552, 'targetPort': 'ext-svc-4552'}, {'name': 'external-service-port-4553', 'port': 4553, 'targetPort': 'ext-svc-4553'}, {'name': 'external-service-port-4554', 'port': 4554, 'targetPort': 'ext-svc-4554'}, {'name': 'external-service-port-4555', 'port': 4555, 'targetPort': 'ext-svc-4555'}, {'name': 'external-service-port-4556', 'port': 4556, 'targetPort': 'ext-svc-4556'}, {'name': 'external-service-port-4557', 'port': 4557, 'targetPort': 'ext-svc-4557'}, {'name': 'external-service-port-4558', 'port': 4558, 'targetPort': 'ext-svc-4558'}, {'name': 'external-service-port-4559', 'port': 4559, 'targetPort': 'ext-svc-4559'}], 'selector': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}}, {'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': {'name': 'localstack'}, 'spec': {'replicas': 1, 'strategy': {'type': 'RollingUpdate'}, 'selector': {'matchLabels': {'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'template': {'metadata': {'labels': {'app': 'localstack-{{ spawner.user.name }}', 'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': 'localstack'}}, 'spec': {'serviceAccountName': 'localstack', 'securityContext': {}, 'containers': [{'name': 'localstack', 'securityContext': {}, 'image': 'localstack/localstack:latest', 'imagePullPolicy': 'IfNotPresent', 'ports': [{'name': 'edge', 'containerPort': 4566, 'protocol': 'TCP'}, {'name': 'ext-svc-4510', 'containerPort': 4510, 'protocol': 'TCP'}, {'name': 'ext-svc-4511', 'containerPort': 4511, 'protocol': 'TCP'}, {'name': 'ext-svc-4512', 'containerPort': 4512, 'protocol': 'TCP'}, {'name': 'ext-svc-4513', 'containerPort': 4513, 'protocol': 'TCP'}, {'name': 'ext-svc-4514', 'containerPort': 4514, 'protocol': 'TCP'}, {'name': 'ext-svc-4515', 'containerPort': 4515, 'protocol': 'TCP'}, {'name': 'ext-svc-4516', 'containerPort': 4516, 'protocol': 'TCP'}, {'name': 'ext-svc-4517', 'containerPort': 4517, 'protocol': 'TCP'}, {'name': 'ext-svc-4518', 'containerPort': 4518, 'protocol': 'TCP'}, {'name': 'ext-svc-4519', 'containerPort': 4519, 'protocol': 'TCP'}, {'name': 'ext-svc-4520', 'containerPort': 4520, 'protocol': 'TCP'}, {'name': 'ext-svc-4521', 'containerPort': 4521, 'protocol': 'TCP'}, {'name': 'ext-svc-4522', 'containerPort': 4522, 'protocol': 'TCP'}, {'name': 'ext-svc-4523', 'containerPort': 4523, 'protocol': 'TCP'}, {'name': 'ext-svc-4524', 'containerPort': 4524, 'protocol': 'TCP'}, {'name': 'ext-svc-4525', 'containerPort': 4525, 'protocol': 'TCP'}, {'name': 'ext-svc-4526', 'containerPort': 4526, 'protocol': 'TCP'}, {'name': 'ext-svc-4527', 'containerPort': 4527, 'protocol': 'TCP'}, {'name': 'ext-svc-4528', 'containerPort': 4528, 'protocol': 'TCP'}, {'name': 'ext-svc-4529', 'containerPort': 4529, 'protocol': 'TCP'}, {'name': 'ext-svc-4530', 'containerPort': 4530, 'protocol': 'TCP'}, {'name': 'ext-svc-4531', 'containerPort': 4531, 'protocol': 'TCP'}, {'name': 'ext-svc-4532', 'containerPort': 4532, 'protocol': 'TCP'}, {'name': 'ext-svc-4533', 'containerPort': 4533, 'protocol': 'TCP'}, {'name': 'ext-svc-4534', 'containerPort': 4534, 'protocol': 'TCP'}, {'name': 'ext-svc-4535', 'containerPort': 4535, 'protocol': 'TCP'}, {'name': 'ext-svc-4536', 'containerPort': 4536, 'protocol': 'TCP'}, {'name': 'ext-svc-4537', 'containerPort': 4537, 'protocol': 'TCP'}, {'name': 'ext-svc-4538', 'containerPort': 4538, 'protocol': 'TCP'}, {'name': 'ext-svc-4539', 'containerPort': 4539, 'protocol': 'TCP'}, {'name': 'ext-svc-4540', 'containerPort': 4540, 'protocol': 'TCP'}, {'name': 'ext-svc-4541', 'containerPort': 4541, 'protocol': 'TCP'}, {'name': 'ext-svc-4542', 'containerPort': 4542, 'protocol': 'TCP'}, {'name': 'ext-svc-4543', 'containerPort': 4543, 'protocol': 'TCP'}, {'name': 'ext-svc-4544', 'containerPort': 4544, 'protocol': 'TCP'}, {'name': 'ext-svc-4545', 'containerPort': 4545, 'protocol': 'TCP'}, {'name': 'ext-svc-4546', 'containerPort': 4546, 'protocol': 'TCP'}, {'name': 'ext-svc-4547', 'containerPort': 4547, 'protocol': 'TCP'}, {'name': 'ext-svc-4548', 'containerPort': 4548, 'protocol': 'TCP'}, {'name': 'ext-svc-4549', 'containerPort': 4549, 'protocol': 'TCP'}, {'name': 'ext-svc-4550', 'containerPort': 4550, 'protocol': 'TCP'}, {'name': 'ext-svc-4551', 'containerPort': 4551, 'protocol': 'TCP'}, {'name': 'ext-svc-4552', 'containerPort': 4552, 'protocol': 'TCP'}, {'name': 'ext-svc-4553', 'containerPort': 4553, 'protocol': 'TCP'}, {'name': 'ext-svc-4554', 'containerPort': 4554, 'protocol': 'TCP'}, {'name': 'ext-svc-4555', 'containerPort': 4555, 'protocol': 'TCP'}, {'name': 'ext-svc-4556', 'containerPort': 4556, 'protocol': 'TCP'}, {'name': 'ext-svc-4557', 'containerPort': 4557, 'protocol': 'TCP'}, {'name': 'ext-svc-4558', 'containerPort': 4558, 'protocol': 'TCP'}, {'name': 'ext-svc-4559', 'containerPort': 4559, 'protocol': 'TCP'}], 'livenessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'readinessProbe': {'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': '/_localstack/health', 'port': 'edge'}}, 'resources': {}, 'env': [{'name': 'DEBUG', 'value': '0'}, {'name': 'EXTERNAL_SERVICE_PORTS_START', 'value': '4510'}, {'name': 'EXTERNAL_SERVICE_PORTS_END', 'value': '4560'}, {'name': 'LOCALSTACK_K8S_SERVICE_NAME', 'value': 'localstack'}, {'name': 'LOCALSTACK_K8S_NAMESPACE', 'valueFrom': {'fieldRef': {'fieldPath': 'metadata.namespace'}}}, {'name': 'LAMBDA_RUNTIME_EXECUTOR', 'value': 'docker'}, {'name': 'LAMBDA_K8S_IMAGE_PREFIX', 'value': 'localstack/lambda-'}, {'name': 'LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT', 'value': '60'}, {'name': 'OVERRIDE_IN_DOCKER', 'value': '1'}]}], 'volumes': []}}}}, {'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': {'name': 'my-config'}, 'data': {'ENV_VAR1': 'value1', 'ENV_VAR2': 'value2'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'my-secret'}, 'type': 'Opaque', 'data': {'SECRET_KEY1': 'dmFsdWUx', 'SECRET_KEY2': 'dmFsdWUy'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'aws-credentials-{{ spawner.user.name }}'}, 'type': 'Opaque', 'data': {'credentials': 'W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPUFTSUFJT1NGT0ROTjdFWEFNUExFCmF3c19zZWNyZXRfYWNjZXNzX2tleT13SmFsclhVdG5GRU1JL0s3TURFTkcvYlB4UmZpQ1lFWEFNUExFS0VZCmF3c19zZXNzaW9uX3Rva2VuPUlRb0piM2pySmdCV05FTE5Hb2xHSkxFT3RTVEFOR1k0TFlPNUk0SzVOUlZFS1pPTkNTTk1HRlNUS1FNSUxXUjJPUzAwRklDRTExSlg='}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'data-by-name', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'data-by-name', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': 'secret-value', 'remoteRef': {'key': 'secret-one', 'property': 'the-key'}}]}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', 'metadata': {'name': 'eoepca-plus-secret-ro', 'namespace': 'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': {'name': 'eoepca-plus-secret-ro', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': '.dockerconfigjson', 'remoteRef': {'key': 'eoepca-plus-secret-ro', 'property': '.dockerconfigjson'}}]}}], persist=False)], env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), Profile(id='profile_studio_desktop_qgis', groups=['group-a', 'group-b'], definition=ProfileDefinition(display_name='QGIS on a Remote Desktop', description='Spatial visualization and decision-making tools for everyone', slug='eoepca_desktop_qgis', default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, mem_limit='2G', mem_guarantee=None, image='eoepca/iga-remote-desktop-qgis:1.1.3', extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, readonly=True, content='alias ll="ls -l"\nalias calrissian="/opt/conda/bin/calrissian --pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir /calrissian/"\nalias cwltool="/opt/conda/bin/cwltool --podman"\n. /home/jovyan/.bashrc\n\n#alias aws="aws --endpoint-url=http://localstack:4566"\n\n# >>> conda initialize >>>\n# !! Contents within this block are managed by \'conda init\' !!\n__conda_setup="$(\'/opt/conda/bin/conda\' \'shell.bash\' \'hook\' 2> /dev/null)"\nif [ $? -eq 0 ]; then\n eval "$__conda_setup"\nelse\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; then\n . "/opt/conda/etc/profile.d/conda.sh"\n else\n export PATH="/srv/conda/bin:$PATH"\n fi\nfi\nunset __conda_setup\n\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\n . "/opt/conda/etc/profile.d/mamba.sh"\nfi\n# <<< conda initialize <<<\n\na={{spawner.user.name}}\n\nalias aws="aws --endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"', persist=False), ConfigMap(name='bash-login', key='bash-login', mount_path='/workspace/.bash_login', default_mode=None, readonly=True, content='source /workspace/.bashrc\n', persist=False)], volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', size='50Gi', storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), persist=True)], pod_env_vars={'HOME': '/workspace'}, default_url='desktop', node_selector={}, role_bindings=None, image_pull_secrets=[], init_containers=[], manifests=None, env_from_config_maps=None, env_from_secrets=None, secret_mounts=None)] ("config: profiles=[Profile(id='profile_studio_coder1', groups=['group-a', " "'group-b'], definition=ProfileDefinition(display_name='Code Server Small', " "description=None, slug='ellip_studio_coder_slug_s', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, ' "mem_limit='8G', mem_guarantee=None, image='eoepca/pde-code-server:develop', " 'extra_resource_limits={}, extra_resource_guarantees={})), ' "config_maps=[ConfigMap(name='bash-rc', key='bash-rc', " "mount_path='/workspace/.bashrc', default_mode=None, readonly=True, " 'content=\'alias ll="ls -l"\\nalias calrissian="/opt/conda/bin/calrissian ' '--pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout ' '/calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix ' '/calrissian/tmp/ --outdir /calrissian/"\\nalias ' 'cwltool="/opt/conda/bin/cwltool --podman"\\n. ' '/home/jovyan/.bashrc\\n\\n#alias aws="aws ' '--endpoint-url=http://localstack:4566"\\n\\n# >>> conda initialize >>>\\n# ' "!! Contents within this block are managed by \\'conda init\\' " '!!\\n__conda_setup="$(\\\'/opt/conda/bin/conda\\\' \\\'shell.bash\\\' ' '\\\'hook\\\' 2> /dev/null)"\\nif [ $? -eq 0 ]; then\\n eval ' '"$__conda_setup"\\nelse\\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; ' 'then\\n . "/opt/conda/etc/profile.d/conda.sh"\\n else\\n ' 'export PATH="/srv/conda/bin:$PATH"\\n fi\\nfi\\nunset ' '__conda_setup\\n\\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\\n ' '. "/opt/conda/etc/profile.d/mamba.sh"\\nfi\\n# <<< conda initialize ' '<<<\\n\\na={{spawner.user.name}}\\n\\nalias aws="aws ' '--endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"\', ' "persist=False)], volumes=[Volume(name='calrissian-volume', " "claim_name='calrissian-claim', size='50Gi', " "storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], " "volume_mount=VolumeMount(name='calrissian-volume', " "mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', " "claim_name='workspace-claim', size='50Gi', " "storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': " "'/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, " 'image_pull_secrets=[], init_containers=[], manifests=None, ' 'env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_studio_coder2', groups=['group-a', 'group-b'], " "definition=ProfileDefinition(display_name='Code Server Medium', " "description=None, slug='ellip_studio_coder_slug_m', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=4, cpu_guarantee=None, ' "mem_limit='12G', mem_guarantee=None, image='eoepca/pde-code-server:develop', " 'extra_resource_limits={}, extra_resource_guarantees={})), ' "config_maps=[ConfigMap(name='bash-rc', key='bash-rc', " "mount_path='/workspace/.bashrc', default_mode=None, readonly=True, " 'content=\'alias ll="ls -l"\\nalias calrissian="/opt/conda/bin/calrissian ' '--pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout ' '/calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix ' '/calrissian/tmp/ --outdir /calrissian/"\\nalias ' 'cwltool="/opt/conda/bin/cwltool --podman"\\n. ' '/home/jovyan/.bashrc\\n\\n#alias aws="aws ' '--endpoint-url=http://localstack:4566"\\n\\n# >>> conda initialize >>>\\n# ' "!! Contents within this block are managed by \\'conda init\\' " '!!\\n__conda_setup="$(\\\'/opt/conda/bin/conda\\\' \\\'shell.bash\\\' ' '\\\'hook\\\' 2> /dev/null)"\\nif [ $? -eq 0 ]; then\\n eval ' '"$__conda_setup"\\nelse\\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; ' 'then\\n . "/opt/conda/etc/profile.d/conda.sh"\\n else\\n ' 'export PATH="/srv/conda/bin:$PATH"\\n fi\\nfi\\nunset ' '__conda_setup\\n\\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\\n ' '. "/opt/conda/etc/profile.d/mamba.sh"\\nfi\\n# <<< conda initialize ' '<<<\\n\\na={{spawner.user.name}}\\n\\nalias aws="aws ' '--endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"\', ' "persist=False)], volumes=[Volume(name='calrissian-volume', " "claim_name='calrissian-claim', size='50Gi', " "storage_class='managed-nfs-storage', access_modes=['ReadWriteMany'], " "volume_mount=VolumeMount(name='calrissian-volume', " "mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', " "claim_name='workspace-claim', size='50Gi', " "storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': " "'/workspace/.envs'}, default_url=None, node_selector={}, role_bindings=None, " 'image_pull_secrets=[], init_containers=[], manifests=None, ' 'env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_demo_init_script', groups=['group-a', 'group-b'], " "definition=ProfileDefinition(display_name='Coder demo init script', " "description='This profile is used to demonstrate the use of an init script', " "slug='eoepca_demo_init_script', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, ' "mem_limit='6G', mem_guarantee='4G', image='eoepca/pde-code-server:develop', " 'extra_resource_limits={}, extra_resource_guarantees={})), ' "config_maps=[ConfigMap(name='init', key='init', " "mount_path='/opt/init/.init.sh', default_mode='0660', readonly=True, " 'content="set -x\\n\\ncd /workspace\\n\\ngit clone ' "'https://github.com/eoap/mastering-app-package.git'\\n\\ncode-server " '--install-extension ms-python.python\\ncode-server --install-extension ' 'redhat.vscode-yaml\\ncode-server --install-extension ' 'sbg-rabix.benten-cwl\\ncode-server --install-extension ' 'ms-toolsai.jupyter\\n\\nln -s /workspace/.local/share/code-server/extensions ' '/workspace/extensions\\n\\nexit 0\\n", persist=False)], ' "volumes=[Volume(name='calrissian-volume', claim_name='calrissian-claim', " "size='50Gi', storage_class='managed-nfs-storage', " "access_modes=['ReadWriteMany'], " "volume_mount=VolumeMount(name='calrissian-volume', " "mount_path='/calrissian'), persist=False), Volume(name='workspace-volume', " "claim_name='workspace-claim', size='50Gi', " "storage_class='managed-nfs-storage', access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': " "'/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': " "'/workspace/.local', 'CODE_SERVER_WS': '/workspace/mastering-app-package'}, " 'default_url=None, node_selector={}, role_bindings=None, ' 'image_pull_secrets=[], ' "init_containers=[InitContainer(name='init-file-on-volume', " "image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh " "/opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', " "mount_path='/workspace'), InitContainerVolumeMount(name='init', " "mount_path='/opt/init/.init.sh', sub_path='init')])], manifests=None, " 'env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_jupyter_lab', groups=['group-c'], " "definition=ProfileDefinition(display_name='Jupyter Lab', " "description='Jupyter Lab with Python 3.11', slug='eoepca_jupyter_lab', " 'default=False, kubespawner_override=KubespawnerOverride(cpu_limit=2, ' "cpu_guarantee=1, mem_limit='6G', mem_guarantee='4G', " "image='jupyter/scipy-notebook', extra_resource_limits={}, " 'extra_resource_guarantees={})), config_maps=[], ' "volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', " "size='50Gi', storage_class='managed-nfs-storage', " "access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': " "'/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, " 'default_url=None, node_selector={}, role_bindings=None, ' 'image_pull_secrets=[], init_containers=[], manifests=None, ' 'env_from_config_maps=None, env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_jupyter_lab_2', groups=['group-c'], " "definition=ProfileDefinition(display_name='Jupyter Lab - profile 2', " "description='Jupyter Lab with Python 3.11 private image - demoes the use of " "an image pull secret', slug='eoepca_jupyter_lab_2', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, ' "mem_limit='6G', mem_guarantee='4G', image='eoepca/iat-jupyterlab:develop', " 'extra_resource_limits={}, extra_resource_guarantees={})), config_maps=[], ' "volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', " "size='50Gi', storage_class='managed-nfs-storage', " "access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'XDG_RUNTIME_DIR': " "'/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.config'}, " 'default_url=None, node_selector={}, role_bindings=None, ' "image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, " "data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], " 'init_containers=[], manifests=None, env_from_config_maps=None, ' 'env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_studio_coder_stac', groups=['group-a', 'group-b'], " "definition=ProfileDefinition(display_name='Understanding STAC for " "input/output data modelling', description='Understand the role of STAC in " "input/output data manifests in EO data processing workflows', " "slug='eoepca_coder_slug_stac', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=1, ' "mem_limit='6G', mem_guarantee='4G', " "image='docker.io/eoepca/pde-code-server@sha256:f57a3d5eabcae667e0db6e84a57b0c07c692c88f0fb5c8f6900ab8d5e38fcd40', " 'extra_resource_limits={}, extra_resource_guarantees={})), ' "config_maps=[ConfigMap(name='init', key='init', " "mount_path='/opt/init/.init.sh', default_mode=None, readonly=True, " "content='set -x \\n\\ncd /workspace\\n\\ngit clone " "\\'https://github.com/eoap/stac-eoap.git\\'\\n\\ncode-server " '--install-extension ms-python.python \\ncode-server --install-extension ' 'redhat.vscode-yaml\\ncode-server --install-extension ' 'sbg-rabix.benten-cwl\\ncode-server --install-extension ' 'ms-toolsai.jupyter\\n\\nln -s /workspace/.local/share/code-server/extensions ' '/workspace/extensions\\n\\nmkdir -p /workspace/User/\\n\\necho ' '\\\'{"workbench.colorTheme": "Visual Studio Dark"}\\\' > ' '/workspace/User/settings.json\\n\\npython -m venv /workspace/.venv\\nsource ' '/workspace/.venv/bin/activate\\n/workspace/.venv/bin/python -m pip install ' '--no-cache-dir stactools rasterio requests stac-asset click-logging tabulate ' 'tqdm pystac-client ipykernel loguru scikit-image rio_stac ' 'boto3==1.35.23\\n\\n/workspace/.venv/bin/python -m pip install --index-url ' 'https://test.pypi.org/simple cwl-wrapper\\n\\n/workspace/.venv/bin/python -m ' 'ipykernel install --user --name stac_env --display-name "Python ' '(STAC)"\\n\\nexport AWS_DEFAULT_REGION="us-east-1"\\nexport ' 'AWS_ACCESS_KEY_ID="test"\\nexport AWS_SECRET_ACCESS_KEY="test"\\naws s3 mb ' "s3://results --endpoint-url=http://localstack:4566\\n\\nexit 0', " "persist=False), ConfigMap(name='bash-rc', key='bash-rc', " "mount_path='/workspace/.bashrc', default_mode=None, readonly=True, " 'content=\'alias ll="ls -l"\\nalias calrissian="/opt/conda/bin/calrissian ' '--pod-nodeselectors /etc/calrissian/pod-node-selector.yml --stdout ' '/calrissian/results.json --max-ram 16G --max-cores "8" --tmp-outdir-prefix ' '/calrissian/tmp/ --outdir /calrissian/"\\nalias ' 'cwltool="/opt/conda/bin/cwltool --podman"\\n. ' '/home/jovyan/.bashrc\\n\\n#alias aws="aws ' '--endpoint-url=http://localstack:4566"\\n\\n# >>> conda initialize >>>\\n# ' "!! Contents within this block are managed by \\'conda init\\' " '!!\\n__conda_setup="$(\\\'/opt/conda/bin/conda\\\' \\\'shell.bash\\\' ' '\\\'hook\\\' 2> /dev/null)"\\nif [ $? -eq 0 ]; then\\n eval ' '"$__conda_setup"\\nelse\\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; ' 'then\\n . "/opt/conda/etc/profile.d/conda.sh"\\n else\\n ' 'export PATH="/srv/conda/bin:$PATH"\\n fi\\nfi\\nunset ' '__conda_setup\\n\\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\\n ' '. "/opt/conda/etc/profile.d/mamba.sh"\\nfi\\n# <<< conda initialize ' '<<<\\n\\na={{spawner.user.name}}\\n\\nalias aws="aws ' '--endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"\', ' "persist=False), ConfigMap(name='bash-login', key='bash-login', " "mount_path='/workspace/.bash_login', default_mode=None, readonly=True, " "content='source /workspace/.bashrc\\n', persist=False)], " "volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', " "size='50Gi', storage_class='managed-nfs-storage', " "access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace', 'CONDA_ENVS_PATH': " "'/workspace/.envs', 'CONDARC': '/workspace/.condarc', 'XDG_RUNTIME_DIR': " "'/workspace/.local', 'XDG_CONFIG_HOME': '/workspace/.local', " "'XDG_DATA_HOME': '/workspace/.local/share/', 'CWLTOOL_OPTIONS': '--podman', " "'CODE_SERVER_WS': '/workspace/stac-eoap', 'AWS_DEFAULT_REGION': 'us-east-1', " "'AWS_ACCESS_KEY_ID': 'test', 'AWS_SECRET_ACCESS_KEY': 'test'}, " 'default_url=None, node_selector={}, role_bindings=[], ' "image_pull_secrets=[ImagePullSecret(name='cr-config', persist=False, " "data='ewogICAgImF1dGhzIjogewogICAgICAgICJjci50ZXJyYWR1ZS5jb20iOiB7CiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCRlb2VwY2EtcGx1cy1ybyIsCiAgICAgICAgICAgICJwYXNzd29yZCI6ICJQMlE4TnkyZ0lHODhkZkxveXlLN05QVUZVbHJOekFZSiIsCiAgICAgICAgICAgICJlbWFpbCI6ICJlb2VwY2EtcGx1c0B0ZXJyYWR1ZS5jb20iLAogICAgICAgICAgICAiYXV0aCI6ICJjbTlpYjNRa1pXOWxjR05oTFhCc2RYTXRjbTg2VURKUk9FNTVNbWRKUnpnNFpHWk1iM2w1U3pkT1VGVkdWV3h5VG5wQldVbz0iCiAgICAgICAgfQogICAgfQp9')], " "init_containers=[InitContainer(name='init-file-on-volume', " "image='eoepca/pde-code-server:develop', command=['sh', '-c', 'sh " "/opt/init/.init.sh'], volume_mounts=[VolumeMount(name='workspace-volume', " "mount_path='/workspace'), InitContainerVolumeMount(name='init', " "mount_path='/opt/init/.init.sh', sub_path='init')])], " "manifests=[Manifest(name='manifests', key='manifests', " "content=[{'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': {'name': " "'localstack'}}, {'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': " "'Role', 'metadata': {'name': 'localstack'}, 'rules': [{'apiGroups': [''], " "'resources': ['pods'], 'verbs': ['*']}, {'apiGroups': [''], 'resources': " "['pods/log'], 'verbs': ['get']}, {'apiGroups': [''], 'resources': " "['pods/exec'], 'verbs': ['get', 'create']}, {'apiGroups': [''], 'resources': " "['services'], 'verbs': ['get', 'list']}]}, {'apiVersion': " "'rbac.authorization.k8s.io/v1', 'kind': 'RoleBinding', 'metadata': {'name': " "'localstack'}, 'subjects': [{'kind': 'ServiceAccount', 'name': " "'localstack'}], 'roleRef': {'kind': 'Role', 'name': 'localstack', " "'apiGroup': 'rbac.authorization.k8s.io'}}, {'apiVersion': 'v1', 'kind': " "'Service', 'metadata': {'name': 'localstack'}, 'spec': {'type': 'ClusterIP', " "'ports': [{'name': 'edge', 'port': 4566, 'targetPort': 4566}, {'name': " "'external-service-port-4510', 'port': 4510, 'targetPort': 'ext-svc-4510'}, " "{'name': 'external-service-port-4511', 'port': 4511, 'targetPort': " "'ext-svc-4511'}, {'name': 'external-service-port-4512', 'port': 4512, " "'targetPort': 'ext-svc-4512'}, {'name': 'external-service-port-4513', " "'port': 4513, 'targetPort': 'ext-svc-4513'}, {'name': " "'external-service-port-4514', 'port': 4514, 'targetPort': 'ext-svc-4514'}, " "{'name': 'external-service-port-4515', 'port': 4515, 'targetPort': " "'ext-svc-4515'}, {'name': 'external-service-port-4516', 'port': 4516, " "'targetPort': 'ext-svc-4516'}, {'name': 'external-service-port-4517', " "'port': 4517, 'targetPort': 'ext-svc-4517'}, {'name': " "'external-service-port-4518', 'port': 4518, 'targetPort': 'ext-svc-4518'}, " "{'name': 'external-service-port-4519', 'port': 4519, 'targetPort': " "'ext-svc-4519'}, {'name': 'external-service-port-4520', 'port': 4520, " "'targetPort': 'ext-svc-4520'}, {'name': 'external-service-port-4521', " "'port': 4521, 'targetPort': 'ext-svc-4521'}, {'name': " "'external-service-port-4522', 'port': 4522, 'targetPort': 'ext-svc-4522'}, " "{'name': 'external-service-port-4523', 'port': 4523, 'targetPort': " "'ext-svc-4523'}, {'name': 'external-service-port-4524', 'port': 4524, " "'targetPort': 'ext-svc-4524'}, {'name': 'external-service-port-4525', " "'port': 4525, 'targetPort': 'ext-svc-4525'}, {'name': " "'external-service-port-4526', 'port': 4526, 'targetPort': 'ext-svc-4526'}, " "{'name': 'external-service-port-4527', 'port': 4527, 'targetPort': " "'ext-svc-4527'}, {'name': 'external-service-port-4528', 'port': 4528, " "'targetPort': 'ext-svc-4528'}, {'name': 'external-service-port-4529', " "'port': 4529, 'targetPort': 'ext-svc-4529'}, {'name': " "'external-service-port-4530', 'port': 4530, 'targetPort': 'ext-svc-4530'}, " "{'name': 'external-service-port-4531', 'port': 4531, 'targetPort': " "'ext-svc-4531'}, {'name': 'external-service-port-4532', 'port': 4532, " "'targetPort': 'ext-svc-4532'}, {'name': 'external-service-port-4533', " "'port': 4533, 'targetPort': 'ext-svc-4533'}, {'name': " "'external-service-port-4534', 'port': 4534, 'targetPort': 'ext-svc-4534'}, " "{'name': 'external-service-port-4535', 'port': 4535, 'targetPort': " "'ext-svc-4535'}, {'name': 'external-service-port-4536', 'port': 4536, " "'targetPort': 'ext-svc-4536'}, {'name': 'external-service-port-4537', " "'port': 4537, 'targetPort': 'ext-svc-4537'}, {'name': " "'external-service-port-4538', 'port': 4538, 'targetPort': 'ext-svc-4538'}, " "{'name': 'external-service-port-4539', 'port': 4539, 'targetPort': " "'ext-svc-4539'}, {'name': 'external-service-port-4540', 'port': 4540, " "'targetPort': 'ext-svc-4540'}, {'name': 'external-service-port-4541', " "'port': 4541, 'targetPort': 'ext-svc-4541'}, {'name': " "'external-service-port-4542', 'port': 4542, 'targetPort': 'ext-svc-4542'}, " "{'name': 'external-service-port-4543', 'port': 4543, 'targetPort': " "'ext-svc-4543'}, {'name': 'external-service-port-4544', 'port': 4544, " "'targetPort': 'ext-svc-4544'}, {'name': 'external-service-port-4545', " "'port': 4545, 'targetPort': 'ext-svc-4545'}, {'name': " "'external-service-port-4546', 'port': 4546, 'targetPort': 'ext-svc-4546'}, " "{'name': 'external-service-port-4547', 'port': 4547, 'targetPort': " "'ext-svc-4547'}, {'name': 'external-service-port-4548', 'port': 4548, " "'targetPort': 'ext-svc-4548'}, {'name': 'external-service-port-4549', " "'port': 4549, 'targetPort': 'ext-svc-4549'}, {'name': " "'external-service-port-4550', 'port': 4550, 'targetPort': 'ext-svc-4550'}, " "{'name': 'external-service-port-4551', 'port': 4551, 'targetPort': " "'ext-svc-4551'}, {'name': 'external-service-port-4552', 'port': 4552, " "'targetPort': 'ext-svc-4552'}, {'name': 'external-service-port-4553', " "'port': 4553, 'targetPort': 'ext-svc-4553'}, {'name': " "'external-service-port-4554', 'port': 4554, 'targetPort': 'ext-svc-4554'}, " "{'name': 'external-service-port-4555', 'port': 4555, 'targetPort': " "'ext-svc-4555'}, {'name': 'external-service-port-4556', 'port': 4556, " "'targetPort': 'ext-svc-4556'}, {'name': 'external-service-port-4557', " "'port': 4557, 'targetPort': 'ext-svc-4557'}, {'name': " "'external-service-port-4558', 'port': 4558, 'targetPort': 'ext-svc-4558'}, " "{'name': 'external-service-port-4559', 'port': 4559, 'targetPort': " "'ext-svc-4559'}], 'selector': {'app.kubernetes.io/name': 'localstack', " "'app.kubernetes.io/instance': 'localstack'}}}, {'apiVersion': 'apps/v1', " "'kind': 'Deployment', 'metadata': {'name': 'localstack'}, 'spec': " "{'replicas': 1, 'strategy': {'type': 'RollingUpdate'}, 'selector': " "{'matchLabels': {'app.kubernetes.io/name': 'localstack', " "'app.kubernetes.io/instance': 'localstack'}}, 'template': {'metadata': " "{'labels': {'app': 'localstack-{{ spawner.user.name }}', " "'app.kubernetes.io/name': 'localstack', 'app.kubernetes.io/instance': " "'localstack'}}, 'spec': {'serviceAccountName': 'localstack', " "'securityContext': {}, 'containers': [{'name': 'localstack', " "'securityContext': {}, 'image': 'localstack/localstack:latest', " "'imagePullPolicy': 'IfNotPresent', 'ports': [{'name': 'edge', " "'containerPort': 4566, 'protocol': 'TCP'}, {'name': 'ext-svc-4510', " "'containerPort': 4510, 'protocol': 'TCP'}, {'name': 'ext-svc-4511', " "'containerPort': 4511, 'protocol': 'TCP'}, {'name': 'ext-svc-4512', " "'containerPort': 4512, 'protocol': 'TCP'}, {'name': 'ext-svc-4513', " "'containerPort': 4513, 'protocol': 'TCP'}, {'name': 'ext-svc-4514', " "'containerPort': 4514, 'protocol': 'TCP'}, {'name': 'ext-svc-4515', " "'containerPort': 4515, 'protocol': 'TCP'}, {'name': 'ext-svc-4516', " "'containerPort': 4516, 'protocol': 'TCP'}, {'name': 'ext-svc-4517', " "'containerPort': 4517, 'protocol': 'TCP'}, {'name': 'ext-svc-4518', " "'containerPort': 4518, 'protocol': 'TCP'}, {'name': 'ext-svc-4519', " "'containerPort': 4519, 'protocol': 'TCP'}, {'name': 'ext-svc-4520', " "'containerPort': 4520, 'protocol': 'TCP'}, {'name': 'ext-svc-4521', " "'containerPort': 4521, 'protocol': 'TCP'}, {'name': 'ext-svc-4522', " "'containerPort': 4522, 'protocol': 'TCP'}, {'name': 'ext-svc-4523', " "'containerPort': 4523, 'protocol': 'TCP'}, {'name': 'ext-svc-4524', " "'containerPort': 4524, 'protocol': 'TCP'}, {'name': 'ext-svc-4525', " "'containerPort': 4525, 'protocol': 'TCP'}, {'name': 'ext-svc-4526', " "'containerPort': 4526, 'protocol': 'TCP'}, {'name': 'ext-svc-4527', " "'containerPort': 4527, 'protocol': 'TCP'}, {'name': 'ext-svc-4528', " "'containerPort': 4528, 'protocol': 'TCP'}, {'name': 'ext-svc-4529', " "'containerPort': 4529, 'protocol': 'TCP'}, {'name': 'ext-svc-4530', " "'containerPort': 4530, 'protocol': 'TCP'}, {'name': 'ext-svc-4531', " "'containerPort': 4531, 'protocol': 'TCP'}, {'name': 'ext-svc-4532', " "'containerPort': 4532, 'protocol': 'TCP'}, {'name': 'ext-svc-4533', " "'containerPort': 4533, 'protocol': 'TCP'}, {'name': 'ext-svc-4534', " "'containerPort': 4534, 'protocol': 'TCP'}, {'name': 'ext-svc-4535', " "'containerPort': 4535, 'protocol': 'TCP'}, {'name': 'ext-svc-4536', " "'containerPort': 4536, 'protocol': 'TCP'}, {'name': 'ext-svc-4537', " "'containerPort': 4537, 'protocol': 'TCP'}, {'name': 'ext-svc-4538', " "'containerPort': 4538, 'protocol': 'TCP'}, {'name': 'ext-svc-4539', " "'containerPort': 4539, 'protocol': 'TCP'}, {'name': 'ext-svc-4540', " "'containerPort': 4540, 'protocol': 'TCP'}, {'name': 'ext-svc-4541', " "'containerPort': 4541, 'protocol': 'TCP'}, {'name': 'ext-svc-4542', " "'containerPort': 4542, 'protocol': 'TCP'}, {'name': 'ext-svc-4543', " "'containerPort': 4543, 'protocol': 'TCP'}, {'name': 'ext-svc-4544', " "'containerPort': 4544, 'protocol': 'TCP'}, {'name': 'ext-svc-4545', " "'containerPort': 4545, 'protocol': 'TCP'}, {'name': 'ext-svc-4546', " "'containerPort': 4546, 'protocol': 'TCP'}, {'name': 'ext-svc-4547', " "'containerPort': 4547, 'protocol': 'TCP'}, {'name': 'ext-svc-4548', " "'containerPort': 4548, 'protocol': 'TCP'}, {'name': 'ext-svc-4549', " "'containerPort': 4549, 'protocol': 'TCP'}, {'name': 'ext-svc-4550', " "'containerPort': 4550, 'protocol': 'TCP'}, {'name': 'ext-svc-4551', " "'containerPort': 4551, 'protocol': 'TCP'}, {'name': 'ext-svc-4552', " "'containerPort': 4552, 'protocol': 'TCP'}, {'name': 'ext-svc-4553', " "'containerPort': 4553, 'protocol': 'TCP'}, {'name': 'ext-svc-4554', " "'containerPort': 4554, 'protocol': 'TCP'}, {'name': 'ext-svc-4555', " "'containerPort': 4555, 'protocol': 'TCP'}, {'name': 'ext-svc-4556', " "'containerPort': 4556, 'protocol': 'TCP'}, {'name': 'ext-svc-4557', " "'containerPort': 4557, 'protocol': 'TCP'}, {'name': 'ext-svc-4558', " "'containerPort': 4558, 'protocol': 'TCP'}, {'name': 'ext-svc-4559', " "'containerPort': 4559, 'protocol': 'TCP'}], 'livenessProbe': " "{'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, " "'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': " "'/_localstack/health', 'port': 'edge'}}, 'readinessProbe': " "{'failureThreshold': 3, 'initialDelaySeconds': 0, 'periodSeconds': 10, " "'successThreshold': 1, 'timeoutSeconds': 1, 'httpGet': {'path': " "'/_localstack/health', 'port': 'edge'}}, 'resources': {}, 'env': [{'name': " "'DEBUG', 'value': '0'}, {'name': 'EXTERNAL_SERVICE_PORTS_START', 'value': " "'4510'}, {'name': 'EXTERNAL_SERVICE_PORTS_END', 'value': '4560'}, {'name': " "'LOCALSTACK_K8S_SERVICE_NAME', 'value': 'localstack'}, {'name': " "'LOCALSTACK_K8S_NAMESPACE', 'valueFrom': {'fieldRef': {'fieldPath': " "'metadata.namespace'}}}, {'name': 'LAMBDA_RUNTIME_EXECUTOR', 'value': " "'docker'}, {'name': 'LAMBDA_K8S_IMAGE_PREFIX', 'value': " "'localstack/lambda-'}, {'name': 'LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT', " "'value': '60'}, {'name': 'OVERRIDE_IN_DOCKER', 'value': '1'}]}], 'volumes': " "[]}}}}, {'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': {'name': " "'my-config'}, 'data': {'ENV_VAR1': 'value1', 'ENV_VAR2': 'value2'}}, " "{'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': 'my-secret'}, " "'type': 'Opaque', 'data': {'SECRET_KEY1': 'dmFsdWUx', 'SECRET_KEY2': " "'dmFsdWUy'}}, {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'name': " "'aws-credentials-{{ spawner.user.name }}'}, 'type': 'Opaque', 'data': " "{'credentials': " "'W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkPUFTSUFJT1NGT0ROTjdFWEFNUExFCmF3c19zZWNyZXRfYWNjZXNzX2tleT13SmFsclhVdG5GRU1JL0s3TURFTkcvYlB4UmZpQ1lFWEFNUExFS0VZCmF3c19zZXNzaW9uX3Rva2VuPUlRb0piM2pySmdCV05FTE5Hb2xHSkxFT3RTVEFOR1k0TFlPNUk0SzVOUlZFS1pPTkNTTk1HRlNUS1FNSUxXUjJPUzAwRklDRTExSlg='}}, " "{'apiVersion': 'external-secrets.io/v1beta1', 'kind': 'ExternalSecret', " "'metadata': {'name': 'data-by-name', 'namespace': 'jupyter-{{ " "spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', 'secretStoreRef': " "{'kind': 'ClusterSecretStore', 'name': 'k8s-secret-store'}, 'target': " "{'name': 'data-by-name', 'creationPolicy': 'Owner'}, 'data': [{'secretKey': " "'secret-value', 'remoteRef': {'key': 'secret-one', 'property': " "'the-key'}}]}}, {'apiVersion': 'external-secrets.io/v1beta1', 'kind': " "'ExternalSecret', 'metadata': {'name': 'eoepca-plus-secret-ro', 'namespace': " "'jupyter-{{ spawner.user.name }}'}, 'spec': {'refreshInterval': '15s', " "'secretStoreRef': {'kind': 'ClusterSecretStore', 'name': " "'k8s-secret-store'}, 'target': {'name': 'eoepca-plus-secret-ro', " "'creationPolicy': 'Owner'}, 'data': [{'secretKey': '.dockerconfigjson', " "'remoteRef': {'key': 'eoepca-plus-secret-ro', 'property': " "'.dockerconfigjson'}}]}}], persist=False)], env_from_config_maps=None, " 'env_from_secrets=None, secret_mounts=None), ' "Profile(id='profile_studio_desktop_qgis', groups=['group-a', 'group-b'], " "definition=ProfileDefinition(display_name='QGIS on a Remote Desktop', " "description='Spatial visualization and decision-making tools for everyone', " "slug='eoepca_desktop_qgis', default=False, " 'kubespawner_override=KubespawnerOverride(cpu_limit=2, cpu_guarantee=None, ' "mem_limit='2G', mem_guarantee=None, " "image='eoepca/iga-remote-desktop-qgis:1.1.3', extra_resource_limits={}, " "extra_resource_guarantees={})), config_maps=[ConfigMap(name='bash-rc', " "key='bash-rc', mount_path='/workspace/.bashrc', default_mode=None, " 'readonly=True, content=\'alias ll="ls -l"\\nalias ' 'calrissian="/opt/conda/bin/calrissian --pod-nodeselectors ' '/etc/calrissian/pod-node-selector.yml --stdout /calrissian/results.json ' '--max-ram 16G --max-cores "8" --tmp-outdir-prefix /calrissian/tmp/ --outdir ' '/calrissian/"\\nalias cwltool="/opt/conda/bin/cwltool --podman"\\n. ' '/home/jovyan/.bashrc\\n\\n#alias aws="aws ' '--endpoint-url=http://localstack:4566"\\n\\n# >>> conda initialize >>>\\n# ' "!! Contents within this block are managed by \\'conda init\\' " '!!\\n__conda_setup="$(\\\'/opt/conda/bin/conda\\\' \\\'shell.bash\\\' ' '\\\'hook\\\' 2> /dev/null)"\\nif [ $? -eq 0 ]; then\\n eval ' '"$__conda_setup"\\nelse\\n if [ -f "/opt/conda/etc/profile.d/conda.sh" ]; ' 'then\\n . "/opt/conda/etc/profile.d/conda.sh"\\n else\\n ' 'export PATH="/srv/conda/bin:$PATH"\\n fi\\nfi\\nunset ' '__conda_setup\\n\\nif [ -f "/opt/conda/etc/profile.d/mamba.sh" ]; then\\n ' '. "/opt/conda/etc/profile.d/mamba.sh"\\nfi\\n# <<< conda initialize ' '<<<\\n\\na={{spawner.user.name}}\\n\\nalias aws="aws ' '--endpoint-url=http://localstack-jupyter-{{spawner.user.name}}:4566"\', ' "persist=False), ConfigMap(name='bash-login', key='bash-login', " "mount_path='/workspace/.bash_login', default_mode=None, readonly=True, " "content='source /workspace/.bashrc\\n', persist=False)], " "volumes=[Volume(name='workspace-volume', claim_name='workspace-claim', " "size='50Gi', storage_class='managed-nfs-storage', " "access_modes=['ReadWriteOnce'], " "volume_mount=VolumeMount(name='workspace-volume', mount_path='/workspace'), " "persist=True)], pod_env_vars={'HOME': '/workspace'}, default_url='desktop', " 'node_selector={}, role_bindings=None, image_pull_secrets=[], ' 'init_containers=[], manifests=None, env_from_config_maps=None, ' 'env_from_secrets=None, secret_mounts=None)]')