Skip to content

Fix missing SSH port and namespace in Welcome notebook on Kubeflow (#133)#149

Open
SannaPersson wants to merge 8 commits into
minnelab:masterfrom
kthcloud:fix/issue-133-kubeflow-welcome-env
Open

Fix missing SSH port and namespace in Welcome notebook on Kubeflow (#133)#149
SannaPersson wants to merge 8 commits into
minnelab:masterfrom
kthcloud:fix/issue-133-kubeflow-welcome-env

Conversation

@SannaPersson

Copy link
Copy Markdown
Contributor

Summary

Fixes #133. The Welcome notebook in MAIA-Workspace only populated SSH port / namespace when JupyterHub injected SSH_PORT_<user>, NAMESPACE, and an overridden HOSTNAME via extraEnv. Pods spawned by Kubeflow's Notebook Controller showed N/A for the SSH command and had no namespace information.

  • New MAIA.workspace_env.discover_workspace_env() resolves the five workspace fields with a Kubeflow fallback path: NB_PREFIX → user, /var/run/secrets/.../namespace → namespace, in-cluster Service lookup → SSH port and hostname.
  • New chart value sshHostname on maia-namespace-base (default "") is rendered as a maia.kthcloud.io/ssh-hostname annotation on each per-user SSH Service. MAIA_install_project_toolkit already runs create_maia_namespace_values, which now passes cluster_config.ssh_hostname through.
  • The Welcome notebook calls the helper instead of reading env vars inline. JupyterHub behaviour is unchanged because env vars are still resolved first; the K8s API is only queried when something is missing. A new markdown cell shows the namespace.
  • Chart bumped to 1.7.2.

Test plan

  • python -m pytest tests/test_workspace_env.py -v — 14 tests covering JupyterHub-only path, Kubeflow fallback, NodePort vs ClusterIP, unrelated-service rejection, all-missing → N/A, missing hostname annotation, K8s API failure, factory exception, env-var precedence over service lookup, JupyterHub-encoded usernames, NB_PREFIX trailing slash, namespace file stripping.
  • helm template of maia-namespace-base with sshHostname=ssh.example.com and unset — annotation appears only when the value is set.
  • python -c "import json; json.load(open('docker/MAIA-Workspace/Welcome.ipynb'))" — notebook is valid JSON.
  • Smoke test on a real Kubeflow-spawned MAIA workspace: open Welcome.ipynb, run the env cell, confirm namespace and ssh maia-user@<host> -p <port> populate correctly.
  • Smoke test on a JupyterHub-spawned MAIA workspace: confirm no regression.

Notes

  • RBAC: the Kubeflow notebook ServiceAccount needs get/list services in its own namespace. The default default-editor role used by Kubeflow Profiles already grants this, but worth confirming on the target cluster.
  • kubernetes is already in setup.cfg install_requires, so the helper imports work in the workspace image without a Dockerfile change.
  • The pod-name-vs-SSH-host distinction is handled by trusting HOSTNAME only when JUPYTERHUB_USER is also set; otherwise the helper reads the SSH host from the new Service annotation.

SimoneBendazzoli93 and others added 6 commits October 14, 2025 12:22
…ab, add new environment variables for dashboard, and clean up commented code for discord signup URL.
Removed nvflare_dashboards from return statement in kubernetes_utils.py.
…innelab#133)

The Welcome notebook only worked when JupyterHub injected SSH_PORT_<user>,
NAMESPACE, and an overridden HOSTNAME via extraEnv. Pods spawned by Kubeflow
saw "N/A" for the SSH command and had no namespace info at all.

Add MAIA.workspace_env.discover_workspace_env() with a Kubeflow fallback
path: NB_PREFIX -> user, the service-account namespace file -> namespace,
and an in-cluster Service lookup -> SSH port + hostname (read from a new
maia.kthcloud.io/ssh-hostname annotation set by maia-namespace-base).

The Welcome notebook now calls the helper, so JupyterHub behaviour is
unchanged while Kubeflow users see correct values.
Copilot AI review requested due to automatic review settings May 2, 2026 09:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the Welcome notebook’s missing SSH command/namespace when MAIA workspaces are spawned by Kubeflow (where JupyterHub extraEnv variables aren’t injected), by adding a Python helper that can fall back to in-cluster Kubernetes lookups and by annotating per-user SSH Services with a discoverable hostname.

Changes:

  • Add MAIA.workspace_env.discover_workspace_env() with Kubeflow fallback resolution (NB_PREFIX, serviceaccount namespace file, Service lookup for SSH port/hostname).
  • Update docker/MAIA-Workspace/Welcome.ipynb to use the helper and display the namespace.
  • Extend the maia-namespace-base Helm chart with sshHostname value rendered as a Service annotation; bump chart to 1.7.2.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
MAIA/workspace_env.py New env discovery helper with optional Kubernetes Service-based fallback for Kubeflow-spawned notebooks.
tests/test_workspace_env.py Adds unit tests covering env precedence, Kubeflow fallback behavior, and failure modes.
docker/MAIA-Workspace/Welcome.ipynb Switches env cell to call discover_workspace_env() and adds a namespace display cell.
charts/maia-namespace-base/values.yaml Adds new sshHostname chart value (default empty).
charts/maia-namespace-base/templates/ssh_service.yaml Emits maia.kthcloud.io/ssh-hostname annotation on SSH Services when configured.
charts/maia-namespace-base/Chart.yaml Bumps chart/app version to 1.7.2.
MAIA/maia_admin.py Passes ssh_hostname through into chart values as sshHostname.
MAIA/kubernetes_utils.py Adds a defensive labels existence check; modifies get_namespace_details return line.

Comment thread MAIA/kubernetes_utils.py
maia_workspace_apps["xnat"] = "N/A"

return maia_workspace_apps, remote_desktop_dict, ssh_ports, monai_models, orthanc_list, deployed_clusters, nvflare_dashboards
return maia_workspace_apps, remote_desktop_dict, ssh_ports, monai_models, orthanc_list, deployed_clusters #, nvflare_dashboards

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep returning the nvflare_dashboards and simply update the docstrings

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment thread MAIA/workspace_env.py Outdated
Comment thread MAIA/workspace_env.py
Comment on lines +45 to +47
try:
services = core_v1.list_namespaced_service(namespace).items
except Exception:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, implement that

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Simone Bendazzoli <simonebendazzoli93@gmail.com>
Comment thread MAIA/kubernetes_utils.py
maia_workspace_apps["xnat"] = "N/A"

return maia_workspace_apps, remote_desktop_dict, ssh_ports, monai_models, orthanc_list, deployed_clusters, nvflare_dashboards
return maia_workspace_apps, remote_desktop_dict, ssh_ports, monai_models, orthanc_list, deployed_clusters #, nvflare_dashboards

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep returning the nvflare_dashboards and simply update the docstrings

Comment thread MAIA/workspace_env.py
Comment on lines +45 to +47
try:
services = core_v1.list_namespaced_service(namespace).items
except Exception:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, implement that

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maia-namespace-base chart is no longer used, so this needs to be moved to the maia-namespace chart

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For from MAIA.workspace_env import discover_workspace_env to work, the notebook needs either to install the maia-toolkit package or to have the Python file available in the environment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signed-off-by: Simone Bendazzoli <simben@kth.se>
@SimoneBendazzoli93

Copy link
Copy Markdown
Collaborator

/format

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix missing SSH Port and Namespace Info in Welcome notebook for Jupyter Servers created via Kubeflow

3 participants