From ecf67cefb475ad58651cf5250acb7291937cef5e Mon Sep 17 00:00:00 2001 From: Taylor Mutch Date: Fri, 10 Jul 2026 11:34:03 -0700 Subject: [PATCH] fix(helm): propagate supervisor image overrides Signed-off-by: Taylor Mutch --- architecture/build.md | 3 ++ deploy/helm/openshell/README.md | 4 +-- deploy/helm/openshell/templates/_helpers.tpl | 23 ++++++++++-- .../openshell/templates/gateway-config.yaml | 2 ++ .../openshell/tests/gateway_config_test.yaml | 36 +++++++++++++++++++ deploy/helm/openshell/values.yaml | 10 +++--- docs/reference/sandbox-compute-drivers.mdx | 2 +- 7 files changed, 69 insertions(+), 11 deletions(-) diff --git a/architecture/build.md b/architecture/build.md index a3cb2e25fb..5537e63619 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -98,6 +98,9 @@ Runtime layout: Gateway image builds bake the corresponding supervisor image tag into the gateway binary so Docker sandboxes do not depend on `:latest` by default. +The Helm chart omits the supervisor image from gateway configuration unless an +operator supplies a repository or tag override, preserving that build-time +pairing for Kubernetes sandboxes as well. Package formulas also pin Docker supervisor extraction to the matching release image tag so standalone gateway binaries do not infer image tags from package versions. diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index 6bc459567b..4a22d640f5 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -237,8 +237,8 @@ add `ci/values-spire.yaml` to the OpenShell release values files. | serviceAccount.create | bool | `true` | Create a service account for the gateway. | | serviceAccount.name | string | `""` | Existing service account name to use when serviceAccount.create is false. | | supervisor.image.pullPolicy | string | `""` | Supervisor image pull policy. Defaults to the gateway image pull policy when empty. | -| supervisor.image.repository | string | `"ghcr.io/nvidia/openshell/supervisor"` | Supervisor image repository. | -| supervisor.image.tag | string | `""` | Supervisor image tag. Defaults to the chart appVersion when empty. | +| supervisor.image.repository | string | `"ghcr.io/nvidia/openshell/supervisor"` | Supervisor image repository. Changing it uses the effective gateway image tag unless tag is also set. | +| supervisor.image.tag | string | `""` | Supervisor image tag override. Empty uses the version pinned into the gateway unless repository is changed. | | supervisor.sideloadMethod | string | `""` | How the supervisor binary is delivered into sandbox pods. Empty (default) = auto-detect from cluster version: K8s >= v1.35 -> "image-volume" (ImageVolume enabled by default; GA in v1.36) K8s < v1.35 -> "init-container" (copies via init container + emptyDir) On K8s v1.33-v1.34 with the ImageVolume feature gate manually enabled, set this to "image-volume" explicitly. | | supervisor.topology | string | `"combined"` | Supervisor pod topology for Kubernetes sandboxes. "combined" runs networking and process supervision in the agent container. | | tolerations | list | `[]` | Tolerations for the gateway pod. | diff --git a/deploy/helm/openshell/templates/_helpers.tpl b/deploy/helm/openshell/templates/_helpers.tpl index 5872dc4043..1b4598088f 100644 --- a/deploy/helm/openshell/templates/_helpers.tpl +++ b/deploy/helm/openshell/templates/_helpers.tpl @@ -78,12 +78,29 @@ so a released chart automatically pulls the matching image without extra overrid {{- printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion) }} {{- end }} +{{/* Official supervisor repository used by the gateway's built-in default. */}} +{{- define "openshell.defaultSupervisorRepository" -}} +ghcr.io/nvidia/openshell/supervisor +{{- end }} + +{{/* +Whether Helm must propagate a supervisor image override into gateway.toml. +The chart's documented repository and empty tag are the gateway-owned default. +*/}} +{{- define "openshell.supervisorImageOverrideEnabled" -}} +{{- $defaultRepository := include "openshell.defaultSupervisorRepository" . -}} +{{- $repository := .Values.supervisor.image.repository | default $defaultRepository -}} +{{- if or (ne $repository $defaultRepository) .Values.supervisor.image.tag -}}true{{- end -}} +{{- end }} + {{/* -Supervisor image reference. Same appVersion fallback as openshell.image so -the supervisor and gateway images stay in sync across releases. +Supervisor image override. A tag-only override uses the official repository; +a repository-only override uses the effective gateway image tag. */}} {{- define "openshell.supervisorImage" -}} -{{- printf "%s:%s" .Values.supervisor.image.repository (.Values.supervisor.image.tag | default .Chart.AppVersion) }} +{{- $repository := .Values.supervisor.image.repository | default (include "openshell.defaultSupervisorRepository" .) -}} +{{- $tag := .Values.supervisor.image.tag | default .Values.image.tag | default .Chart.AppVersion -}} +{{- printf "%s:%s" $repository $tag }} {{- end }} {{/* diff --git a/deploy/helm/openshell/templates/gateway-config.yaml b/deploy/helm/openshell/templates/gateway-config.yaml index 0e75a311f0..55beac7a19 100644 --- a/deploy/helm/openshell/templates/gateway-config.yaml +++ b/deploy/helm/openshell/templates/gateway-config.yaml @@ -34,7 +34,9 @@ data: log_level = {{ .Values.server.logLevel | quote }} sandbox_namespace = {{ include "openshell.sandboxNamespace" . | quote }} default_image = {{ .Values.server.sandboxImage | quote }} + {{- if include "openshell.supervisorImageOverrideEnabled" . }} supervisor_image = {{ include "openshell.supervisorImage" . | quote }} + {{- end }} {{- if .Values.server.hostGatewayIP }} host_gateway_ip = {{ .Values.server.hostGatewayIP | quote }} {{- end }} diff --git a/deploy/helm/openshell/tests/gateway_config_test.yaml b/deploy/helm/openshell/tests/gateway_config_test.yaml index 50051e0036..797182558e 100644 --- a/deploy/helm/openshell/tests/gateway_config_test.yaml +++ b/deploy/helm/openshell/tests/gateway_config_test.yaml @@ -90,6 +90,42 @@ tests: path: data["gateway.toml"] pattern: '(?ms)\[openshell\.drivers\.kubernetes\].*?supervisor_topology\s*=\s*"combined"' + - it: uses the gateway built-in supervisor image by default + template: templates/gateway-config.yaml + asserts: + - notMatchRegex: + path: data["gateway.toml"] + pattern: 'supervisor_image\s*=' + + - it: renders a supervisor tag override with the official repository + template: templates/gateway-config.yaml + set: + supervisor.image.tag: 1.2.3 + asserts: + - matchRegex: + path: data["gateway.toml"] + pattern: 'supervisor_image\s*=\s*"ghcr\.io/nvidia/openshell/supervisor:1\.2\.3"' + + - it: renders a supervisor repository override with the effective gateway tag + template: templates/gateway-config.yaml + set: + image.tag: gateway-build + supervisor.image.repository: registry.example.com/openshell/supervisor + asserts: + - matchRegex: + path: data["gateway.toml"] + pattern: 'supervisor_image\s*=\s*"registry\.example\.com/openshell/supervisor:gateway-build"' + + - it: renders complete supervisor repository and tag overrides + template: templates/gateway-config.yaml + set: + supervisor.image.repository: registry.example.com/openshell/supervisor + supervisor.image.tag: supervisor-build + asserts: + - matchRegex: + path: data["gateway.toml"] + pattern: 'supervisor_image\s*=\s*"registry\.example\.com/openshell/supervisor:supervisor-build"' + - it: renders explicit combined supervisor topology under [openshell.drivers.kubernetes] template: templates/gateway-config.yaml set: diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index fd73dd0713..f36b533d13 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -26,16 +26,16 @@ image: # -- Gateway image tag. Defaults to the chart appVersion when empty. tag: "" -# Supervisor image - provides the openshell-sandbox binary injected into sandbox -# pods. tag defaults to appVersion (same as the gateway image) so both stay in -# sync when the chart is released. +# Supervisor image for the openshell-sandbox binary injected into sandbox pods. +# The default repository and empty tag use the version-pinned image built into +# the gateway. Changing the repository or setting a tag enables a Helm override. supervisor: image: - # -- Supervisor image repository. + # -- Supervisor image repository. Changing it uses the effective gateway image tag unless tag is also set. repository: ghcr.io/nvidia/openshell/supervisor # -- Supervisor image pull policy. Defaults to the gateway image pull policy when empty. pullPolicy: "" - # -- Supervisor image tag. Defaults to the chart appVersion when empty. + # -- Supervisor image tag override. Empty uses the version pinned into the gateway unless repository is changed. tag: "" # -- How the supervisor binary is delivered into sandbox pods. # Empty (default) = auto-detect from cluster version: diff --git a/docs/reference/sandbox-compute-drivers.mdx b/docs/reference/sandbox-compute-drivers.mdx index 714ddd6c33..e5cb8e254d 100644 --- a/docs/reference/sandbox-compute-drivers.mdx +++ b/docs/reference/sandbox-compute-drivers.mdx @@ -303,7 +303,7 @@ For maintainer-level implementation details, refer to the [Kubernetes driver REA | `image_pull_secrets` | `server.sandboxImagePullSecrets` | Attach Kubernetes image pull secrets to sandbox pods. Referenced Secrets must exist in the sandbox namespace. | | `grpc_endpoint` | `server.grpcEndpoint` | Set the gateway callback endpoint reachable from sandbox pods. | | `client_tls_secret_name` | `server.tls.clientTlsSecretName` | Mount sandbox client TLS materials from a Kubernetes secret. | -| `supervisor_image` | `supervisor.image.repository` / `supervisor.image.tag` | Set the supervisor image that provides the `openshell-sandbox` binary. | +| `supervisor_image` | `supervisor.image.repository` / `supervisor.image.tag` | Override the supervisor image that provides the `openshell-sandbox` binary. The default repository with an empty tag uses the version-pinned image built into the gateway. Changing the repository uses the effective gateway image tag, while setting a tag pins that version explicitly. | | `supervisor_image_pull_policy` | `supervisor.image.pullPolicy` | Set the Kubernetes image pull policy for the supervisor image. | | `supervisor_sideload_method` | `supervisor.sideloadMethod` | How the supervisor binary is delivered into sandbox pods. Leave empty to auto-detect from cluster version. Set to `image-volume` to mount the supervisor OCI image directly as a volume (requires Kubernetes 1.33+ with the ImageVolume feature gate; GA in 1.36), or `init-container` to copy it through an init container on older clusters. | | `app_armor_profile` | `server.appArmorProfile` | Set the sandbox agent container's AppArmor profile. Helm defaults this to `Unconfined` so AppArmor-enabled nodes do not block supervisor network namespace setup. Set the Helm value to an empty string to omit the field, or use `RuntimeDefault` or `Localhost/` for operator-managed profiles. |