From f960874038aabbc4319fb72cf0d247ccb38a05ae Mon Sep 17 00:00:00 2001 From: Edelenyi Date: Thu, 13 Aug 2026 17:34:12 +1000 Subject: [PATCH 1/5] feat(ontoserver): expose StatefulSet podManagementPolicy podManagementPolicy was hardcoded to Parallel. Under Parallel the controller does not wait for a replacement pod to be Ready before replacing the next one, so a rolling update on a multi-replica install can terminate every pod within seconds and leave the Service with no ready endpoint until the first replacement passes its readiness probe. A PodDisruptionBudget does not help: it only gates the Eviction API, not StatefulSet-driven pod replacement. The default stays Parallel, so existing installs render identically and keep the fast parallel scale-up. Operators who prefer availability during rolling updates over startup speed can now set OrderedReady. --- charts/ontoserver/templates/statefulset.yaml | 2 +- charts/ontoserver/tests/statefulset_test.yaml | 9 +++++++++ charts/ontoserver/values.schema.json | 8 ++++++++ charts/ontoserver/values.yaml | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/charts/ontoserver/templates/statefulset.yaml b/charts/ontoserver/templates/statefulset.yaml index 86722c7..61a4b6c 100644 --- a/charts/ontoserver/templates/statefulset.yaml +++ b/charts/ontoserver/templates/statefulset.yaml @@ -26,7 +26,7 @@ spec: {{- fail (printf "ontoserver.deployment.type must be one of the following: 'single', 'scaled'. Got: '%s'" .Values.ontoserver.deployment.type) }} {{- end }} replicas: {{ .Values.ontoserver.deployment.replicas }} - podManagementPolicy: Parallel + podManagementPolicy: {{ .Values.ontoserver.deployment.podManagementPolicy }} serviceName: {{ .Release.Name }}-ontoserver-headless selector: matchLabels: diff --git a/charts/ontoserver/tests/statefulset_test.yaml b/charts/ontoserver/tests/statefulset_test.yaml index 3e0f4c3..8b08f1e 100644 --- a/charts/ontoserver/tests/statefulset_test.yaml +++ b/charts/ontoserver/tests/statefulset_test.yaml @@ -25,6 +25,15 @@ tests: path: spec.podManagementPolicy value: Parallel + - it: honours a podManagementPolicy override + set: + ontoserver.deployment.kind: StatefulSet + ontoserver.deployment.podManagementPolicy: OrderedReady + asserts: + - equal: + path: spec.podManagementPolicy + value: OrderedReady + - it: sets serviceName to headless service set: ontoserver.deployment.kind: StatefulSet diff --git a/charts/ontoserver/values.schema.json b/charts/ontoserver/values.schema.json index 87a2d19..7fbae9a 100644 --- a/charts/ontoserver/values.schema.json +++ b/charts/ontoserver/values.schema.json @@ -53,6 +53,14 @@ "type": "integer", "minimum": 0 }, + "podManagementPolicy": { + "type": "string", + "enum": [ + "Parallel", + "OrderedReady" + ], + "description": "StatefulSet pod management policy. Parallel does not wait for Ready before replacing the next pod; OrderedReady does. Immutable on a live StatefulSet." + }, "clusterName": { "type": "string" }, diff --git a/charts/ontoserver/values.yaml b/charts/ontoserver/values.yaml index e618e5c..5151010 100644 --- a/charts/ontoserver/values.yaml +++ b/charts/ontoserver/values.yaml @@ -28,6 +28,8 @@ ontoserver: allowScaledReadWrite: false ## @param ontoserver.deployment.replicas Number of replicas - min 2 for scaled deployment - can be set to 0 replicas: 1 + ## @param ontoserver.deployment.podManagementPolicy StatefulSet pod management policy (Parallel or OrderedReady); ignored when kind is Deployment. Parallel starts and replaces pods without waiting for Ready, so a multi-replica rolling update can leave the Service with no ready endpoint; OrderedReady waits for each pod to become Ready first. Immutable on a live StatefulSet - see the README for the --cascade=orphan recreate. + podManagementPolicy: Parallel ## @param ontoserver.deployment.clusterName Cluster name for auto-discovery in scaled deployments (overrides the default "ontoserver" set in application.properties); ignored for single deployments clusterName: "" ## @param ontoserver.deployment.annotations Deployment/Statefulset manifest annotations From 46a37e21ba3faf09355c3ac1479712bbfd586631 Mon Sep 17 00:00:00 2001 From: Edelenyi Date: Thu, 13 Aug 2026 17:35:02 +1000 Subject: [PATCH 2/5] feat(ontoserver): expose OTel metrics and logs exporters OTEL_METRICS_EXPORTER and OTEL_LOGS_EXPORTER were hardcoded to "none" in the Instrumentation resource, with no way to override them from values. That leaves metricsExporter: otlp - the usual way to get JVM heap and GC metrics off the Java agent - unreachable for chart users; unlike most other agent settings it cannot be worked around from outside the chart. Both default to "none", so an existing install renders unchanged. --- .../opentelemetry-instrumentation.yaml | 4 +-- .../tests/optional_features_test.yaml | 30 +++++++++++++++++++ charts/ontoserver/values.schema.json | 8 +++++ charts/ontoserver/values.yaml | 6 +++- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/charts/ontoserver/templates/opentelemetry-instrumentation.yaml b/charts/ontoserver/templates/opentelemetry-instrumentation.yaml index 1580c42..aaf153c 100644 --- a/charts/ontoserver/templates/opentelemetry-instrumentation.yaml +++ b/charts/ontoserver/templates/opentelemetry-instrumentation.yaml @@ -20,9 +20,9 @@ spec: value: {{ .Values.ontoserver.opentelemetry.instrumentation.exporter.endpoint | quote }} {{- end }} - name: OTEL_METRICS_EXPORTER - value: "none" + value: {{ .Values.ontoserver.opentelemetry.instrumentation.metricsExporter | quote }} - name: OTEL_LOGS_EXPORTER - value: "none" + value: {{ .Values.ontoserver.opentelemetry.instrumentation.logsExporter | quote }} - name: OTEL_PROPAGATORS value: {{ .Values.ontoserver.opentelemetry.instrumentation.propagators | quote }} - name: OTEL_INSTRUMENTATION_COMMON_ENDUSER_ENABLED diff --git a/charts/ontoserver/tests/optional_features_test.yaml b/charts/ontoserver/tests/optional_features_test.yaml index fbd2ce9..69901f7 100644 --- a/charts/ontoserver/tests/optional_features_test.yaml +++ b/charts/ontoserver/tests/optional_features_test.yaml @@ -64,6 +64,36 @@ tests: - equal: path: spec.exporter.endpoint value: "http://jaeger:4317" + - contains: + path: spec.java.env + content: + name: OTEL_METRICS_EXPORTER + value: "none" + - contains: + path: spec.java.env + content: + name: OTEL_LOGS_EXPORTER + value: "none" + + - it: honours metricsExporter and logsExporter overrides + templates: + - templates/opentelemetry-instrumentation.yaml + set: + ontoserver.opentelemetry.instrumentation.enabled: true + ontoserver.opentelemetry.instrumentation.exporter.endpoint: "http://collector:4317" + ontoserver.opentelemetry.instrumentation.metricsExporter: otlp + ontoserver.opentelemetry.instrumentation.logsExporter: otlp + asserts: + - contains: + path: spec.java.env + content: + name: OTEL_METRICS_EXPORTER + value: "otlp" + - contains: + path: spec.java.env + content: + name: OTEL_LOGS_EXPORTER + value: "otlp" - it: renders no Envoy policies by default templates: diff --git a/charts/ontoserver/values.schema.json b/charts/ontoserver/values.schema.json index 7fbae9a..11a0609 100644 --- a/charts/ontoserver/values.schema.json +++ b/charts/ontoserver/values.schema.json @@ -661,6 +661,14 @@ "excludedClasses": { "type": "string" }, + "metricsExporter": { + "type": "string", + "description": "OTEL_METRICS_EXPORTER for the Java agent (e.g. otlp, prometheus, none)." + }, + "logsExporter": { + "type": "string", + "description": "OTEL_LOGS_EXPORTER for the Java agent (e.g. otlp, none)." + }, "exporter": { "type": "object", "properties": { diff --git a/charts/ontoserver/values.yaml b/charts/ontoserver/values.yaml index 5151010..ec963bb 100644 --- a/charts/ontoserver/values.yaml +++ b/charts/ontoserver/values.yaml @@ -320,8 +320,12 @@ ontoserver: propagators: "tracecontext,baggage,b3multi" ## @param ontoserver.opentelemetry.instrumentation.excludedClasses Classes to exclude from instrumentation excludedClasses: "ca.uhn.fhir.*Interceptor*" + ## @param ontoserver.opentelemetry.instrumentation.metricsExporter OTEL_METRICS_EXPORTER for the Java agent (e.g. otlp for JVM heap and GC metrics, or none to disable) + metricsExporter: "none" + ## @param ontoserver.opentelemetry.instrumentation.logsExporter OTEL_LOGS_EXPORTER for the Java agent (e.g. otlp, or none to disable) + logsExporter: "none" exporter: - ## @param ontoserver.opentelemetry.instrumentation.exporter.type Exporter type (zipkin, otlp, etc.) + ## @param ontoserver.opentelemetry.instrumentation.exporter.type Trace exporter type (OTEL_TRACES_EXPORTER - zipkin, otlp, etc.) type: zipkin ## @param ontoserver.opentelemetry.instrumentation.exporter.endpoint Exporter endpoint URL (required when enabled) endpoint: "" From d76637af84f55a396b62df90157d31c5745f189d Mon Sep 17 00:00:00 2001 From: Edelenyi Date: Thu, 13 Aug 2026 17:35:13 +1000 Subject: [PATCH 3/5] fix(ontoserver): restore empty serverPort default 0.4.0 changed the serverPort default from "" to "8080" so the local port-forward instructions would produce working URLs. The side effect is that every install that never sets serverPort - including the cloud examples served on 80/443 - publishes host:8080 in its CapabilityStatement, ontoserver.fhir.base and canonical URLs. Nothing errors, so it is easy to miss. Revert the default to "" and instead set serverPort: "8080" explicitly in the two local examples whose documented access path is a 8080:80 port-forward. The k3d examples already set it. Installs on 0.4.0/0.4.1 that relied on the inherited default must now set serverPort: "8080" themselves. --- .../ontoserver/examples/local/single-ro.yaml | 3 ++ .../ontoserver/examples/local/single-rw.yaml | 3 ++ charts/ontoserver/tests/deployment_test.yaml | 28 +++++++++++++++++++ charts/ontoserver/values.yaml | 2 +- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/charts/ontoserver/examples/local/single-ro.yaml b/charts/ontoserver/examples/local/single-ro.yaml index 632f13e..3a1b4b4 100644 --- a/charts/ontoserver/examples/local/single-ro.yaml +++ b/charts/ontoserver/examples/local/single-ro.yaml @@ -20,6 +20,9 @@ ontoserver: serverName: localhost + # Matches the port-forward above, so the CapabilityStatement and canonical URLs + # advertise http://localhost:8080/... Remove this when serving on port 80/443. + serverPort: "8080" hostNames: - localhost diff --git a/charts/ontoserver/examples/local/single-rw.yaml b/charts/ontoserver/examples/local/single-rw.yaml index f8c5867..d262c08 100644 --- a/charts/ontoserver/examples/local/single-rw.yaml +++ b/charts/ontoserver/examples/local/single-rw.yaml @@ -22,6 +22,9 @@ ontoserver: serverName: localhost + # Matches the port-forward above, so the CapabilityStatement and canonical URLs + # advertise http://localhost:8080/... Remove this when serving on port 80/443. + serverPort: "8080" hostNames: - localhost diff --git a/charts/ontoserver/tests/deployment_test.yaml b/charts/ontoserver/tests/deployment_test.yaml index cf3410b..1442c5d 100644 --- a/charts/ontoserver/tests/deployment_test.yaml +++ b/charts/ontoserver/tests/deployment_test.yaml @@ -15,6 +15,34 @@ tests: path: spec.replicas value: 1 + - it: omits a port from the published base URLs by default + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ontoserver.fhir.base + value: http://localhost/fhir + - contains: + path: spec.template.spec.containers[0].env + content: + name: ontoserver.synd.base + value: http://localhost/synd + + - it: appends serverPort to the published base URLs when set + set: + ontoserver.serverPort: "8080" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ontoserver.fhir.base + value: http://localhost:8080/fhir + - contains: + path: spec.template.spec.containers[0].env + content: + name: ontoserver.formats.html.base + value: http://localhost:8080/static + - it: sets replicas from values set: ontoserver.deployment.replicas: 0 diff --git a/charts/ontoserver/values.yaml b/charts/ontoserver/values.yaml index ec963bb..dea1f75 100644 --- a/charts/ontoserver/values.yaml +++ b/charts/ontoserver/values.yaml @@ -201,7 +201,7 @@ ontoserver: ## @param ontoserver.serverName Server hostname - must match a hostName at ontoserver.hostNames serverName: localhost ## @param ontoserver.serverPort Non-standard port exposed to clients (e.g. 8080 when port-forwarding or k3d maps 8080:80). Leave empty for standard ports (80/443). - serverPort: "8080" + serverPort: "" ## @param ontoserver.hostNames Hostnames for ingress/gateway hostNames: - localhost From 95b54f42490e56f0838562ea888dc4b1384e908c Mon Sep 17 00:00:00 2001 From: Edelenyi Date: Thu, 13 Aug 2026 17:35:22 +1000 Subject: [PATCH 4/5] docs(ontoserver): document podManagementPolicy, exporters and serverPort Adds a "StatefulSet rolling updates and podManagementPolicy" section covering the no-ready-endpoint window under Parallel, why a PDB does not prevent it, the OrderedReady trade-off, and the kubectl delete --cascade=orphan recreate needed to adopt the policy on a live StatefulSet since the field is immutable. Also records the serverPort default change and its effect on 0.4.0/0.4.1 installs, and adds the new parameters to the values tables. --- charts/ontoserver/README.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/charts/ontoserver/README.md b/charts/ontoserver/README.md index 1862b83..a060b9e 100644 --- a/charts/ontoserver/README.md +++ b/charts/ontoserver/README.md @@ -86,6 +86,31 @@ The chart supports four deployment combinations controlled by `ontoserver.deploy - `clusterName` sets `ontoserver.cluster.name` for auto-discovery, allowing independent scaled clusters on the same network. Defaults to `ontoserver` (the application default) when unset. - `StatefulSet` kind always provisions PVCs via `volumeClaimTemplates`. `Deployment` kind requires `persistence.enabledForDeployment: true` to use PVCs. - The `PodDisruptionBudget` is rendered **only for `scaled`** deployments. A single instance owns its Lucene index on a ReadWriteOnce PVC and must be replaced rather than kept available during a disruption, so a PDB there would block node drains without protecting anything. Set exactly one of `minAvailable` or `maxUnavailable` — both accept a whole number or a percentage string (`"25%"`), and the chart fails if both or neither are set. `minAvailable: 1` is the default, so clear it (`minAvailable: null`) when you want `maxUnavailable`. +- `podManagementPolicy` (StatefulSet only) defaults to `Parallel`. See [StatefulSet rolling updates and `podManagementPolicy`](#statefulset-rolling-updates-and-podmanagementpolicy) — `Parallel` can leave a multi-replica install with no ready endpoint mid-update. + +### StatefulSet rolling updates and `podManagementPolicy` + +`ontoserver.deployment.podManagementPolicy` defaults to `Parallel`, which is what makes an initial scale-up fast: all replicas start at once rather than waiting for each pod's Lucene index preload in turn. The cost is that during a *rolling update* the controller also does not wait for a replacement pod to become Ready before replacing the next one. On a multi-replica install every pod can therefore be terminated within seconds of each other, and the Service is left with no ready endpoint until the first replacement passes its readiness probe — long enough with `healthCheckOption: -s` to return 503s to clients. A `PodDisruptionBudget` does not prevent this: a PDB only gates the Eviction API (node drains, `kubectl drain`), not StatefulSet-controller-driven pod replacement. + +Set `podManagementPolicy: OrderedReady` to make the controller wait for each pod to be Ready before moving to the next, which keeps at least one ready endpoint throughout the update. The trade-off is that startup and scale-up are serialized too, so a cluster whose pods need a long index preload takes proportionally longer to come up. + +```yaml +ontoserver: + deployment: + kind: StatefulSet + type: scaled + replicas: 3 + podManagementPolicy: OrderedReady +``` + +> **`podManagementPolicy` is immutable on an existing StatefulSet.** `helm upgrade` against a live release will fail with a field-is-immutable error. To adopt it on an already-deployed release, delete the StatefulSet while leaving the pods (and their PVCs) running, then upgrade so the chart recreates it: +> +> ```sh +> kubectl delete statefulset -statefulset --cascade=orphan +> helm upgrade ... --set ontoserver.deployment.podManagementPolicy=OrderedReady +> ``` +> +> The orphaned pods keep serving traffic and are adopted by the recreated StatefulSet, which matches them by selector and ordinal name. Because only `podManagementPolicy` changes and the pod template does not, the adopted pods should be treated as current and left running — watch `kubectl get pods -w` through the upgrade to confirm. The first rolling update after this is the one that honours the new policy. ### Supported configurations @@ -689,6 +714,8 @@ kubectl rollout status deployment/my-ontoserver-ontoserver ``` > **Port mapping note:** When the load balancer port differs from the standard HTTP/HTTPS port (as with `8080:80` above), set `ontoserver.serverPort: "8080"` in your values file. The chart uses this to construct the Spring Boot base URLs (`ontoserver.fhir.base`, `ontoserver.formats.html.base`, `ontoserver.synd.base`) that Ontoserver embeds in responses. Without it, Ontoserver would advertise `http://localhost/fhir` instead of `http://localhost:8080/fhir`. The `k3d-traefik-values.yaml` example already sets this. +> +> `serverPort` defaults to empty, which is correct for anything served on 80/443. Chart versions 0.4.0 and 0.4.1 shipped a default of `"8080"`, so installs on those versions that never set `serverPort` published `host:8080` in their CapabilityStatement and canonical URLs. Upgrading past 0.4.1 restores the empty default and the port disappears from those URLs — set `serverPort: "8080"` explicitly if you were relying on it. See [`examples/k3d-traefik-values.yaml`](examples/k3d-traefik-values.yaml) for the complete quick-start values file and [`examples/local-values.yaml`](examples/local-values.yaml) for a general local cluster reference. @@ -1153,6 +1180,7 @@ Requires the [External Secrets Operator](https://external-secrets.io/) installed | `ontoserver.deployment.isReadOnly` | Ontoserver in read‑only mode. Required to be true when type is scaled; see allowScaledReadWrite. | `true` | | `ontoserver.deployment.allowScaledReadWrite` | Opt in to the unsupported scaled read-write topology. Each replica has its own Lucene index, so content written through the round-robin Service is only indexed on the replica that served the write and $expand / $validate-code fail on the others. Load content with a single-instance read-write deployment instead, then serve it scaled and read-only. | `false` | | `ontoserver.deployment.replicas` | Number of replicas - min 2 for scaled deployment - can be set to 0 | `1` | +| `ontoserver.deployment.podManagementPolicy` | StatefulSet pod management policy (Parallel or OrderedReady); ignored when kind is Deployment. Parallel starts and replaces pods without waiting for Ready, so a multi-replica rolling update can leave the Service with no ready endpoint; OrderedReady waits for each pod to become Ready first. Immutable on a live StatefulSet - see the note below. | `Parallel` | | `ontoserver.deployment.clusterName` | Cluster name for auto-discovery in scaled deployments (overrides the default "ontoserver" set in application.properties); ignored for single deployments | `""` | | `ontoserver.deployment.annotations` | Deployment/Statefulset manifest annotations | `{}` | | `ontoserver.deployment.labels` | Deployment/Statefulset manifest labels | `{}` | @@ -1229,7 +1257,7 @@ Requires the [External Secrets Operator](https://external-secrets.io/) installed | Name | Description | Value | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------- | | `ontoserver.serverName` | Server hostname - must match a hostName at ontoserver.hostNames | `localhost` | -| `ontoserver.serverPort` | Non-standard port exposed to clients (e.g. 8080 when port-forwarding or k3d maps 8080:80). Leave empty for standard ports (80/443). | `8080` | +| `ontoserver.serverPort` | Non-standard port exposed to clients (e.g. 8080 when port-forwarding or k3d maps 8080:80). Leave empty for standard ports (80/443). | `""` | | `ontoserver.hostNames` | Hostnames for ingress/gateway | `["localhost"]` | | `ontoserver.timeZone` | Server time zone | `UTC` | | `ontoserver.language` | Locale/language | `en_US` | @@ -1290,7 +1318,9 @@ Requires the [External Secrets Operator](https://external-secrets.io/) installed | `ontoserver.opentelemetry.instrumentation.serviceName` | OTel service name (defaults to releaseName/releaseName-ontoserver) | `""` | | `ontoserver.opentelemetry.instrumentation.propagators` | Trace context propagators | `tracecontext,baggage,b3multi` | | `ontoserver.opentelemetry.instrumentation.excludedClasses` | Classes to exclude from instrumentation | `ca.uhn.fhir.*Interceptor*` | -| `ontoserver.opentelemetry.instrumentation.exporter.type` | Exporter type (zipkin, otlp, etc.) | `zipkin` | +| `ontoserver.opentelemetry.instrumentation.metricsExporter` | OTEL_METRICS_EXPORTER for the Java agent (e.g. otlp for JVM heap and GC metrics, or none to disable) | `none` | +| `ontoserver.opentelemetry.instrumentation.logsExporter` | OTEL_LOGS_EXPORTER for the Java agent (e.g. otlp, or none to disable) | `none` | +| `ontoserver.opentelemetry.instrumentation.exporter.type` | Trace exporter type (OTEL_TRACES_EXPORTER - zipkin, otlp, etc.) | `zipkin` | | `ontoserver.opentelemetry.instrumentation.exporter.endpoint` | Exporter endpoint URL (required when enabled) | `""` | ### Miscellaneous From 12f9c78daafa2ca6562a89cc2ab3990a916efd91 Mon Sep 17 00:00:00 2001 From: Edelenyi Date: Thu, 13 Aug 2026 17:44:30 +1000 Subject: [PATCH 5/5] docs(ontoserver): regenerate README parameter tables Runs the helm-readme-generator table pass so the parameter tables match values.yaml exactly, rather than the hand-written rows added in the previous commit. Only descriptions and column padding change. --- charts/ontoserver/README.md | 154 ++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/charts/ontoserver/README.md b/charts/ontoserver/README.md index a060b9e..3856c3c 100644 --- a/charts/ontoserver/README.md +++ b/charts/ontoserver/README.md @@ -1168,81 +1168,81 @@ Requires the [External Secrets Operator](https://external-secrets.io/) installed ### Deployment -| Name | Description | Value | -| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- | -| `ontoserver.deployment.kind` | Kind of controller (Deployment or StatefulSet) | `Deployment` | -| `ontoserver.deployment.type` | single|scaled deployment topology | `single` | -| `ontoserver.deployment.image` | Container image for OntoServer | `quay.io/aehrc/ontoserver:ctsa-6` | -| `ontoserver.deployment.imagePullPolicy` | Image pull policy | `IfNotPresent` | -| `ontoserver.deployment.containerPort` | Container port Ontoserver listens on. Use 8080 for HTTP (ONTOSERVER_INSECURE=true) or 8443 for HTTPS (ONTOSERVER_INSECURE=false). | `8080` | -| `ontoserver.deployment.lifecycle` | Container lifecycle hooks (postStart / preStop). Passed through as-is to the container spec. | `{}` | -| `ontoserver.deployment.imagePullSecrets` | Additional pre-created image pull secrets to attach to the pod (merged with the chart-managed pull secret when imageCredentials are set) | `[]` | -| `ontoserver.deployment.isReadOnly` | Ontoserver in read‑only mode. Required to be true when type is scaled; see allowScaledReadWrite. | `true` | -| `ontoserver.deployment.allowScaledReadWrite` | Opt in to the unsupported scaled read-write topology. Each replica has its own Lucene index, so content written through the round-robin Service is only indexed on the replica that served the write and $expand / $validate-code fail on the others. Load content with a single-instance read-write deployment instead, then serve it scaled and read-only. | `false` | -| `ontoserver.deployment.replicas` | Number of replicas - min 2 for scaled deployment - can be set to 0 | `1` | -| `ontoserver.deployment.podManagementPolicy` | StatefulSet pod management policy (Parallel or OrderedReady); ignored when kind is Deployment. Parallel starts and replaces pods without waiting for Ready, so a multi-replica rolling update can leave the Service with no ready endpoint; OrderedReady waits for each pod to become Ready first. Immutable on a live StatefulSet - see the note below. | `Parallel` | -| `ontoserver.deployment.clusterName` | Cluster name for auto-discovery in scaled deployments (overrides the default "ontoserver" set in application.properties); ignored for single deployments | `""` | -| `ontoserver.deployment.annotations` | Deployment/Statefulset manifest annotations | `{}` | -| `ontoserver.deployment.labels` | Deployment/Statefulset manifest labels | `{}` | -| `ontoserver.deployment.podAnnotations` | Pod annotations | `{}` | -| `ontoserver.deployment.podLabels` | Pod labels | `{}` | -| `ontoserver.deployment.podSecurityContext` | Pod-level securityContext, passed through as-is (e.g. runAsNonRoot, runAsUser, fsGroup, seccompProfile) | `{}` | -| `ontoserver.deployment.containerSecurityContext` | Container-level securityContext for the Ontoserver container, passed through as-is (e.g. allowPrivilegeEscalation, capabilities, readOnlyRootFilesystem) | `{}` | -| `ontoserver.deployment.automountServiceAccountToken` | Mount the ServiceAccount token into the pod. Ontoserver does not call the Kubernetes API — scaled clustering uses DNS, not the API — so false is safe. Leave unset (null) for the cluster default. | `nil` | -| `ontoserver.deployment.extraVolumes` | Extra pod volumes, e.g. `[{name: tmp, emptyDir: {}}]` | `[]` | -| `ontoserver.deployment.extraVolumeMounts` | Extra mounts for the Ontoserver container, e.g. `[{name: tmp, mountPath: /tmp}]` | `[]` | -| `ontoserver.deployment.deploymentStrategy` | K8s update strategy when using Deployment Kind. Forced to Recreate when a ReadWriteOnce volume is mounted. | `RollingUpdate` | -| `ontoserver.deployment.startupProbe.initialDelaySeconds` | Startup probe initial delay | `5` | -| `ontoserver.deployment.startupProbe.periodSeconds` | Startup probe period | `2` | -| `ontoserver.deployment.startupProbe.failureThreshold` | Startup probe failure threshold | `150` | -| `ontoserver.deployment.startupProbe.timeoutSeconds` | Startup probe timeout | `5` | -| `ontoserver.deployment.livenessProbe.initialDelaySeconds` | Liveness probe initial delay | `15` | -| `ontoserver.deployment.livenessProbe.periodSeconds` | Liveness probe period | `5` | -| `ontoserver.deployment.livenessProbe.failureThreshold` | Liveness probe failure threshold | `10` | -| `ontoserver.deployment.livenessProbe.timeoutSeconds` | Liveness probe timeout | `5` | -| `ontoserver.deployment.readinessProbe.initialDelaySeconds` | Readiness probe initial delay | `0` | -| `ontoserver.deployment.readinessProbe.periodSeconds` | Readiness probe period | `5` | -| `ontoserver.deployment.readinessProbe.failureThreshold` | Readiness probe failure threshold | `3` | -| `ontoserver.deployment.readinessProbe.timeoutSeconds` | Readiness probe timeout | `5` | -| `ontoserver.deployment.persistence.enabledForDeployment` | Enable PVC on Deployment | `false` | -| `ontoserver.deployment.persistence.mode` | shared | split - Use one or separate PV for db and lucene files | `split` | -| `ontoserver.deployment.persistence.files.accessMode` | PVC access mode. Use ReadWriteOnce for single instances and StatefulSet scaled deployments (each pod gets its own PVC via volumeClaimTemplates). Shared volumes across pods are not supported — Lucene indexes are pod-local. | `ReadWriteOnce` | -| `ontoserver.deployment.persistence.files.storageSize` | Requested storage size for the Ontoserver files volume | `10Gi` | -| `ontoserver.deployment.persistence.files.existingVolume.enabled` | Bind to existing PV (Deployment only; not supported for StatefulSet) | `false` | -| `ontoserver.deployment.persistence.files.existingVolume.name` | Name of existing PV | `""` | -| `ontoserver.deployment.persistence.files.pv.enabled` | Create a PersistentVolume for the files PVC backed by a pre-provisioned disk (requires existingVolume.enabled and existingVolume.name) | `false` | -| `ontoserver.deployment.persistence.files.pv.diskURI` | CSI volumeHandle — cloud-specific disk identifier (required when enabled, e.g. Azure disk resource ID or EBS volume ID) | `""` | -| `ontoserver.deployment.persistence.files.pv.csiDriver` | CSI driver (required when enabled, e.g. disk.csi.azure.com or ebs.csi.aws.com) | `""` | -| `ontoserver.deployment.persistence.files.pv.storageClassName` | StorageClass name (defaults to RELEASE-ontoserver-files) | `""` | -| `ontoserver.deployment.persistence.files.storageClass.name` | StorageClass name to use when provided.enabled is false; leave empty to use the cluster default StorageClass | `default` | -| `ontoserver.deployment.persistence.files.storageClass.provided.enabled` | Use provided storageClass | `true` | -| `ontoserver.deployment.persistence.files.storageClass.provided.storageProvisioner` | CSI driver - the default is AKS/Azure specific, replace for other clouds (e.g. ebs.csi.aws.com for EKS) | `disk.csi.azure.com` | -| `ontoserver.deployment.persistence.files.storageClass.provided.reclaimPolicy` | Storage Reclaim Policy | `Retain` | -| `ontoserver.deployment.persistence.files.storageClass.provided.storageParameters.skuName` | Storage SKU name (AKS/Azure specific) | `Premium_LRS` | -| `ontoserver.deployment.persistence.files.storageClass.provided.storageParameters.kind` | Storage kind (AKS/Azure specific) | `Managed` | -| `ontoserver.deployment.persistence.files.storageClass.provided.allowVolumeExpansion` | Allow volume expansion | `true` | -| `ontoserver.deployment.persistence.dbfiles.accessMode` | PVC access mode. Use ReadWriteOnce; only relevant for single-instance deployments with sidecar db (scaled deployments require external PostgreSQL and do not use dbfiles). | `ReadWriteOnce` | -| `ontoserver.deployment.persistence.dbfiles.storageSize` | Requested storage size for the database files volume | `10Gi` | -| `ontoserver.deployment.persistence.dbfiles.existingVolume.enabled` | Bind to existing PV (Deployment only; not supported for StatefulSet) | `false` | -| `ontoserver.deployment.persistence.dbfiles.existingVolume.name` | Name of existing PV | `""` | -| `ontoserver.deployment.persistence.dbfiles.pv.enabled` | Create a PersistentVolume for the db-files PVC backed by a pre-provisioned disk (requires existingVolume.enabled and existingVolume.name; only used in split mode with db.enabled) | `false` | -| `ontoserver.deployment.persistence.dbfiles.pv.diskURI` | CSI volumeHandle — cloud-specific disk identifier (required when enabled, e.g. Azure disk resource ID or EBS volume ID) | `""` | -| `ontoserver.deployment.persistence.dbfiles.pv.csiDriver` | CSI driver (required when enabled, e.g. disk.csi.azure.com or ebs.csi.aws.com) | `""` | -| `ontoserver.deployment.persistence.dbfiles.pv.storageClassName` | StorageClass name (defaults to RELEASE-ontoserver-db-files) | `""` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.name` | StorageClass name to use when provided.enabled is false; leave empty to use the cluster default StorageClass | `default` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.enabled` | Use provided storageClass | `true` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageProvisioner` | CSI driver - the default is AKS/Azure specific, replace for other clouds (e.g. ebs.csi.aws.com for EKS) | `disk.csi.azure.com` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.reclaimPolicy` | Storage Reclaim Policy | `Retain` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageParameters.skuName` | Storage SKU name (AKS/Azure specific) | `Premium_LRS` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageParameters.kind` | Storage kind (AKS/Azure specific) | `Managed` | -| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.allowVolumeExpansion` | Allow volume expansion | `true` | -| `ontoserver.deployment.podDisruptionBudget.enabled` | Enable PDB for scaled deployments | `true` | -| `ontoserver.deployment.podDisruptionBudget.minAvailable` | Minimum pods that must stay available. Whole number (1) or percentage string ("50%"). Mutually exclusive with maxUnavailable — clear this one (minAvailable: null) to use that instead. | `1` | -| `ontoserver.deployment.podDisruptionBudget.maxUnavailable` | Maximum pods that may be unavailable. Whole number (1) or percentage string ("25%"). Mutually exclusive with minAvailable, which is set by default. | `""` | -| `ontoserver.deployment.podDisruptionBudget.unhealthyPodEvictionPolicy` | IfHealthyBudget or AlwaysAllow. Empty uses the cluster default (IfHealthyBudget). | `""` | -| `ontoserver.deployment.db.enabled` | Enable Postgres sidecar | `true` | -| `ontoserver.deployment.db.postgresVersion` | Version of Postgres | `16` | -| `ontoserver.deployment.db.containerSecurityContext` | Container-level securityContext for the Postgres sidecar, passed through as-is. Kept separate from the Ontoserver container's because the two differ: the postgres image entrypoint requires uid 999 (it refuses to run as root) and initdb needs its data directory writable. | `{}` | +| Name | Description | Value | +| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | +| `ontoserver.deployment.kind` | Kind of controller (Deployment or StatefulSet) | `Deployment` | +| `ontoserver.deployment.type` | single|scaled deployment topology | `single` | +| `ontoserver.deployment.image` | Container image for OntoServer | `quay.io/aehrc/ontoserver:ctsa-6` | +| `ontoserver.deployment.imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `ontoserver.deployment.containerPort` | Container port Ontoserver listens on. Use 8080 for HTTP (ONTOSERVER_INSECURE=true) or 8443 for HTTPS (ONTOSERVER_INSECURE=false). | `8080` | +| `ontoserver.deployment.lifecycle` | Container lifecycle hooks (postStart / preStop). Passed through as-is to the container spec. | `{}` | +| `ontoserver.deployment.imagePullSecrets` | Additional pre-created image pull secrets to attach to the pod (merged with the chart-managed pull secret when imageCredentials are set) | `[]` | +| `ontoserver.deployment.isReadOnly` | Ontoserver in read‑only mode. Required to be true when type is scaled; see allowScaledReadWrite. | `true` | +| `ontoserver.deployment.allowScaledReadWrite` | Opt in to the unsupported scaled read-write topology. Each replica has its own Lucene index, so content written through the round-robin Service is only indexed on the replica that served the write and $expand / $validate-code fail on the others. Load content with a single-instance read-write deployment instead, then serve it scaled and read-only. | `false` | +| `ontoserver.deployment.replicas` | Number of replicas - min 2 for scaled deployment - can be set to 0 | `1` | +| `ontoserver.deployment.podManagementPolicy` | StatefulSet pod management policy (Parallel or OrderedReady); ignored when kind is Deployment. Parallel starts and replaces pods without waiting for Ready, so a multi-replica rolling update can leave the Service with no ready endpoint; OrderedReady waits for each pod to become Ready first. Immutable on a live StatefulSet - see the README for the --cascade=orphan recreate. | `Parallel` | +| `ontoserver.deployment.clusterName` | Cluster name for auto-discovery in scaled deployments (overrides the default "ontoserver" set in application.properties); ignored for single deployments | `""` | +| `ontoserver.deployment.annotations` | Deployment/Statefulset manifest annotations | `{}` | +| `ontoserver.deployment.labels` | Deployment/Statefulset manifest labels | `{}` | +| `ontoserver.deployment.podAnnotations` | Pod annotations | `{}` | +| `ontoserver.deployment.podLabels` | Pod labels | `{}` | +| `ontoserver.deployment.podSecurityContext` | Pod-level securityContext, passed through as-is (e.g. runAsNonRoot, runAsUser, fsGroup, seccompProfile) | `{}` | +| `ontoserver.deployment.containerSecurityContext` | Container-level securityContext for the Ontoserver container, passed through as-is (e.g. allowPrivilegeEscalation, capabilities, readOnlyRootFilesystem) | `{}` | +| `ontoserver.deployment.automountServiceAccountToken` | Mount the ServiceAccount token into the pod. Ontoserver does not call the Kubernetes API — scaled clustering uses DNS, not the API — so false is safe. Leave unset (null) for the cluster default. | `nil` | +| `ontoserver.deployment.extraVolumes` | Extra pod volumes, e.g. `[{name: tmp, emptyDir: {}}]` | `[]` | +| `ontoserver.deployment.extraVolumeMounts` | Extra mounts for the Ontoserver container, e.g. `[{name: tmp, mountPath: /tmp}]` | `[]` | +| `ontoserver.deployment.deploymentStrategy` | K8s update strategy when using Deployment Kind. Forced to Recreate when a ReadWriteOnce volume is mounted. | `RollingUpdate` | +| `ontoserver.deployment.startupProbe.initialDelaySeconds` | Startup probe initial delay | `5` | +| `ontoserver.deployment.startupProbe.periodSeconds` | Startup probe period | `2` | +| `ontoserver.deployment.startupProbe.failureThreshold` | Startup probe failure threshold | `150` | +| `ontoserver.deployment.startupProbe.timeoutSeconds` | Startup probe timeout | `5` | +| `ontoserver.deployment.livenessProbe.initialDelaySeconds` | Liveness probe initial delay | `15` | +| `ontoserver.deployment.livenessProbe.periodSeconds` | Liveness probe period | `5` | +| `ontoserver.deployment.livenessProbe.failureThreshold` | Liveness probe failure threshold | `10` | +| `ontoserver.deployment.livenessProbe.timeoutSeconds` | Liveness probe timeout | `5` | +| `ontoserver.deployment.readinessProbe.initialDelaySeconds` | Readiness probe initial delay | `0` | +| `ontoserver.deployment.readinessProbe.periodSeconds` | Readiness probe period | `5` | +| `ontoserver.deployment.readinessProbe.failureThreshold` | Readiness probe failure threshold | `3` | +| `ontoserver.deployment.readinessProbe.timeoutSeconds` | Readiness probe timeout | `5` | +| `ontoserver.deployment.persistence.enabledForDeployment` | Enable PVC on Deployment | `false` | +| `ontoserver.deployment.persistence.mode` | shared | split - Use one or separate PV for db and lucene files | `split` | +| `ontoserver.deployment.persistence.files.accessMode` | PVC access mode. Use ReadWriteOnce for single instances and StatefulSet scaled deployments (each pod gets its own PVC via volumeClaimTemplates). Shared volumes across pods are not supported — Lucene indexes are pod-local. | `ReadWriteOnce` | +| `ontoserver.deployment.persistence.files.storageSize` | Requested storage size for the Ontoserver files volume | `10Gi` | +| `ontoserver.deployment.persistence.files.existingVolume.enabled` | Bind to existing PV (Deployment only; not supported for StatefulSet) | `false` | +| `ontoserver.deployment.persistence.files.existingVolume.name` | Name of existing PV | `""` | +| `ontoserver.deployment.persistence.files.pv.enabled` | Create a PersistentVolume for the files PVC backed by a pre-provisioned disk (requires existingVolume.enabled and existingVolume.name) | `false` | +| `ontoserver.deployment.persistence.files.pv.diskURI` | CSI volumeHandle — cloud-specific disk identifier (required when enabled, e.g. Azure disk resource ID or EBS volume ID) | `""` | +| `ontoserver.deployment.persistence.files.pv.csiDriver` | CSI driver (required when enabled, e.g. disk.csi.azure.com or ebs.csi.aws.com) | `""` | +| `ontoserver.deployment.persistence.files.pv.storageClassName` | StorageClass name (defaults to RELEASE-ontoserver-files) | `""` | +| `ontoserver.deployment.persistence.files.storageClass.name` | StorageClass name to use when provided.enabled is false; leave empty to use the cluster default StorageClass | `default` | +| `ontoserver.deployment.persistence.files.storageClass.provided.enabled` | Use provided storageClass | `true` | +| `ontoserver.deployment.persistence.files.storageClass.provided.storageProvisioner` | CSI driver - the default is AKS/Azure specific, replace for other clouds (e.g. ebs.csi.aws.com for EKS) | `disk.csi.azure.com` | +| `ontoserver.deployment.persistence.files.storageClass.provided.reclaimPolicy` | Storage Reclaim Policy | `Retain` | +| `ontoserver.deployment.persistence.files.storageClass.provided.storageParameters.skuName` | Storage SKU name (AKS/Azure specific) | `Premium_LRS` | +| `ontoserver.deployment.persistence.files.storageClass.provided.storageParameters.kind` | Storage kind (AKS/Azure specific) | `Managed` | +| `ontoserver.deployment.persistence.files.storageClass.provided.allowVolumeExpansion` | Allow volume expansion | `true` | +| `ontoserver.deployment.persistence.dbfiles.accessMode` | PVC access mode. Use ReadWriteOnce; only relevant for single-instance deployments with sidecar db (scaled deployments require external PostgreSQL and do not use dbfiles). | `ReadWriteOnce` | +| `ontoserver.deployment.persistence.dbfiles.storageSize` | Requested storage size for the database files volume | `10Gi` | +| `ontoserver.deployment.persistence.dbfiles.existingVolume.enabled` | Bind to existing PV (Deployment only; not supported for StatefulSet) | `false` | +| `ontoserver.deployment.persistence.dbfiles.existingVolume.name` | Name of existing PV | `""` | +| `ontoserver.deployment.persistence.dbfiles.pv.enabled` | Create a PersistentVolume for the db-files PVC backed by a pre-provisioned disk (requires existingVolume.enabled and existingVolume.name; only used in split mode with db.enabled) | `false` | +| `ontoserver.deployment.persistence.dbfiles.pv.diskURI` | CSI volumeHandle — cloud-specific disk identifier (required when enabled, e.g. Azure disk resource ID or EBS volume ID) | `""` | +| `ontoserver.deployment.persistence.dbfiles.pv.csiDriver` | CSI driver (required when enabled, e.g. disk.csi.azure.com or ebs.csi.aws.com) | `""` | +| `ontoserver.deployment.persistence.dbfiles.pv.storageClassName` | StorageClass name (defaults to RELEASE-ontoserver-db-files) | `""` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.name` | StorageClass name to use when provided.enabled is false; leave empty to use the cluster default StorageClass | `default` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.enabled` | Use provided storageClass | `true` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageProvisioner` | CSI driver - the default is AKS/Azure specific, replace for other clouds (e.g. ebs.csi.aws.com for EKS) | `disk.csi.azure.com` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.reclaimPolicy` | Storage Reclaim Policy | `Retain` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageParameters.skuName` | Storage SKU name (AKS/Azure specific) | `Premium_LRS` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.storageParameters.kind` | Storage kind (AKS/Azure specific) | `Managed` | +| `ontoserver.deployment.persistence.dbfiles.storageClass.provided.allowVolumeExpansion` | Allow volume expansion | `true` | +| `ontoserver.deployment.podDisruptionBudget.enabled` | Enable PDB for scaled deployments | `true` | +| `ontoserver.deployment.podDisruptionBudget.minAvailable` | Minimum pods that must stay available. Whole number (1) or percentage string ("50%"). Mutually exclusive with maxUnavailable — clear this one (minAvailable: null) to use that instead. | `1` | +| `ontoserver.deployment.podDisruptionBudget.maxUnavailable` | Maximum pods that may be unavailable. Whole number (1) or percentage string ("25%"). Mutually exclusive with minAvailable, which is set by default. | `""` | +| `ontoserver.deployment.podDisruptionBudget.unhealthyPodEvictionPolicy` | IfHealthyBudget or AlwaysAllow. Empty uses the cluster default (IfHealthyBudget). | `""` | +| `ontoserver.deployment.db.enabled` | Enable Postgres sidecar | `true` | +| `ontoserver.deployment.db.postgresVersion` | Version of Postgres | `16` | +| `ontoserver.deployment.db.containerSecurityContext` | Container-level securityContext for the Postgres sidecar, passed through as-is. Kept separate from the Ontoserver container's because the two differ: the postgres image entrypoint requires uid 999 (it refuses to run as root) and initdb needs its data directory writable. | `{}` | ### Registry Credentials @@ -1318,8 +1318,8 @@ Requires the [External Secrets Operator](https://external-secrets.io/) installed | `ontoserver.opentelemetry.instrumentation.serviceName` | OTel service name (defaults to releaseName/releaseName-ontoserver) | `""` | | `ontoserver.opentelemetry.instrumentation.propagators` | Trace context propagators | `tracecontext,baggage,b3multi` | | `ontoserver.opentelemetry.instrumentation.excludedClasses` | Classes to exclude from instrumentation | `ca.uhn.fhir.*Interceptor*` | -| `ontoserver.opentelemetry.instrumentation.metricsExporter` | OTEL_METRICS_EXPORTER for the Java agent (e.g. otlp for JVM heap and GC metrics, or none to disable) | `none` | -| `ontoserver.opentelemetry.instrumentation.logsExporter` | OTEL_LOGS_EXPORTER for the Java agent (e.g. otlp, or none to disable) | `none` | +| `ontoserver.opentelemetry.instrumentation.metricsExporter` | OTEL_METRICS_EXPORTER for the Java agent (e.g. otlp for JVM heap and GC metrics, or none to disable) | `none` | +| `ontoserver.opentelemetry.instrumentation.logsExporter` | OTEL_LOGS_EXPORTER for the Java agent (e.g. otlp, or none to disable) | `none` | | `ontoserver.opentelemetry.instrumentation.exporter.type` | Trace exporter type (OTEL_TRACES_EXPORTER - zipkin, otlp, etc.) | `zipkin` | | `ontoserver.opentelemetry.instrumentation.exporter.endpoint` | Exporter endpoint URL (required when enabled) | `""` |