From 7a690a805a14e9a96bd89cb71c6503f23c037574 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 2 Sep 2026 17:48:19 +0200 Subject: [PATCH 1/5] docs: add migration guide from backstage chart (1.y) to rhdh chart (2.y) Add a values mapping reference under docs/ covering all path changes between the legacy backstage chart and the new redhat-developer-hub chart. Link to it from the README migration section and replace the WIP placeholder with actionable guidance. Ref: RHIDP-16514 --- charts/rhdh/Chart.yaml | 2 +- charts/rhdh/README.md | 283 +++++++++--------- charts/rhdh/README.md.gotmpl | 4 +- .../docs/migration-from-backstage-chart.md | 241 +++++++++++++++ 4 files changed, 385 insertions(+), 145 deletions(-) create mode 100644 charts/rhdh/docs/migration-from-backstage-chart.md diff --git a/charts/rhdh/Chart.yaml b/charts/rhdh/Chart.yaml index 29620c62..b1c1ade8 100644 --- a/charts/rhdh/Chart.yaml +++ b/charts/rhdh/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: redhat-developer-hub type: application -version: 2.0.0 +version: 2.0.1 appVersion: 2.1.0 annotations: artifacthub.io/category: integration-delivery diff --git a/charts/rhdh/README.md b/charts/rhdh/README.md index d359da0d..d1188e4d 100644 --- a/charts/rhdh/README.md +++ b/charts/rhdh/README.md @@ -1,7 +1,6 @@ - # RHDH Helm Chart for OpenShift and Kubernetes -![Version: 2.0.0](https://img.shields.io/badge/Version-2.0.0-informational?style=flat-square) +![Version: 2.0.1](https://img.shields.io/badge/Version-2.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Helm chart for deploying Red Hat Developer Hub, which is a Red Hat supported version of Backstage. @@ -36,7 +35,7 @@ For the **Generally Available** version of this chart, see: helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart -helm install my-rhdh redhat-developer/redhat-developer-hub --version 2.0.0 +helm install my-rhdh redhat-developer/redhat-developer-hub --version 2.0.1 ``` ## Introduction @@ -159,9 +158,9 @@ The command removes all the Kubernetes components associated with the chart and ## Upgrading from the backstage chart (RHDH 1.y) -> **Note:** This section is a work in progress. A detailed migration guide will be provided before the GA release of RHDH 2.y. +If you are upgrading from the legacy `backstage` chart (used in RHDH 1.y), the new `redhat-developer-hub` chart is a clean break. The values structure has changed significantly — all `global.*` and `upstream.backstage.*` nesting has been flattened to root-level keys. You cannot pass your old values file directly to the new chart; you must migrate your values first, then `helm upgrade` the release in place. -If you are upgrading from the legacy `backstage` chart (used in RHDH 1.y), the new `redhat-developer-hub` chart is a clean break. The values structure has changed significantly — all `global.*` and `upstream.backstage.*` nesting has been flattened to root-level keys. A `helm upgrade` from the old chart to this one is **not** supported; you will need to perform a fresh install with migrated values. +See the [Migration guide](docs/migration-from-backstage-chart.md) for step-by-step instructions and a complete values mapping reference. ## Requirements @@ -174,143 +173,143 @@ Kubernetes: `>= 1.31.0-0` ## Values -| Key | Description | Type | Default | -|-----|-------------|------|---------| -| affinity | Affinity rules for pod assignment. | object | `{}` | -| appConfig | Inline Backstage app-config YAML. Rendered into a ConfigMap and mounted as app-config-from-configmap.yaml. | object | Default config with base URLs, CORS, database connection, and backend auth. | -| argsOverride | Override the container arguments entirely. When set, system config arguments are NOT added automatically; you must include them yourself. | list | `[]` | -| auth | Service-to-service authentication configuration. | object | `{"backend":{"enabled":true,"existingSecretRef":{"key":"backend-secret","name":""},"value":""}}` | -| auth.backend.enabled | Enable backend service-to-service authentication. Generates a random secret unless existingSecretRef is set or value is provided. Disable if you inject the secret via extraEnvFrom or extraEnv instead. | bool | `true` | -| auth.backend.existingSecretRef | Reference an existing Secret instead of generating one. When not set, the chart auto-generates a random token. | object | `{"key":"backend-secret","name":""}` | -| auth.backend.existingSecretRef.key | Key within the Secret that holds the backend auth token. | string | `"backend-secret"` | -| auth.backend.existingSecretRef.name | Name of the existing Secret. When empty, the chart generates one. | string | `""` | -| auth.backend.value | Use a specific value instead of generating one. | string | `""` | -| autoscaling | Horizontal Pod Autoscaler configuration. | object | `{"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | -| catalogIndex | Catalog index configuration for automatic plugin discovery. | object | `{"extraImages":[],"image":{"digest":"","registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"next"}}` | -| catalogIndex.extraImages | Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include `registry`, `repository`, and `tag` fields; `name` and `digest` are optional. Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). | list | `[]` | -| commandOverride | Override the container command. | list | `[]` | -| commonAnnotations | Annotations applied to ALL chart resources. | object | `{}` | -| commonLabels | Labels applied to ALL chart resources. | object | `{}` | -| containerSecurityContext | Security context for the main RHDH container (not the Lightspeed Core sidecar or init containers). | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | -| deploymentAnnotations | Annotations for the Deployment resource (not the pod). | object | `{}` | -| dynamicPlugins | Dynamic plugin system configuration. | object | `{"includes":["dynamic-plugins.default.yaml"],"initContainer":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}},"maxEntrySize":40000000,"plugins":[],"volume":{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}}` | -| dynamicPlugins.includes | Array of YAML files listing dynamic plugins to include. Relative paths are resolved from the working directory of the initContainer (`/opt/app-root/src`). | list | `["dynamic-plugins.default.yaml"]` | -| dynamicPlugins.initContainer | Configuration for the install-dynamic-plugins init container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}}` | -| dynamicPlugins.initContainer.argsOverride | Override the default arguments. Leave empty to use the defaults. | list | `[]` | -| dynamicPlugins.initContainer.commandOverride | Override the default command. Leave empty to use the default (./install-dynamic-plugins.sh /dynamic-plugins-root). | list | `[]` | -| dynamicPlugins.initContainer.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | -| dynamicPlugins.initContainer.extraEnv | Extra environment variables appended after the system env vars (NPM_CONFIG_USERCONFIG, MAX_ENTRY_SIZE, CATALOG_INDEX_IMAGE, etc.). | list | `[]` | -| dynamicPlugins.initContainer.extraVolumeMounts | Additional volume mounts appended after the system mounts (dynamic-plugins-root, npmrc, registry-auth, npmcacache, extensions-catalog, temp). | list | `[]` | -| dynamicPlugins.initContainer.resources | Resource requests and limits. | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | -| dynamicPlugins.initContainer.securityContext | Security context for the init container. | object | Same as containerSecurityContext | -| dynamicPlugins.maxEntrySize | Maximum uncompressed size (in bytes) of a single dynamic plugin entry. | int | `40000000` | -| dynamicPlugins.plugins | List of dynamic plugins. Every item defines the plugin `package` as a NPM package spec or OCI reference. | list | `[]` | -| dynamicPlugins.volume | Volume configuration for the dynamic plugins root directory. | object | `{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}` | -| dynamicPlugins.volume.emptyDir | Raw Kubernetes emptyDir volume spec. Used when type is "emptyDir". | object | `{}` | -| dynamicPlugins.volume.ephemeral | Ephemeral volume configuration. Used when type is "ephemeral". The chart builds the full ephemeral.volumeClaimTemplate.spec from these fields. | object | `{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}` | -| dynamicPlugins.volume.ephemeral.accessModes | Access modes for the ephemeral PVC. | list | `["ReadWriteOnce"]` | -| dynamicPlugins.volume.ephemeral.resources | Resource requests for the ephemeral PVC. | object | `{"requests":{"storage":"5Gi"}}` | -| dynamicPlugins.volume.ephemeral.storageClassName | StorageClass for the ephemeral volume. When empty, uses global.defaultStorageClass or the cluster default. | string | `""` | -| dynamicPlugins.volume.pvc | Raw Kubernetes persistentVolumeClaim volume spec. Used when type is "pvc". | object | `{"claimName":""}` | -| dynamicPlugins.volume.type | Volume type: "ephemeral" (auto-provisioned PVC per pod), "emptyDir" (scratch space, lost on pod restart), or "pvc" (pre-existing PersistentVolumeClaim). | string | `"ephemeral"` | -| envFromOverride | Override the container envFrom entirely. When set, extraEnvFrom is ignored. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | list | `[]` | -| envOverride | Override the container environment variables entirely. When set, system env vars (BACKEND_SECRET, DB credentials, etc.) are NOT added automatically. | list | `[]` | -| externalDatabase | External database connection. Used when postgresql.enabled is false. See docs/external-db.md for TLS setup and privilege requirements. When both postgresql.enabled and externalDatabase.host are false/empty, the chart renders no database env vars (BYO configuration via extraEnv or appConfig). | object | `{"existingSecretRef":{"key":"password","name":""},"host":"","port":5432,"user":"postgres"}` | -| externalDatabase.existingSecretRef | Reference to an existing Secret containing the database password. | object | `{"key":"password","name":""}` | -| externalDatabase.existingSecretRef.key | Key within the Secret that holds the password. | string | `"password"` | -| externalDatabase.existingSecretRef.name | Name of the existing Secret. | string | `""` | -| externalDatabase.host | External database hostname. | string | `""` | -| externalDatabase.port | External database port. | int | `5432` | -| externalDatabase.user | External database user. | string | `"postgres"` | -| extraAppConfig | Additional app-config files from existing ConfigMaps. | list | `[]` | -| extraArgs | Extra arguments appended after the system config flags. | list | `[]` | -| extraContainers | Additional sidecar containers. These are ADDED to system containers (e.g. Lightspeed Core sidecar), never replacing them. | list | `[]` | -| extraEnv | Extra environment variables appended after the system env vars. | list | `[]` | -| extraEnvFrom | Extra envFrom entries appended to the container. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | list | `[]` | -| extraInitContainers | Additional init containers. These are ADDED after system init containers (install-dynamic-plugins, Intelligent Assistant RAG init), never replacing them. | list | `[]` | -| extraVolumeMounts | Additional volume mounts to add to the main container. These are ADDED to system-required mounts, never replacing them. | list | `[]` | -| extraVolumes | Additional volumes to add to the pod. These are ADDED to system-required volumes (dynamic-plugins-root, temp, npmcacache, etc.), never replacing them. | list | `[]` | -| fullnameOverride | Override the full resource name. | string | `""` | -| global | Global parameters shared with bitnami subcharts (postgresql, common). | object | `{"defaultStorageClass":"","imagePullSecrets":[],"imageRegistry":""}` | -| global.defaultStorageClass | Global default StorageClass for PVCs. | string | `""` | -| global.imagePullSecrets | Global Docker registry secret names. | list | `[]` | -| global.imageRegistry | Global Docker image registry. Overrides per-image registries for all containers. | string | `""` | -| host | Custom hostname. Overrides openshift.clusterRouterBase for URL generation. | string | `""` | -| hostAliases | Host aliases for /etc/hosts entries. | list | `[]` | -| httpRoute | Gateway API HTTPRoute configuration. | object | `{"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}` | -| httpRoute.labels | Additional labels for the HTTPRoute resource. | object | `{}` | -| image | Container image configuration. | object | `{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"rhdh-community/rhdh","tag":"next"}` | -| image.digest | Overrides the image tag with an image digest. | string | `""` | -| imagePullSecrets | Secrets for pulling images from private registries (merged with global.imagePullSecrets). | list | `[]` | -| ingress | Kubernetes Ingress configuration. | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | -| intelligentAssistant | Built-in Intelligent Assistant feature configuration. | object | `{"config":{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}},"core":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"enabled":true,"existingSecret":"","plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}],"ragInit":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | -| intelligentAssistant.config | Configuration files mounted into the sidecar. By default, the chart creates ConfigMaps from bundled source files. Set existingConfigMap to use a pre-existing ConfigMap instead. | object | `{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}}` | -| intelligentAssistant.config.profile | Python profile with prompt templates (rhdh-profile.py). | object | `{"existingConfigMap":{"key":"","name":""}}` | -| intelligentAssistant.config.profile.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled rhdh-profile.py | -| intelligentAssistant.config.profile.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (rhdh-profile.py) if not set. | string | `""` | -| intelligentAssistant.config.profile.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | -| intelligentAssistant.config.server | Llama Stack server configuration (config.yaml). | object | `{"existingConfigMap":{"key":"","name":""}}` | -| intelligentAssistant.config.server.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled config.yaml | -| intelligentAssistant.config.server.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (config.yaml) if not set. | string | `""` | -| intelligentAssistant.config.server.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | -| intelligentAssistant.config.stack | Lightspeed Core service configuration (lightspeed-stack.yaml). | object | `{"existingConfigMap":{"key":"","name":""}}` | -| intelligentAssistant.config.stack.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled lightspeed-stack.yaml | -| intelligentAssistant.config.stack.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (lightspeed-stack.yaml) if not set. | string | `""` | -| intelligentAssistant.config.stack.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | -| intelligentAssistant.core | Lightspeed Core sidecar container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | -| intelligentAssistant.core.argsOverride | Override the container's default args. Leave empty to use the image defaults. | list | `[]` | -| intelligentAssistant.core.commandOverride | Override the container's default command. Leave empty to use the image entrypoint. | list | `[]` | -| intelligentAssistant.core.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | -| intelligentAssistant.existingSecret | Name of an existing Secret to inject via envFrom into the lightspeed-core container. If empty, no secret is mounted. Expected keys (all optional — only set the ones for the providers you use): ENABLE_VLLM, VLLM_URL, VLLM_API_KEY, VLLM_MAX_TOKENS, VLLM_TLS_VERIFY, ENABLE_OPENAI, OPENAI_API_KEY, ENABLE_VERTEX_AI, VERTEX_AI_PROJECT, VERTEX_AI_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, ENABLE_OLLAMA, OLLAMA_URL, ENABLE_VALIDATION, VALIDATION_PROVIDER, VALIDATION_MODEL_NAME, LLAMA_STACK_LOGGING See files/intelligent-assistant/secret.example.yaml for a reference template. | string | `""` | -| intelligentAssistant.plugins | Intelligent Assistant dynamic plugin packages. | list | `[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}]` | -| intelligentAssistant.ragInit | RAG data bootstrap init container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | -| intelligentAssistant.ragInit.argsOverride | Override the default arguments for the RAG init container. | list | `[]` | -| intelligentAssistant.ragInit.commandOverride | Override the default command for the RAG init container. | list | `[]` | -| intelligentAssistant.ragInit.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | -| intelligentAssistant.runtimeVolume | Writable scratch volume for the sidecar (/tmp). | object | `{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}` | -| intelligentAssistant.runtimeVolume.type | Volume type: "emptyDir" or "persistentVolumeClaim". | string | `"emptyDir"` | -| livenessProbe | Liveness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}` | -| metrics | Prometheus metrics configuration. | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}` | -| nameOverride | Override the chart name used in resource naming. | string | `""` | -| nodeSelector | Node labels for pod assignment. | object | `{}` | -| openshift | OpenShift-specific configuration. | object | `{"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}` | -| openshift.clusterRouterBase | Cluster router base domain used to auto-generate the hostname. | string | `"apps.example.com"` | -| openshift.route | OpenShift Route configuration. | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | -| orchestrator | Orchestrator (Serverless workflows) configuration. | object | `{"enabled":false,"plugins":[{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}],"serverlessLogicOperator":{"enabled":true},"serverlessOperator":{"enabled":true},"sonataflowPlatform":{"dataIndex":{"image":{"digest":"","registry":"","repository":"","tag":""}},"dbCreationJob":{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null},"eventing":{"broker":{"name":"","namespace":""}},"externalDB":{"existingSecret":"","host":"","name":"","port":""},"jobService":{"image":{"digest":"","registry":"","repository":"","tag":""}},"monitoring":{"enabled":true},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"250m","memory":"64Mi"}}}}` | -| orchestrator.sonataflowPlatform.dataIndex | SonataFlow Data Index service configuration. | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | -| orchestrator.sonataflowPlatform.dataIndex.image | Override the Data Index container image. If empty, the operator default is used. | object | `{"digest":"","registry":"","repository":"","tag":""}` | -| orchestrator.sonataflowPlatform.dbCreationJob | Database creation Job configuration. | object | `{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null}` | -| orchestrator.sonataflowPlatform.dbCreationJob.image | Container image for the create-db Job. | object | `{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"}` | -| orchestrator.sonataflowPlatform.externalDB | External database connection. Used when postgresql.enabled is false. | object | `{"existingSecret":"","host":"","name":"","port":""}` | -| orchestrator.sonataflowPlatform.externalDB.existingSecret | Name of a Secret containing POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD keys. | string | `""` | -| orchestrator.sonataflowPlatform.externalDB.host | Database host (used in JDBC URLs). | string | `""` | -| orchestrator.sonataflowPlatform.externalDB.name | Database name to connect to for the CREATE DATABASE command. | string | `""` | -| orchestrator.sonataflowPlatform.externalDB.port | Database port (used in JDBC URLs). | string | `""` | -| orchestrator.sonataflowPlatform.jobService | SonataFlow Job Service configuration. | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | -| orchestrator.sonataflowPlatform.jobService.image | Override the Job Service container image. If empty, the operator default is used. | object | `{"digest":"","registry":"","repository":"","tag":""}` | -| podAnnotations | Annotations to add to the pod. | object | `{}` | -| podDisruptionBudget | Pod Disruption Budget configuration. | object | `{"create":false,"maxUnavailable":1,"minAvailable":""}` | -| podLabels | Labels to add to the pod. | object | `{}` | -| podSecurityContext | Pod-level security context. | object | `{}` | -| postgresql | Built-in PostgreSQL database (bitnami subchart). | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"serviceBindings":{"enabled":true}}` | -| preInitContainers | Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). | list | `[]` | -| readinessProbe | Readiness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}` | -| replicaCount | Number of desired pods. | int | `1` | -| resources | Resource requests and limits for the main RHDH container. | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}` | -| revisionHistoryLimit | Number of old ReplicaSets to retain. | int | `10` | -| service | Service configuration. | object | `{"annotations":{},"clusterIP":"","externalTrafficPolicy":"","extraPorts":[{"name":"http-metrics","port":9464,"targetPort":9464}],"ipFamilies":[],"ipFamilyPolicy":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePort":"","port":7007,"sessionAffinity":"","type":"ClusterIP"}` | -| service.extraPorts | Additional service ports. | list | `[{"name":"http-metrics","port":9464,"targetPort":9464}]` | -| service.ipFamilies | IP families for dual-stack networking. | list | `[]` | -| service.ipFamilyPolicy | IP family policy for dual-stack networking. | string | `""` | -| service.nodePort | Node port for NodePort/LoadBalancer service types (range 30000-32767). | string | `""` | -| serviceAccount | ServiceAccount configuration. | object | `{"annotations":{},"automount":true,"create":false,"labels":{},"name":""}` | -| serviceAccount.labels | Additional labels for the ServiceAccount. | object | `{}` | -| serviceAccount.name | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | string | `""` | -| startupProbe | Startup probe configuration. Gives the application time to start before liveness/readiness probes kick in. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":4}` | -| strategy | Deployment update strategy. | object | `{}` | -| test | Test pod configuration for `helm test`. | object | `{"enabled":true,"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"curl/curl","tag":"8.21.0"},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}` | -| tolerations | Tolerations for pod assignment. | list | `[]` | -| topologySpreadConstraints | Topology spread constraints for pod scheduling. | list | `[]` | +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity rules for pod assignment. | +| appConfig | object | Default config with base URLs, CORS, database connection, and backend auth. | Inline Backstage app-config YAML. Rendered into a ConfigMap and mounted as app-config-from-configmap.yaml. | +| argsOverride | list | `[]` | Override the container arguments entirely. When set, system config arguments are NOT added automatically; you must include them yourself. | +| auth | object | `{"backend":{"enabled":true,"existingSecretRef":{"key":"backend-secret","name":""},"value":""}}` | Service-to-service authentication configuration. | +| auth.backend.enabled | bool | `true` | Enable backend service-to-service authentication. Generates a random secret unless existingSecretRef is set or value is provided. Disable if you inject the secret via extraEnvFrom or extraEnv instead. | +| auth.backend.existingSecretRef | object | `{"key":"backend-secret","name":""}` | Reference an existing Secret instead of generating one. When not set, the chart auto-generates a random token. | +| auth.backend.existingSecretRef.key | string | `"backend-secret"` | Key within the Secret that holds the backend auth token. | +| auth.backend.existingSecretRef.name | string | `""` | Name of the existing Secret. When empty, the chart generates one. | +| auth.backend.value | string | `""` | Use a specific value instead of generating one. | +| autoscaling | object | `{"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Horizontal Pod Autoscaler configuration. | +| catalogIndex | object | `{"extraImages":[],"image":{"digest":"","registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"next"}}` | Catalog index configuration for automatic plugin discovery. | +| catalogIndex.extraImages | list | `[]` | Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include `registry`, `repository`, and `tag` fields; `name` and `digest` are optional. Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). | +| commandOverride | list | `[]` | Override the container command. | +| commonAnnotations | object | `{}` | Annotations applied to ALL chart resources. | +| commonLabels | object | `{}` | Labels applied to ALL chart resources. | +| containerSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for the main RHDH container (not the Lightspeed Core sidecar or init containers). | +| deploymentAnnotations | object | `{}` | Annotations for the Deployment resource (not the pod). | +| dynamicPlugins | object | `{"includes":["dynamic-plugins.default.yaml"],"initContainer":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}},"maxEntrySize":40000000,"plugins":[],"volume":{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}}` | Dynamic plugin system configuration. | +| dynamicPlugins.includes | list | `["dynamic-plugins.default.yaml"]` | Array of YAML files listing dynamic plugins to include. Relative paths are resolved from the working directory of the initContainer (`/opt/app-root/src`). | +| dynamicPlugins.initContainer | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}}` | Configuration for the install-dynamic-plugins init container. | +| dynamicPlugins.initContainer.argsOverride | list | `[]` | Override the default arguments. Leave empty to use the defaults. | +| dynamicPlugins.initContainer.commandOverride | list | `[]` | Override the default command. Leave empty to use the default (./install-dynamic-plugins.sh /dynamic-plugins-root). | +| dynamicPlugins.initContainer.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | +| dynamicPlugins.initContainer.extraEnv | list | `[]` | Extra environment variables appended after the system env vars (NPM_CONFIG_USERCONFIG, MAX_ENTRY_SIZE, CATALOG_INDEX_IMAGE, etc.). | +| dynamicPlugins.initContainer.extraVolumeMounts | list | `[]` | Additional volume mounts appended after the system mounts (dynamic-plugins-root, npmrc, registry-auth, npmcacache, extensions-catalog, temp). | +| dynamicPlugins.initContainer.resources | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | Resource requests and limits. | +| dynamicPlugins.initContainer.securityContext | object | Same as containerSecurityContext | Security context for the init container. | +| dynamicPlugins.maxEntrySize | int | `40000000` | Maximum uncompressed size (in bytes) of a single dynamic plugin entry. | +| dynamicPlugins.plugins | list | `[]` | List of dynamic plugins. Every item defines the plugin `package` as a NPM package spec or OCI reference. | +| dynamicPlugins.volume | object | `{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}` | Volume configuration for the dynamic plugins root directory. | +| dynamicPlugins.volume.emptyDir | object | `{}` | Raw Kubernetes emptyDir volume spec. Used when type is "emptyDir". | +| dynamicPlugins.volume.ephemeral | object | `{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}` | Ephemeral volume configuration. Used when type is "ephemeral". The chart builds the full ephemeral.volumeClaimTemplate.spec from these fields. | +| dynamicPlugins.volume.ephemeral.accessModes | list | `["ReadWriteOnce"]` | Access modes for the ephemeral PVC. | +| dynamicPlugins.volume.ephemeral.resources | object | `{"requests":{"storage":"5Gi"}}` | Resource requests for the ephemeral PVC. | +| dynamicPlugins.volume.ephemeral.storageClassName | string | `""` | StorageClass for the ephemeral volume. When empty, uses global.defaultStorageClass or the cluster default. | +| dynamicPlugins.volume.pvc | object | `{"claimName":""}` | Raw Kubernetes persistentVolumeClaim volume spec. Used when type is "pvc". | +| dynamicPlugins.volume.type | string | `"ephemeral"` | Volume type: "ephemeral" (auto-provisioned PVC per pod), "emptyDir" (scratch space, lost on pod restart), or "pvc" (pre-existing PersistentVolumeClaim). | +| envFromOverride | list | `[]` | Override the container envFrom entirely. When set, extraEnvFrom is ignored. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | +| envOverride | list | `[]` | Override the container environment variables entirely. When set, system env vars (BACKEND_SECRET, DB credentials, etc.) are NOT added automatically. | +| externalDatabase | object | `{"existingSecretRef":{"key":"password","name":""},"host":"","port":5432,"user":"postgres"}` | External database connection. Used when postgresql.enabled is false. See docs/external-db.md for TLS setup and privilege requirements. When both postgresql.enabled and externalDatabase.host are false/empty, the chart renders no database env vars (BYO configuration via extraEnv or appConfig). | +| externalDatabase.existingSecretRef | object | `{"key":"password","name":""}` | Reference to an existing Secret containing the database password. | +| externalDatabase.existingSecretRef.key | string | `"password"` | Key within the Secret that holds the password. | +| externalDatabase.existingSecretRef.name | string | `""` | Name of the existing Secret. | +| externalDatabase.host | string | `""` | External database hostname. | +| externalDatabase.port | int | `5432` | External database port. | +| externalDatabase.user | string | `"postgres"` | External database user. | +| extraAppConfig | list | `[]` | Additional app-config files from existing ConfigMaps. | +| extraArgs | list | `[]` | Extra arguments appended after the system config flags. | +| extraContainers | list | `[]` | Additional sidecar containers. These are ADDED to system containers (e.g. Lightspeed Core sidecar), never replacing them. | +| extraEnv | list | `[]` | Extra environment variables appended after the system env vars. | +| extraEnvFrom | list | `[]` | Extra envFrom entries appended to the container. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | +| extraInitContainers | list | `[]` | Additional init containers. These are ADDED after system init containers (install-dynamic-plugins, Intelligent Assistant RAG init), never replacing them. | +| extraVolumeMounts | list | `[]` | Additional volume mounts to add to the main container. These are ADDED to system-required mounts, never replacing them. | +| extraVolumes | list | `[]` | Additional volumes to add to the pod. These are ADDED to system-required volumes (dynamic-plugins-root, temp, npmcacache, etc.), never replacing them. | +| fullnameOverride | string | `""` | Override the full resource name. | +| global | object | `{"defaultStorageClass":"","imagePullSecrets":[],"imageRegistry":""}` | Global parameters shared with bitnami subcharts (postgresql, common). | +| global.defaultStorageClass | string | `""` | Global default StorageClass for PVCs. | +| global.imagePullSecrets | list | `[]` | Global Docker registry secret names. | +| global.imageRegistry | string | `""` | Global Docker image registry. Overrides per-image registries for all containers. | +| host | string | `""` | Custom hostname. Overrides openshift.clusterRouterBase for URL generation. | +| hostAliases | list | `[]` | Host aliases for /etc/hosts entries. | +| httpRoute | object | `{"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}` | Gateway API HTTPRoute configuration. | +| httpRoute.labels | object | `{}` | Additional labels for the HTTPRoute resource. | +| image | object | `{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"rhdh-community/rhdh","tag":"next"}` | Container image configuration. | +| image.digest | string | `""` | Overrides the image tag with an image digest. | +| imagePullSecrets | list | `[]` | Secrets for pulling images from private registries (merged with global.imagePullSecrets). | +| ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | Kubernetes Ingress configuration. | +| intelligentAssistant | object | `{"config":{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}},"core":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"enabled":true,"existingSecret":"","plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}],"ragInit":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | Built-in Intelligent Assistant feature configuration. | +| intelligentAssistant.config | object | `{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}}` | Configuration files mounted into the sidecar. By default, the chart creates ConfigMaps from bundled source files. Set existingConfigMap to use a pre-existing ConfigMap instead. | +| intelligentAssistant.config.profile | object | `{"existingConfigMap":{"key":"","name":""}}` | Python profile with prompt templates (rhdh-profile.py). | +| intelligentAssistant.config.profile.existingConfigMap | object | Created from bundled rhdh-profile.py | Use an existing ConfigMap instead of the bundled default. | +| intelligentAssistant.config.profile.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (rhdh-profile.py) if not set. | +| intelligentAssistant.config.profile.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | +| intelligentAssistant.config.server | object | `{"existingConfigMap":{"key":"","name":""}}` | Llama Stack server configuration (config.yaml). | +| intelligentAssistant.config.server.existingConfigMap | object | Created from bundled config.yaml | Use an existing ConfigMap instead of the bundled default. | +| intelligentAssistant.config.server.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (config.yaml) if not set. | +| intelligentAssistant.config.server.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | +| intelligentAssistant.config.stack | object | `{"existingConfigMap":{"key":"","name":""}}` | Lightspeed Core service configuration (lightspeed-stack.yaml). | +| intelligentAssistant.config.stack.existingConfigMap | object | Created from bundled lightspeed-stack.yaml | Use an existing ConfigMap instead of the bundled default. | +| intelligentAssistant.config.stack.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (lightspeed-stack.yaml) if not set. | +| intelligentAssistant.config.stack.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | +| intelligentAssistant.core | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | Lightspeed Core sidecar container. | +| intelligentAssistant.core.argsOverride | list | `[]` | Override the container's default args. Leave empty to use the image defaults. | +| intelligentAssistant.core.commandOverride | list | `[]` | Override the container's default command. Leave empty to use the image entrypoint. | +| intelligentAssistant.core.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | +| intelligentAssistant.existingSecret | string | `""` | Name of an existing Secret to inject via envFrom into the lightspeed-core container. If empty, no secret is mounted. Expected keys (all optional — only set the ones for the providers you use): ENABLE_VLLM, VLLM_URL, VLLM_API_KEY, VLLM_MAX_TOKENS, VLLM_TLS_VERIFY, ENABLE_OPENAI, OPENAI_API_KEY, ENABLE_VERTEX_AI, VERTEX_AI_PROJECT, VERTEX_AI_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, ENABLE_OLLAMA, OLLAMA_URL, ENABLE_VALIDATION, VALIDATION_PROVIDER, VALIDATION_MODEL_NAME, LLAMA_STACK_LOGGING See files/intelligent-assistant/secret.example.yaml for a reference template. | +| intelligentAssistant.plugins | list | `[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}]` | Intelligent Assistant dynamic plugin packages. | +| intelligentAssistant.ragInit | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | RAG data bootstrap init container. | +| intelligentAssistant.ragInit.argsOverride | list | `[]` | Override the default arguments for the RAG init container. | +| intelligentAssistant.ragInit.commandOverride | list | `[]` | Override the default command for the RAG init container. | +| intelligentAssistant.ragInit.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | +| intelligentAssistant.runtimeVolume | object | `{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}` | Writable scratch volume for the sidecar (/tmp). | +| intelligentAssistant.runtimeVolume.type | string | `"emptyDir"` | Volume type: "emptyDir" or "persistentVolumeClaim". | +| livenessProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}` | Liveness probe configuration. | +| metrics | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}` | Prometheus metrics configuration. | +| nameOverride | string | `""` | Override the chart name used in resource naming. | +| nodeSelector | object | `{}` | Node labels for pod assignment. | +| openshift | object | `{"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}` | OpenShift-specific configuration. | +| openshift.clusterRouterBase | string | `"apps.example.com"` | Cluster router base domain used to auto-generate the hostname. | +| openshift.route | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | OpenShift Route configuration. | +| orchestrator | object | `{"enabled":false,"plugins":[{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}],"serverlessLogicOperator":{"enabled":true},"serverlessOperator":{"enabled":true},"sonataflowPlatform":{"dataIndex":{"image":{"digest":"","registry":"","repository":"","tag":""}},"dbCreationJob":{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null},"eventing":{"broker":{"name":"","namespace":""}},"externalDB":{"existingSecret":"","host":"","name":"","port":""},"jobService":{"image":{"digest":"","registry":"","repository":"","tag":""}},"monitoring":{"enabled":true},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"250m","memory":"64Mi"}}}}` | Orchestrator (Serverless workflows) configuration. | +| orchestrator.sonataflowPlatform.dataIndex | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | SonataFlow Data Index service configuration. | +| orchestrator.sonataflowPlatform.dataIndex.image | object | `{"digest":"","registry":"","repository":"","tag":""}` | Override the Data Index container image. If empty, the operator default is used. | +| orchestrator.sonataflowPlatform.dbCreationJob | object | `{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null}` | Database creation Job configuration. | +| orchestrator.sonataflowPlatform.dbCreationJob.image | object | `{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"}` | Container image for the create-db Job. | +| orchestrator.sonataflowPlatform.externalDB | object | `{"existingSecret":"","host":"","name":"","port":""}` | External database connection. Used when postgresql.enabled is false. | +| orchestrator.sonataflowPlatform.externalDB.existingSecret | string | `""` | Name of a Secret containing POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD keys. | +| orchestrator.sonataflowPlatform.externalDB.host | string | `""` | Database host (used in JDBC URLs). | +| orchestrator.sonataflowPlatform.externalDB.name | string | `""` | Database name to connect to for the CREATE DATABASE command. | +| orchestrator.sonataflowPlatform.externalDB.port | string | `""` | Database port (used in JDBC URLs). | +| orchestrator.sonataflowPlatform.jobService | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | SonataFlow Job Service configuration. | +| orchestrator.sonataflowPlatform.jobService.image | object | `{"digest":"","registry":"","repository":"","tag":""}` | Override the Job Service container image. If empty, the operator default is used. | +| podAnnotations | object | `{}` | Annotations to add to the pod. | +| podDisruptionBudget | object | `{"create":false,"maxUnavailable":1,"minAvailable":""}` | Pod Disruption Budget configuration. | +| podLabels | object | `{}` | Labels to add to the pod. | +| podSecurityContext | object | `{}` | Pod-level security context. | +| postgresql | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"serviceBindings":{"enabled":true}}` | Built-in PostgreSQL database (bitnami subchart). | +| preInitContainers | list | `[]` | Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). | +| readinessProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}` | Readiness probe configuration. | +| replicaCount | int | `1` | Number of desired pods. | +| resources | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}` | Resource requests and limits for the main RHDH container. | +| revisionHistoryLimit | int | `10` | Number of old ReplicaSets to retain. | +| service | object | `{"annotations":{},"clusterIP":"","externalTrafficPolicy":"","extraPorts":[{"name":"http-metrics","port":9464,"targetPort":9464}],"ipFamilies":[],"ipFamilyPolicy":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePort":"","port":7007,"sessionAffinity":"","type":"ClusterIP"}` | Service configuration. | +| service.extraPorts | list | `[{"name":"http-metrics","port":9464,"targetPort":9464}]` | Additional service ports. | +| service.ipFamilies | list | `[]` | IP families for dual-stack networking. | +| service.ipFamilyPolicy | string | `""` | IP family policy for dual-stack networking. | +| service.nodePort | string | `""` | Node port for NodePort/LoadBalancer service types (range 30000-32767). | +| serviceAccount | object | `{"annotations":{},"automount":true,"create":false,"labels":{},"name":""}` | ServiceAccount configuration. | +| serviceAccount.labels | object | `{}` | Additional labels for the ServiceAccount. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | +| startupProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":4}` | Startup probe configuration. Gives the application time to start before liveness/readiness probes kick in. | +| strategy | object | `{}` | Deployment update strategy. | +| test | object | `{"enabled":true,"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"curl/curl","tag":"8.21.0"},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}` | Test pod configuration for `helm test`. | +| tolerations | list | `[]` | Tolerations for pod assignment. | +| topologySpreadConstraints | list | `[]` | Topology spread constraints for pod scheduling. | ## Opinionated RHDH deployment diff --git a/charts/rhdh/README.md.gotmpl b/charts/rhdh/README.md.gotmpl index 8f25764e..8cdc62dd 100644 --- a/charts/rhdh/README.md.gotmpl +++ b/charts/rhdh/README.md.gotmpl @@ -150,9 +150,9 @@ The command removes all the Kubernetes components associated with the chart and ## Upgrading from the backstage chart (RHDH 1.y) -> **Note:** This section is a work in progress. A detailed migration guide will be provided before the GA release of RHDH 2.y. +If you are upgrading from the legacy `backstage` chart (used in RHDH 1.y), the new `redhat-developer-hub` chart is a clean break. The values structure has changed significantly — all `global.*` and `upstream.backstage.*` nesting has been flattened to root-level keys. You cannot pass your old values file directly to the new chart; you must migrate your values first, then `helm upgrade` the release in place. -If you are upgrading from the legacy `backstage` chart (used in RHDH 1.y), the new `redhat-developer-hub` chart is a clean break. The values structure has changed significantly — all `global.*` and `upstream.backstage.*` nesting has been flattened to root-level keys. A `helm upgrade` from the old chart to this one is **not** supported; you will need to perform a fresh install with migrated values. +See the [Migration guide](docs/migration-from-backstage-chart.md) for step-by-step instructions and a complete values mapping reference. {{ template "chart.requirementsSection" . }} diff --git a/charts/rhdh/docs/migration-from-backstage-chart.md b/charts/rhdh/docs/migration-from-backstage-chart.md new file mode 100644 index 00000000..9b3e367b --- /dev/null +++ b/charts/rhdh/docs/migration-from-backstage-chart.md @@ -0,0 +1,241 @@ +# Migration guide: `backstage` chart (RHDH 1.y) to `redhat-developer-hub` chart (RHDH 2.y) + +The RHDH 2.y `redhat-developer-hub` chart is a clean break from the 1.y `backstage` chart. +The old chart delegated most Kubernetes resource creation to an embedded upstream +[Backstage subchart](https://github.com/backstage/charts), so values lived under +`upstream.backstage.*` and `global.*`. The new chart owns all templates directly and +flattens configuration to root-level keys. + +Because the values structure has changed, you cannot pass your old values file +directly to the new chart. You must migrate your values first, then +`helm upgrade` the release in place. Tooling (a migration script or AI skill) +to automate the values conversion is planned in the near future. + +## Migration steps + +1. Export your current user-supplied values (this returns only the overrides you + provided, not the chart defaults): + + ```bash + helm get values -o yaml > old-values.yaml + ``` + + > **Tip:** Add `-a` to include all computed values (user-supplied + chart + > defaults). This can be useful as a reference, but the file without `-a` is + > what you need to migrate. + +2. Create a new values file using the mapping tables below to translate each + setting to its new path. + +3. Upgrade the existing release in place with the new chart and migrated values: + + ```bash + helm upgrade redhat-developer/redhat-developer-hub -f new-values.yaml + ``` + +4. Verify the deployment is healthy. + +## Key structural changes + +| Aspect | Old chart (`backstage`) | New chart (`redhat-developer-hub`) | +|--------|------------------------|------------------------------------| +| Chart name | `backstage` | `redhat-developer-hub` | +| Template ownership | Delegates to upstream Backstage subchart | Owns all templates directly | +| System volumes/mounts/env | User had to list them in full under `upstream.backstage.extraVolumes`, `extraVolumeMounts`, `extraEnvVars` | Hardcoded in templates; `extra*` keys only add user values | +| Init containers | User had to specify the full init container array | System init containers are managed; use `preInitContainers` / `extraInitContainers` to add custom ones | +| Database env vars | `POSTGRESQL_ADMIN_PASSWORD` injected manually via `upstream.backstage.extraEnvVars` | `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD` auto-injected | +| Lightspeed | `global.lightspeed.*` | Rebranded to `intelligentAssistant.*` | +| OpenShift Route | `route.*` | `openshift.route.*` | + +## Values mapping reference + +### Container image + +| Old path | New path | +|----------|----------| +| `upstream.backstage.image.registry` | `image.registry` | +| `upstream.backstage.image.repository` | `image.repository` | +| `upstream.backstage.image.tag` | `image.tag` | +| `upstream.backstage.image.pullPolicy` | `image.pullPolicy` | + +### Global parameters + +| Old path | New path | Notes | +|----------|----------|-------| +| `global.clusterRouterBase` | `openshift.clusterRouterBase` | | +| `global.host` | `host` | Promoted to root | +| `global.imagePullSecrets` | `global.imagePullSecrets` | Unchanged (used by bitnami subcharts) | + +### App config + +| Old path | New path | Notes | +|----------|----------|-------| +| `upstream.backstage.appConfig` | `appConfig` | Entire tree flattened to root | +| `upstream.backstage.appConfig.backend.database.connection.password` | `appConfig.backend.database.connection.password` | Env var changed from `POSTGRESQL_ADMIN_PASSWORD` to `POSTGRES_PASSWORD` | +| `upstream.backstage.appConfig.backend.database.connection.user` | `appConfig.backend.database.connection.user` | Env var changed from hardcoded `postgres` to `POSTGRES_USER` | + +### Authentication + +| Old path | New path | Notes | +|----------|----------|-------| +| `global.auth.backend.enabled` | `auth.backend.enabled` | | +| `global.auth.backend.existingSecret` | `auth.backend.existingSecretRef.name` | Now an object with `name` and `key` | +| _(none)_ | `auth.backend.existingSecretRef.key` | Defaults to `backend-secret` | +| `global.auth.backend.value` | `auth.backend.value` | | + +### Dynamic plugins + +| Old path | New path | Notes | +|----------|----------|-------| +| `global.dynamic.includes` | `dynamicPlugins.includes` | | +| `global.dynamic.plugins` | `dynamicPlugins.plugins` | | +| `upstream.backstage.extraVolumes` _(dynamic-plugins-root)_ | `dynamicPlugins.volume.*` | Declarative config replaces raw volume spec | +| `upstream.backstage.initContainers[0].resources` | `dynamicPlugins.initContainer.resources` | | +| `upstream.backstage.initContainers[0].securityContext` | `dynamicPlugins.initContainer.securityContext` | | +| `upstream.backstage.initContainers[0].env` | `dynamicPlugins.initContainer.extraEnv` | System env vars auto-injected | + +### Container command, args, and env + +| Old path | New path | Notes | +|----------|----------|-------| +| `upstream.backstage.command` | `commandOverride` | | +| `upstream.backstage.args` | `argsOverride` | System `--config` flags now auto-injected | +| `upstream.backstage.extraEnvVars` | `extraEnv` | System env vars auto-injected; only add custom ones | + +### Volumes and mounts + +| Old path | New path | Notes | +|----------|----------|-------| +| `upstream.backstage.extraVolumes` | `extraVolumes` | Only user additions; system volumes are hardcoded | +| `upstream.backstage.extraVolumeMounts` | `extraVolumeMounts` | Only user additions; system mounts are hardcoded | + +### Init containers and sidecars + +| Old path | New path | Notes | +|----------|----------|-------| +| `upstream.backstage.initContainers` | _(managed by chart)_ | System init containers no longer user-configurable | +| _(none)_ | `preInitContainers` | Runs **before** system init containers | +| _(none)_ | `extraInitContainers` | Runs **after** system init containers | +| _(none)_ | `extraContainers` | Additional sidecars | + +### Security contexts and resources + +| Old path | New path | +|----------|----------| +| `upstream.backstage.containerSecurityContext` | `containerSecurityContext` | +| `upstream.backstage.resources` | `resources` | + +### Probes + +| Old path | New path | +|----------|----------| +| `upstream.backstage.startupProbe` | `startupProbe` | +| `upstream.backstage.readinessProbe` | `readinessProbe` | +| `upstream.backstage.livenessProbe` | `livenessProbe` | + +### Service + +| Old path | New path | +|----------|----------| +| `upstream.service.extraPorts` | `service.extraPorts` | + +### OpenShift Route + +| Old path | New path | +|----------|----------| +| `route.enabled` | `openshift.route.enabled` | +| `route.annotations` | `openshift.route.annotations` | +| `route.host` | `openshift.route.host` | +| `route.path` | `openshift.route.path` | +| `route.wildcardPolicy` | `openshift.route.wildcardPolicy` | +| `route.tls.enabled` | `openshift.route.tls.enabled` | +| `route.tls.termination` | `openshift.route.tls.termination` | +| `route.tls.certificate` | `openshift.route.tls.certificate` | +| `route.tls.key` | `openshift.route.tls.key` | +| `route.tls.caCertificate` | `openshift.route.tls.caCertificate` | +| `route.tls.destinationCACertificate` | `openshift.route.tls.destinationCACertificate` | +| `route.tls.insecureEdgeTerminationPolicy` | `openshift.route.tls.insecureEdgeTerminationPolicy` | + +### Ingress + +| Old path | New path | Notes | +|----------|----------|-------| +| `upstream.ingress.enabled` | `ingress.enabled` | | +| `upstream.ingress.host` | `ingress.hosts[].host` | Now an array of host objects | + +### Catalog index + +| Old path | New path | +|----------|----------| +| `global.catalogIndex.image.registry` | `catalogIndex.image.registry` | +| `global.catalogIndex.image.repository` | `catalogIndex.image.repository` | +| `global.catalogIndex.image.tag` | `catalogIndex.image.tag` | +| `global.catalogIndex.extraImages` | `catalogIndex.extraImages` | + +### PostgreSQL (bitnami subchart) + +| Old path | New path | +|----------|----------| +| `upstream.postgresql.enabled` | `postgresql.enabled` | +| `upstream.postgresql.postgresqlDataDir` | `postgresql.postgresqlDataDir` | +| `upstream.postgresql.serviceBindings.enabled` | `postgresql.serviceBindings.enabled` | +| `upstream.postgresql.image.*` | `postgresql.image.*` | +| `upstream.postgresql.auth.*` | `postgresql.auth.*` | +| `upstream.postgresql.primary.*` | `postgresql.primary.*` | + +### Metrics / monitoring + +| Old path | New path | +|----------|----------| +| `upstream.metrics.serviceMonitor.enabled` | `metrics.serviceMonitor.enabled` | +| `upstream.metrics.serviceMonitor.path` | `metrics.serviceMonitor.path` | +| `upstream.metrics.serviceMonitor.port` | `metrics.serviceMonitor.port` | + +### Intelligent Assistant (formerly Lightspeed) + +| Old path | New path | Notes | +|----------|----------|-------| +| `global.lightspeed.enabled` | `intelligentAssistant.enabled` | Default changed from `false` to `true` | +| `global.lightspeed.plugins` | `intelligentAssistant.plugins` | Plugin format changed from OCI to `ref://` | +| `global.lightspeed.sidecar.image` | `intelligentAssistant.core.image.*` | Single string split into `registry`/`repository`/`tag` | +| `global.lightspeed.sidecar.resources` | `intelligentAssistant.core.resources` | | +| `global.lightspeed.sidecar.securityContext` | `intelligentAssistant.core.securityContext` | | +| `global.lightspeed.sidecar.command` | `intelligentAssistant.core.commandOverride` | | +| `global.lightspeed.sidecar.args` | `intelligentAssistant.core.argsOverride` | | +| `global.lightspeed.sidecar.env` | `intelligentAssistant.core.extraEnv` | | +| `global.lightspeed.initContainer.image` | `intelligentAssistant.ragInit.image.*` | Single string split into `registry`/`repository`/`tag` | +| `global.lightspeed.initContainer.resources` | `intelligentAssistant.ragInit.resources` | | +| `global.lightspeed.initContainer.securityContext` | `intelligentAssistant.ragInit.securityContext` | | +| `global.lightspeed.initContainer.command` | `intelligentAssistant.ragInit.commandOverride` | | +| `global.lightspeed.initContainer.args` | `intelligentAssistant.ragInit.argsOverride` | | +| `global.lightspeed.initContainer.env` | `intelligentAssistant.ragInit.extraEnv` | | +| `global.lightspeed.runtimeVolume.type` | `intelligentAssistant.runtimeVolume.type` | | +| `global.lightspeed.runtimeVolume.emptyDir` | `intelligentAssistant.runtimeVolume.emptyDir` | | +| `global.lightspeed.runtimeVolume.persistentVolumeClaim` | `intelligentAssistant.runtimeVolume.persistentVolumeClaim` | | +| `global.lightspeed.configMaps` | `intelligentAssistant.config.{stack,server,profile}.existingConfigMap` | Array replaced with structured per-file config | +| `global.lightspeed.secret.create` / `.name` | `intelligentAssistant.existingSecret` | Simplified to a secret name string | + +### Orchestrator + +| Old path | New path | Notes | +|----------|----------|-------| +| `orchestrator.enabled` | `orchestrator.enabled` | | +| `orchestrator.plugins` | `orchestrator.plugins` | | +| `orchestrator.sonataflowPlatform.externalDBsecretRef` | `orchestrator.sonataflowPlatform.externalDB.existingSecret` | Restructured | +| `orchestrator.sonataflowPlatform.externalDBName` | `orchestrator.sonataflowPlatform.externalDB.name` | | +| `orchestrator.sonataflowPlatform.externalDBHost` | `orchestrator.sonataflowPlatform.externalDB.host` | | +| `orchestrator.sonataflowPlatform.externalDBPort` | `orchestrator.sonataflowPlatform.externalDB.port` | | +| `orchestrator.sonataflowPlatform.initContainerImage` | `orchestrator.sonataflowPlatform.dbCreationJob.image.*` | Single string split into structured image fields | +| `orchestrator.sonataflowPlatform.createDBJobImage` | `orchestrator.sonataflowPlatform.dbCreationJob.image.*` | Merged with `initContainerImage` | +| `orchestrator.sonataflowPlatform.dataIndexImage` | `orchestrator.sonataflowPlatform.dataIndex.image.*` | Single string split into structured image fields | +| `orchestrator.sonataflowPlatform.jobServiceImage` | `orchestrator.sonataflowPlatform.jobService.image.*` | Single string split into structured image fields | + +### Test pod + +| Old path | New path | Notes | +|----------|----------|-------| +| `test.enabled` | `test.enabled` | | +| `test.image.registry` | `test.image.registry` | | +| `test.image.repository` | `test.image.repository` | | +| `test.image.tag` | `test.image.tag` | Default changed from `latest` to a pinned version | +| `test.injectTestNpmrcSecret` | _(removed)_ | No longer needed | From 010b9a49784bc4311e2237cee5d21a9b0c9c0a7c Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 2 Sep 2026 18:02:17 +0200 Subject: [PATCH 2/5] docs: improve migration guide wording and instructions - Use GitHub alert syntax for the important notice - Guide users to locate their existing values file first - Use helm upgrade --install to handle both existing and new releases Ref: RHIDP-16514 --- .../docs/migration-from-backstage-chart.md | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/charts/rhdh/docs/migration-from-backstage-chart.md b/charts/rhdh/docs/migration-from-backstage-chart.md index 9b3e367b..0c4f1503 100644 --- a/charts/rhdh/docs/migration-from-backstage-chart.md +++ b/charts/rhdh/docs/migration-from-backstage-chart.md @@ -1,36 +1,34 @@ # Migration guide: `backstage` chart (RHDH 1.y) to `redhat-developer-hub` chart (RHDH 2.y) -The RHDH 2.y `redhat-developer-hub` chart is a clean break from the 1.y `backstage` chart. +This `redhat-developer-hub` chart is a clean break from the 1.y `backstage` chart. The old chart delegated most Kubernetes resource creation to an embedded upstream [Backstage subchart](https://github.com/backstage/charts), so values lived under `upstream.backstage.*` and `global.*`. The new chart owns all templates directly and flattens configuration to root-level keys. -Because the values structure has changed, you cannot pass your old values file -directly to the new chart. You must migrate your values first, then -`helm upgrade` the release in place. Tooling (a migration script or AI skill) -to automate the values conversion is planned in the near future. +> [!IMPORTANT] +> Because the values structure has changed, you cannot pass your old values file +> directly to the new chart. You must migrate your values first, then +> `helm upgrade` the release in place. Tooling (a migration script or AI skill) +> to automate the values conversion is planned in the near future. ## Migration steps -1. Export your current user-supplied values (this returns only the overrides you - provided, not the chart defaults): +1. Locate your existing values file (typically stored in your Git repo or + locally). If you don't have it, you can export the user-supplied overrides + from a running release: ```bash helm get values -o yaml > old-values.yaml ``` - > **Tip:** Add `-a` to include all computed values (user-supplied + chart - > defaults). This can be useful as a reference, but the file without `-a` is - > what you need to migrate. - 2. Create a new values file using the mapping tables below to translate each setting to its new path. 3. Upgrade the existing release in place with the new chart and migrated values: ```bash - helm upgrade redhat-developer/redhat-developer-hub -f new-values.yaml + helm upgrade --install redhat-developer/redhat-developer-hub -f new-values.yaml ``` 4. Verify the deployment is healthy. From 6ebc2671150b3677241e692ed74eac7cd6b5afaf Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 2 Sep 2026 18:08:06 +0200 Subject: [PATCH 3/5] docs: highlight image digest fields and global.imageRegistry in migration guide Ref: RHIDP-16514 --- charts/rhdh/README.md | 275 +++++++++--------- .../docs/migration-from-backstage-chart.md | 2 + 2 files changed, 140 insertions(+), 137 deletions(-) diff --git a/charts/rhdh/README.md b/charts/rhdh/README.md index d1188e4d..1b001148 100644 --- a/charts/rhdh/README.md +++ b/charts/rhdh/README.md @@ -1,3 +1,4 @@ + # RHDH Helm Chart for OpenShift and Kubernetes ![Version: 2.0.1](https://img.shields.io/badge/Version-2.0.1-informational?style=flat-square) @@ -173,143 +174,143 @@ Kubernetes: `>= 1.31.0-0` ## Values -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | Affinity rules for pod assignment. | -| appConfig | object | Default config with base URLs, CORS, database connection, and backend auth. | Inline Backstage app-config YAML. Rendered into a ConfigMap and mounted as app-config-from-configmap.yaml. | -| argsOverride | list | `[]` | Override the container arguments entirely. When set, system config arguments are NOT added automatically; you must include them yourself. | -| auth | object | `{"backend":{"enabled":true,"existingSecretRef":{"key":"backend-secret","name":""},"value":""}}` | Service-to-service authentication configuration. | -| auth.backend.enabled | bool | `true` | Enable backend service-to-service authentication. Generates a random secret unless existingSecretRef is set or value is provided. Disable if you inject the secret via extraEnvFrom or extraEnv instead. | -| auth.backend.existingSecretRef | object | `{"key":"backend-secret","name":""}` | Reference an existing Secret instead of generating one. When not set, the chart auto-generates a random token. | -| auth.backend.existingSecretRef.key | string | `"backend-secret"` | Key within the Secret that holds the backend auth token. | -| auth.backend.existingSecretRef.name | string | `""` | Name of the existing Secret. When empty, the chart generates one. | -| auth.backend.value | string | `""` | Use a specific value instead of generating one. | -| autoscaling | object | `{"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Horizontal Pod Autoscaler configuration. | -| catalogIndex | object | `{"extraImages":[],"image":{"digest":"","registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"next"}}` | Catalog index configuration for automatic plugin discovery. | -| catalogIndex.extraImages | list | `[]` | Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include `registry`, `repository`, and `tag` fields; `name` and `digest` are optional. Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). | -| commandOverride | list | `[]` | Override the container command. | -| commonAnnotations | object | `{}` | Annotations applied to ALL chart resources. | -| commonLabels | object | `{}` | Labels applied to ALL chart resources. | -| containerSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for the main RHDH container (not the Lightspeed Core sidecar or init containers). | -| deploymentAnnotations | object | `{}` | Annotations for the Deployment resource (not the pod). | -| dynamicPlugins | object | `{"includes":["dynamic-plugins.default.yaml"],"initContainer":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}},"maxEntrySize":40000000,"plugins":[],"volume":{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}}` | Dynamic plugin system configuration. | -| dynamicPlugins.includes | list | `["dynamic-plugins.default.yaml"]` | Array of YAML files listing dynamic plugins to include. Relative paths are resolved from the working directory of the initContainer (`/opt/app-root/src`). | -| dynamicPlugins.initContainer | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}}` | Configuration for the install-dynamic-plugins init container. | -| dynamicPlugins.initContainer.argsOverride | list | `[]` | Override the default arguments. Leave empty to use the defaults. | -| dynamicPlugins.initContainer.commandOverride | list | `[]` | Override the default command. Leave empty to use the default (./install-dynamic-plugins.sh /dynamic-plugins-root). | -| dynamicPlugins.initContainer.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | -| dynamicPlugins.initContainer.extraEnv | list | `[]` | Extra environment variables appended after the system env vars (NPM_CONFIG_USERCONFIG, MAX_ENTRY_SIZE, CATALOG_INDEX_IMAGE, etc.). | -| dynamicPlugins.initContainer.extraVolumeMounts | list | `[]` | Additional volume mounts appended after the system mounts (dynamic-plugins-root, npmrc, registry-auth, npmcacache, extensions-catalog, temp). | -| dynamicPlugins.initContainer.resources | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | Resource requests and limits. | -| dynamicPlugins.initContainer.securityContext | object | Same as containerSecurityContext | Security context for the init container. | -| dynamicPlugins.maxEntrySize | int | `40000000` | Maximum uncompressed size (in bytes) of a single dynamic plugin entry. | -| dynamicPlugins.plugins | list | `[]` | List of dynamic plugins. Every item defines the plugin `package` as a NPM package spec or OCI reference. | -| dynamicPlugins.volume | object | `{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}` | Volume configuration for the dynamic plugins root directory. | -| dynamicPlugins.volume.emptyDir | object | `{}` | Raw Kubernetes emptyDir volume spec. Used when type is "emptyDir". | -| dynamicPlugins.volume.ephemeral | object | `{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}` | Ephemeral volume configuration. Used when type is "ephemeral". The chart builds the full ephemeral.volumeClaimTemplate.spec from these fields. | -| dynamicPlugins.volume.ephemeral.accessModes | list | `["ReadWriteOnce"]` | Access modes for the ephemeral PVC. | -| dynamicPlugins.volume.ephemeral.resources | object | `{"requests":{"storage":"5Gi"}}` | Resource requests for the ephemeral PVC. | -| dynamicPlugins.volume.ephemeral.storageClassName | string | `""` | StorageClass for the ephemeral volume. When empty, uses global.defaultStorageClass or the cluster default. | -| dynamicPlugins.volume.pvc | object | `{"claimName":""}` | Raw Kubernetes persistentVolumeClaim volume spec. Used when type is "pvc". | -| dynamicPlugins.volume.type | string | `"ephemeral"` | Volume type: "ephemeral" (auto-provisioned PVC per pod), "emptyDir" (scratch space, lost on pod restart), or "pvc" (pre-existing PersistentVolumeClaim). | -| envFromOverride | list | `[]` | Override the container envFrom entirely. When set, extraEnvFrom is ignored. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | -| envOverride | list | `[]` | Override the container environment variables entirely. When set, system env vars (BACKEND_SECRET, DB credentials, etc.) are NOT added automatically. | -| externalDatabase | object | `{"existingSecretRef":{"key":"password","name":""},"host":"","port":5432,"user":"postgres"}` | External database connection. Used when postgresql.enabled is false. See docs/external-db.md for TLS setup and privilege requirements. When both postgresql.enabled and externalDatabase.host are false/empty, the chart renders no database env vars (BYO configuration via extraEnv or appConfig). | -| externalDatabase.existingSecretRef | object | `{"key":"password","name":""}` | Reference to an existing Secret containing the database password. | -| externalDatabase.existingSecretRef.key | string | `"password"` | Key within the Secret that holds the password. | -| externalDatabase.existingSecretRef.name | string | `""` | Name of the existing Secret. | -| externalDatabase.host | string | `""` | External database hostname. | -| externalDatabase.port | int | `5432` | External database port. | -| externalDatabase.user | string | `"postgres"` | External database user. | -| extraAppConfig | list | `[]` | Additional app-config files from existing ConfigMaps. | -| extraArgs | list | `[]` | Extra arguments appended after the system config flags. | -| extraContainers | list | `[]` | Additional sidecar containers. These are ADDED to system containers (e.g. Lightspeed Core sidecar), never replacing them. | -| extraEnv | list | `[]` | Extra environment variables appended after the system env vars. | -| extraEnvFrom | list | `[]` | Extra envFrom entries appended to the container. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | -| extraInitContainers | list | `[]` | Additional init containers. These are ADDED after system init containers (install-dynamic-plugins, Intelligent Assistant RAG init), never replacing them. | -| extraVolumeMounts | list | `[]` | Additional volume mounts to add to the main container. These are ADDED to system-required mounts, never replacing them. | -| extraVolumes | list | `[]` | Additional volumes to add to the pod. These are ADDED to system-required volumes (dynamic-plugins-root, temp, npmcacache, etc.), never replacing them. | -| fullnameOverride | string | `""` | Override the full resource name. | -| global | object | `{"defaultStorageClass":"","imagePullSecrets":[],"imageRegistry":""}` | Global parameters shared with bitnami subcharts (postgresql, common). | -| global.defaultStorageClass | string | `""` | Global default StorageClass for PVCs. | -| global.imagePullSecrets | list | `[]` | Global Docker registry secret names. | -| global.imageRegistry | string | `""` | Global Docker image registry. Overrides per-image registries for all containers. | -| host | string | `""` | Custom hostname. Overrides openshift.clusterRouterBase for URL generation. | -| hostAliases | list | `[]` | Host aliases for /etc/hosts entries. | -| httpRoute | object | `{"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}` | Gateway API HTTPRoute configuration. | -| httpRoute.labels | object | `{}` | Additional labels for the HTTPRoute resource. | -| image | object | `{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"rhdh-community/rhdh","tag":"next"}` | Container image configuration. | -| image.digest | string | `""` | Overrides the image tag with an image digest. | -| imagePullSecrets | list | `[]` | Secrets for pulling images from private registries (merged with global.imagePullSecrets). | -| ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | Kubernetes Ingress configuration. | -| intelligentAssistant | object | `{"config":{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}},"core":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"enabled":true,"existingSecret":"","plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}],"ragInit":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | Built-in Intelligent Assistant feature configuration. | -| intelligentAssistant.config | object | `{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}}` | Configuration files mounted into the sidecar. By default, the chart creates ConfigMaps from bundled source files. Set existingConfigMap to use a pre-existing ConfigMap instead. | -| intelligentAssistant.config.profile | object | `{"existingConfigMap":{"key":"","name":""}}` | Python profile with prompt templates (rhdh-profile.py). | -| intelligentAssistant.config.profile.existingConfigMap | object | Created from bundled rhdh-profile.py | Use an existing ConfigMap instead of the bundled default. | -| intelligentAssistant.config.profile.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (rhdh-profile.py) if not set. | -| intelligentAssistant.config.profile.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | -| intelligentAssistant.config.server | object | `{"existingConfigMap":{"key":"","name":""}}` | Llama Stack server configuration (config.yaml). | -| intelligentAssistant.config.server.existingConfigMap | object | Created from bundled config.yaml | Use an existing ConfigMap instead of the bundled default. | -| intelligentAssistant.config.server.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (config.yaml) if not set. | -| intelligentAssistant.config.server.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | -| intelligentAssistant.config.stack | object | `{"existingConfigMap":{"key":"","name":""}}` | Lightspeed Core service configuration (lightspeed-stack.yaml). | -| intelligentAssistant.config.stack.existingConfigMap | object | Created from bundled lightspeed-stack.yaml | Use an existing ConfigMap instead of the bundled default. | -| intelligentAssistant.config.stack.existingConfigMap.key | string | `""` | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (lightspeed-stack.yaml) if not set. | -| intelligentAssistant.config.stack.existingConfigMap.name | string | `""` | Name of the existing ConfigMap. | -| intelligentAssistant.core | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | Lightspeed Core sidecar container. | -| intelligentAssistant.core.argsOverride | list | `[]` | Override the container's default args. Leave empty to use the image defaults. | -| intelligentAssistant.core.commandOverride | list | `[]` | Override the container's default command. Leave empty to use the image entrypoint. | -| intelligentAssistant.core.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | -| intelligentAssistant.existingSecret | string | `""` | Name of an existing Secret to inject via envFrom into the lightspeed-core container. If empty, no secret is mounted. Expected keys (all optional — only set the ones for the providers you use): ENABLE_VLLM, VLLM_URL, VLLM_API_KEY, VLLM_MAX_TOKENS, VLLM_TLS_VERIFY, ENABLE_OPENAI, OPENAI_API_KEY, ENABLE_VERTEX_AI, VERTEX_AI_PROJECT, VERTEX_AI_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, ENABLE_OLLAMA, OLLAMA_URL, ENABLE_VALIDATION, VALIDATION_PROVIDER, VALIDATION_MODEL_NAME, LLAMA_STACK_LOGGING See files/intelligent-assistant/secret.example.yaml for a reference template. | -| intelligentAssistant.plugins | list | `[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}]` | Intelligent Assistant dynamic plugin packages. | -| intelligentAssistant.ragInit | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | RAG data bootstrap init container. | -| intelligentAssistant.ragInit.argsOverride | list | `[]` | Override the default arguments for the RAG init container. | -| intelligentAssistant.ragInit.commandOverride | list | `[]` | Override the default command for the RAG init container. | -| intelligentAssistant.ragInit.extraArgs | list | `[]` | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | -| intelligentAssistant.runtimeVolume | object | `{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}` | Writable scratch volume for the sidecar (/tmp). | -| intelligentAssistant.runtimeVolume.type | string | `"emptyDir"` | Volume type: "emptyDir" or "persistentVolumeClaim". | -| livenessProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}` | Liveness probe configuration. | -| metrics | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}` | Prometheus metrics configuration. | -| nameOverride | string | `""` | Override the chart name used in resource naming. | -| nodeSelector | object | `{}` | Node labels for pod assignment. | -| openshift | object | `{"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}` | OpenShift-specific configuration. | -| openshift.clusterRouterBase | string | `"apps.example.com"` | Cluster router base domain used to auto-generate the hostname. | -| openshift.route | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | OpenShift Route configuration. | -| orchestrator | object | `{"enabled":false,"plugins":[{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}],"serverlessLogicOperator":{"enabled":true},"serverlessOperator":{"enabled":true},"sonataflowPlatform":{"dataIndex":{"image":{"digest":"","registry":"","repository":"","tag":""}},"dbCreationJob":{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null},"eventing":{"broker":{"name":"","namespace":""}},"externalDB":{"existingSecret":"","host":"","name":"","port":""},"jobService":{"image":{"digest":"","registry":"","repository":"","tag":""}},"monitoring":{"enabled":true},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"250m","memory":"64Mi"}}}}` | Orchestrator (Serverless workflows) configuration. | -| orchestrator.sonataflowPlatform.dataIndex | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | SonataFlow Data Index service configuration. | -| orchestrator.sonataflowPlatform.dataIndex.image | object | `{"digest":"","registry":"","repository":"","tag":""}` | Override the Data Index container image. If empty, the operator default is used. | -| orchestrator.sonataflowPlatform.dbCreationJob | object | `{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null}` | Database creation Job configuration. | -| orchestrator.sonataflowPlatform.dbCreationJob.image | object | `{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"}` | Container image for the create-db Job. | -| orchestrator.sonataflowPlatform.externalDB | object | `{"existingSecret":"","host":"","name":"","port":""}` | External database connection. Used when postgresql.enabled is false. | -| orchestrator.sonataflowPlatform.externalDB.existingSecret | string | `""` | Name of a Secret containing POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD keys. | -| orchestrator.sonataflowPlatform.externalDB.host | string | `""` | Database host (used in JDBC URLs). | -| orchestrator.sonataflowPlatform.externalDB.name | string | `""` | Database name to connect to for the CREATE DATABASE command. | -| orchestrator.sonataflowPlatform.externalDB.port | string | `""` | Database port (used in JDBC URLs). | -| orchestrator.sonataflowPlatform.jobService | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | SonataFlow Job Service configuration. | -| orchestrator.sonataflowPlatform.jobService.image | object | `{"digest":"","registry":"","repository":"","tag":""}` | Override the Job Service container image. If empty, the operator default is used. | -| podAnnotations | object | `{}` | Annotations to add to the pod. | -| podDisruptionBudget | object | `{"create":false,"maxUnavailable":1,"minAvailable":""}` | Pod Disruption Budget configuration. | -| podLabels | object | `{}` | Labels to add to the pod. | -| podSecurityContext | object | `{}` | Pod-level security context. | -| postgresql | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"serviceBindings":{"enabled":true}}` | Built-in PostgreSQL database (bitnami subchart). | -| preInitContainers | list | `[]` | Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). | -| readinessProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}` | Readiness probe configuration. | -| replicaCount | int | `1` | Number of desired pods. | -| resources | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}` | Resource requests and limits for the main RHDH container. | -| revisionHistoryLimit | int | `10` | Number of old ReplicaSets to retain. | -| service | object | `{"annotations":{},"clusterIP":"","externalTrafficPolicy":"","extraPorts":[{"name":"http-metrics","port":9464,"targetPort":9464}],"ipFamilies":[],"ipFamilyPolicy":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePort":"","port":7007,"sessionAffinity":"","type":"ClusterIP"}` | Service configuration. | -| service.extraPorts | list | `[{"name":"http-metrics","port":9464,"targetPort":9464}]` | Additional service ports. | -| service.ipFamilies | list | `[]` | IP families for dual-stack networking. | -| service.ipFamilyPolicy | string | `""` | IP family policy for dual-stack networking. | -| service.nodePort | string | `""` | Node port for NodePort/LoadBalancer service types (range 30000-32767). | -| serviceAccount | object | `{"annotations":{},"automount":true,"create":false,"labels":{},"name":""}` | ServiceAccount configuration. | -| serviceAccount.labels | object | `{}` | Additional labels for the ServiceAccount. | -| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | -| startupProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":4}` | Startup probe configuration. Gives the application time to start before liveness/readiness probes kick in. | -| strategy | object | `{}` | Deployment update strategy. | -| test | object | `{"enabled":true,"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"curl/curl","tag":"8.21.0"},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}` | Test pod configuration for `helm test`. | -| tolerations | list | `[]` | Tolerations for pod assignment. | -| topologySpreadConstraints | list | `[]` | Topology spread constraints for pod scheduling. | +| Key | Description | Type | Default | +|-----|-------------|------|---------| +| affinity | Affinity rules for pod assignment. | object | `{}` | +| appConfig | Inline Backstage app-config YAML. Rendered into a ConfigMap and mounted as app-config-from-configmap.yaml. | object | Default config with base URLs, CORS, database connection, and backend auth. | +| argsOverride | Override the container arguments entirely. When set, system config arguments are NOT added automatically; you must include them yourself. | list | `[]` | +| auth | Service-to-service authentication configuration. | object | `{"backend":{"enabled":true,"existingSecretRef":{"key":"backend-secret","name":""},"value":""}}` | +| auth.backend.enabled | Enable backend service-to-service authentication. Generates a random secret unless existingSecretRef is set or value is provided. Disable if you inject the secret via extraEnvFrom or extraEnv instead. | bool | `true` | +| auth.backend.existingSecretRef | Reference an existing Secret instead of generating one. When not set, the chart auto-generates a random token. | object | `{"key":"backend-secret","name":""}` | +| auth.backend.existingSecretRef.key | Key within the Secret that holds the backend auth token. | string | `"backend-secret"` | +| auth.backend.existingSecretRef.name | Name of the existing Secret. When empty, the chart generates one. | string | `""` | +| auth.backend.value | Use a specific value instead of generating one. | string | `""` | +| autoscaling | Horizontal Pod Autoscaler configuration. | object | `{"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | +| catalogIndex | Catalog index configuration for automatic plugin discovery. | object | `{"extraImages":[],"image":{"digest":"","registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"next"}}` | +| catalogIndex.extraImages | Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include `registry`, `repository`, and `tag` fields; `name` and `digest` are optional. Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). | list | `[]` | +| commandOverride | Override the container command. | list | `[]` | +| commonAnnotations | Annotations applied to ALL chart resources. | object | `{}` | +| commonLabels | Labels applied to ALL chart resources. | object | `{}` | +| containerSecurityContext | Security context for the main RHDH container (not the Lightspeed Core sidecar or init containers). | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | +| deploymentAnnotations | Annotations for the Deployment resource (not the pod). | object | `{}` | +| dynamicPlugins | Dynamic plugin system configuration. | object | `{"includes":["dynamic-plugins.default.yaml"],"initContainer":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}},"maxEntrySize":40000000,"plugins":[],"volume":{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}}` | +| dynamicPlugins.includes | Array of YAML files listing dynamic plugins to include. Relative paths are resolved from the working directory of the initContainer (`/opt/app-root/src`). | list | `["dynamic-plugins.default.yaml"]` | +| dynamicPlugins.initContainer | Configuration for the install-dynamic-plugins init container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}}` | +| dynamicPlugins.initContainer.argsOverride | Override the default arguments. Leave empty to use the defaults. | list | `[]` | +| dynamicPlugins.initContainer.commandOverride | Override the default command. Leave empty to use the default (./install-dynamic-plugins.sh /dynamic-plugins-root). | list | `[]` | +| dynamicPlugins.initContainer.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | +| dynamicPlugins.initContainer.extraEnv | Extra environment variables appended after the system env vars (NPM_CONFIG_USERCONFIG, MAX_ENTRY_SIZE, CATALOG_INDEX_IMAGE, etc.). | list | `[]` | +| dynamicPlugins.initContainer.extraVolumeMounts | Additional volume mounts appended after the system mounts (dynamic-plugins-root, npmrc, registry-auth, npmcacache, extensions-catalog, temp). | list | `[]` | +| dynamicPlugins.initContainer.resources | Resource requests and limits. | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | +| dynamicPlugins.initContainer.securityContext | Security context for the init container. | object | Same as containerSecurityContext | +| dynamicPlugins.maxEntrySize | Maximum uncompressed size (in bytes) of a single dynamic plugin entry. | int | `40000000` | +| dynamicPlugins.plugins | List of dynamic plugins. Every item defines the plugin `package` as a NPM package spec or OCI reference. | list | `[]` | +| dynamicPlugins.volume | Volume configuration for the dynamic plugins root directory. | object | `{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"type":"ephemeral"}` | +| dynamicPlugins.volume.emptyDir | Raw Kubernetes emptyDir volume spec. Used when type is "emptyDir". | object | `{}` | +| dynamicPlugins.volume.ephemeral | Ephemeral volume configuration. Used when type is "ephemeral". The chart builds the full ephemeral.volumeClaimTemplate.spec from these fields. | object | `{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}` | +| dynamicPlugins.volume.ephemeral.accessModes | Access modes for the ephemeral PVC. | list | `["ReadWriteOnce"]` | +| dynamicPlugins.volume.ephemeral.resources | Resource requests for the ephemeral PVC. | object | `{"requests":{"storage":"5Gi"}}` | +| dynamicPlugins.volume.ephemeral.storageClassName | StorageClass for the ephemeral volume. When empty, uses global.defaultStorageClass or the cluster default. | string | `""` | +| dynamicPlugins.volume.pvc | Raw Kubernetes persistentVolumeClaim volume spec. Used when type is "pvc". | object | `{"claimName":""}` | +| dynamicPlugins.volume.type | Volume type: "ephemeral" (auto-provisioned PVC per pod), "emptyDir" (scratch space, lost on pod restart), or "pvc" (pre-existing PersistentVolumeClaim). | string | `"ephemeral"` | +| envFromOverride | Override the container envFrom entirely. When set, extraEnvFrom is ignored. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | list | `[]` | +| envOverride | Override the container environment variables entirely. When set, system env vars (BACKEND_SECRET, DB credentials, etc.) are NOT added automatically. | list | `[]` | +| externalDatabase | External database connection. Used when postgresql.enabled is false. See docs/external-db.md for TLS setup and privilege requirements. When both postgresql.enabled and externalDatabase.host are false/empty, the chart renders no database env vars (BYO configuration via extraEnv or appConfig). | object | `{"existingSecretRef":{"key":"password","name":""},"host":"","port":5432,"user":"postgres"}` | +| externalDatabase.existingSecretRef | Reference to an existing Secret containing the database password. | object | `{"key":"password","name":""}` | +| externalDatabase.existingSecretRef.key | Key within the Secret that holds the password. | string | `"password"` | +| externalDatabase.existingSecretRef.name | Name of the existing Secret. | string | `""` | +| externalDatabase.host | External database hostname. | string | `""` | +| externalDatabase.port | External database port. | int | `5432` | +| externalDatabase.user | External database user. | string | `"postgres"` | +| extraAppConfig | Additional app-config files from existing ConfigMaps. | list | `[]` | +| extraArgs | Extra arguments appended after the system config flags. | list | `[]` | +| extraContainers | Additional sidecar containers. These are ADDED to system containers (e.g. Lightspeed Core sidecar), never replacing them. | list | `[]` | +| extraEnv | Extra environment variables appended after the system env vars. | list | `[]` | +| extraEnvFrom | Extra envFrom entries appended to the container. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). | list | `[]` | +| extraInitContainers | Additional init containers. These are ADDED after system init containers (install-dynamic-plugins, Intelligent Assistant RAG init), never replacing them. | list | `[]` | +| extraVolumeMounts | Additional volume mounts to add to the main container. These are ADDED to system-required mounts, never replacing them. | list | `[]` | +| extraVolumes | Additional volumes to add to the pod. These are ADDED to system-required volumes (dynamic-plugins-root, temp, npmcacache, etc.), never replacing them. | list | `[]` | +| fullnameOverride | Override the full resource name. | string | `""` | +| global | Global parameters shared with bitnami subcharts (postgresql, common). | object | `{"defaultStorageClass":"","imagePullSecrets":[],"imageRegistry":""}` | +| global.defaultStorageClass | Global default StorageClass for PVCs. | string | `""` | +| global.imagePullSecrets | Global Docker registry secret names. | list | `[]` | +| global.imageRegistry | Global Docker image registry. Overrides per-image registries for all containers. | string | `""` | +| host | Custom hostname. Overrides openshift.clusterRouterBase for URL generation. | string | `""` | +| hostAliases | Host aliases for /etc/hosts entries. | list | `[]` | +| httpRoute | Gateway API HTTPRoute configuration. | object | `{"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}` | +| httpRoute.labels | Additional labels for the HTTPRoute resource. | object | `{}` | +| image | Container image configuration. | object | `{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"rhdh-community/rhdh","tag":"next"}` | +| image.digest | Overrides the image tag with an image digest. | string | `""` | +| imagePullSecrets | Secrets for pulling images from private registries (merged with global.imagePullSecrets). | list | `[]` | +| ingress | Kubernetes Ingress configuration. | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | +| intelligentAssistant | Built-in Intelligent Assistant feature configuration. | object | `{"config":{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}},"core":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"enabled":true,"existingSecret":"","plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}],"ragInit":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| intelligentAssistant.config | Configuration files mounted into the sidecar. By default, the chart creates ConfigMaps from bundled source files. Set existingConfigMap to use a pre-existing ConfigMap instead. | object | `{"profile":{"existingConfigMap":{"key":"","name":""}},"server":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}}` | +| intelligentAssistant.config.profile | Python profile with prompt templates (rhdh-profile.py). | object | `{"existingConfigMap":{"key":"","name":""}}` | +| intelligentAssistant.config.profile.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled rhdh-profile.py | +| intelligentAssistant.config.profile.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (rhdh-profile.py) if not set. | string | `""` | +| intelligentAssistant.config.profile.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | +| intelligentAssistant.config.server | Llama Stack server configuration (config.yaml). | object | `{"existingConfigMap":{"key":"","name":""}}` | +| intelligentAssistant.config.server.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled config.yaml | +| intelligentAssistant.config.server.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (config.yaml) if not set. | string | `""` | +| intelligentAssistant.config.server.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | +| intelligentAssistant.config.stack | Lightspeed Core service configuration (lightspeed-stack.yaml). | object | `{"existingConfigMap":{"key":"","name":""}}` | +| intelligentAssistant.config.stack.existingConfigMap | Use an existing ConfigMap instead of the bundled default. | object | Created from bundled lightspeed-stack.yaml | +| intelligentAssistant.config.stack.existingConfigMap.key | Key within the ConfigMap that holds the file content. Defaults to the bundled filename (lightspeed-stack.yaml) if not set. | string | `""` | +| intelligentAssistant.config.stack.existingConfigMap.name | Name of the existing ConfigMap. | string | `""` | +| intelligentAssistant.core | Lightspeed Core sidecar container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.6.2"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | +| intelligentAssistant.core.argsOverride | Override the container's default args. Leave empty to use the image defaults. | list | `[]` | +| intelligentAssistant.core.commandOverride | Override the container's default command. Leave empty to use the image entrypoint. | list | `[]` | +| intelligentAssistant.core.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | +| intelligentAssistant.existingSecret | Name of an existing Secret to inject via envFrom into the lightspeed-core container. If empty, no secret is mounted. Expected keys (all optional — only set the ones for the providers you use): ENABLE_VLLM, VLLM_URL, VLLM_API_KEY, VLLM_MAX_TOKENS, VLLM_TLS_VERIFY, ENABLE_OPENAI, OPENAI_API_KEY, ENABLE_VERTEX_AI, VERTEX_AI_PROJECT, VERTEX_AI_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, ENABLE_OLLAMA, OLLAMA_URL, ENABLE_VALIDATION, VALIDATION_PROVIDER, VALIDATION_MODEL_NAME, LLAMA_STACK_LOGGING See files/intelligent-assistant/secret.example.yaml for a reference template. | string | `""` | +| intelligentAssistant.plugins | Intelligent Assistant dynamic plugin packages. | list | `[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}]` | +| intelligentAssistant.ragInit | RAG data bootstrap init container. | object | `{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"redhat-ai-dev/rag-content","tag":"release-1.10-lls-0.5.0-8c231a3b5177f12fff9db042dfa4091d8f2f26b3"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}` | +| intelligentAssistant.ragInit.argsOverride | Override the default arguments for the RAG init container. | list | `[]` | +| intelligentAssistant.ragInit.commandOverride | Override the default command for the RAG init container. | list | `[]` | +| intelligentAssistant.ragInit.extraArgs | Extra arguments appended after the default arguments. Ignored when argsOverride is set. | list | `[]` | +| intelligentAssistant.runtimeVolume | Writable scratch volume for the sidecar (/tmp). | object | `{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}` | +| intelligentAssistant.runtimeVolume.type | Volume type: "emptyDir" or "persistentVolumeClaim". | string | `"emptyDir"` | +| livenessProbe | Liveness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}` | +| metrics | Prometheus metrics configuration. | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}` | +| nameOverride | Override the chart name used in resource naming. | string | `""` | +| nodeSelector | Node labels for pod assignment. | object | `{}` | +| openshift | OpenShift-specific configuration. | object | `{"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}` | +| openshift.clusterRouterBase | Cluster router base domain used to auto-generate the hostname. | string | `"apps.example.com"` | +| openshift.route | OpenShift Route configuration. | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | +| orchestrator | Orchestrator (Serverless workflows) configuration. | object | `{"enabled":false,"plugins":[{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"enabled":true,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}],"serverlessLogicOperator":{"enabled":true},"serverlessOperator":{"enabled":true},"sonataflowPlatform":{"dataIndex":{"image":{"digest":"","registry":"","repository":"","tag":""}},"dbCreationJob":{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null},"eventing":{"broker":{"name":"","namespace":""}},"externalDB":{"existingSecret":"","host":"","name":"","port":""},"jobService":{"image":{"digest":"","registry":"","repository":"","tag":""}},"monitoring":{"enabled":true},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"250m","memory":"64Mi"}}}}` | +| orchestrator.sonataflowPlatform.dataIndex | SonataFlow Data Index service configuration. | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | +| orchestrator.sonataflowPlatform.dataIndex.image | Override the Data Index container image. If empty, the operator default is used. | object | `{"digest":"","registry":"","repository":"","tag":""}` | +| orchestrator.sonataflowPlatform.dbCreationJob | Database creation Job configuration. | object | `{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null}` | +| orchestrator.sonataflowPlatform.dbCreationJob.image | Container image for the create-db Job. | object | `{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"}` | +| orchestrator.sonataflowPlatform.externalDB | External database connection. Used when postgresql.enabled is false. | object | `{"existingSecret":"","host":"","name":"","port":""}` | +| orchestrator.sonataflowPlatform.externalDB.existingSecret | Name of a Secret containing POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD keys. | string | `""` | +| orchestrator.sonataflowPlatform.externalDB.host | Database host (used in JDBC URLs). | string | `""` | +| orchestrator.sonataflowPlatform.externalDB.name | Database name to connect to for the CREATE DATABASE command. | string | `""` | +| orchestrator.sonataflowPlatform.externalDB.port | Database port (used in JDBC URLs). | string | `""` | +| orchestrator.sonataflowPlatform.jobService | SonataFlow Job Service configuration. | object | `{"image":{"digest":"","registry":"","repository":"","tag":""}}` | +| orchestrator.sonataflowPlatform.jobService.image | Override the Job Service container image. If empty, the operator default is used. | object | `{"digest":"","registry":"","repository":"","tag":""}` | +| podAnnotations | Annotations to add to the pod. | object | `{}` | +| podDisruptionBudget | Pod Disruption Budget configuration. | object | `{"create":false,"maxUnavailable":1,"minAvailable":""}` | +| podLabels | Labels to add to the pod. | object | `{}` | +| podSecurityContext | Pod-level security context. | object | `{}` | +| postgresql | Built-in PostgreSQL database (bitnami subchart). | object | `{"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-15","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"serviceBindings":{"enabled":true}}` | +| preInitContainers | Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). | list | `[]` | +| readinessProbe | Readiness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}` | +| replicaCount | Number of desired pods. | int | `1` | +| resources | Resource requests and limits for the main RHDH container. | object | `{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}` | +| revisionHistoryLimit | Number of old ReplicaSets to retain. | int | `10` | +| service | Service configuration. | object | `{"annotations":{},"clusterIP":"","externalTrafficPolicy":"","extraPorts":[{"name":"http-metrics","port":9464,"targetPort":9464}],"ipFamilies":[],"ipFamilyPolicy":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePort":"","port":7007,"sessionAffinity":"","type":"ClusterIP"}` | +| service.extraPorts | Additional service ports. | list | `[{"name":"http-metrics","port":9464,"targetPort":9464}]` | +| service.ipFamilies | IP families for dual-stack networking. | list | `[]` | +| service.ipFamilyPolicy | IP family policy for dual-stack networking. | string | `""` | +| service.nodePort | Node port for NodePort/LoadBalancer service types (range 30000-32767). | string | `""` | +| serviceAccount | ServiceAccount configuration. | object | `{"annotations":{},"automount":true,"create":false,"labels":{},"name":""}` | +| serviceAccount.labels | Additional labels for the ServiceAccount. | object | `{}` | +| serviceAccount.name | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | string | `""` | +| startupProbe | Startup probe configuration. Gives the application time to start before liveness/readiness probes kick in. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":4}` | +| strategy | Deployment update strategy. | object | `{}` | +| test | Test pod configuration for `helm test`. | object | `{"enabled":true,"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"curl/curl","tag":"8.21.0"},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}` | +| tolerations | Tolerations for pod assignment. | list | `[]` | +| topologySpreadConstraints | Topology spread constraints for pod scheduling. | list | `[]` | ## Opinionated RHDH deployment diff --git a/charts/rhdh/docs/migration-from-backstage-chart.md b/charts/rhdh/docs/migration-from-backstage-chart.md index 0c4f1503..7ca31c25 100644 --- a/charts/rhdh/docs/migration-from-backstage-chart.md +++ b/charts/rhdh/docs/migration-from-backstage-chart.md @@ -42,6 +42,8 @@ flattens configuration to root-level keys. | System volumes/mounts/env | User had to list them in full under `upstream.backstage.extraVolumes`, `extraVolumeMounts`, `extraEnvVars` | Hardcoded in templates; `extra*` keys only add user values | | Init containers | User had to specify the full init container array | System init containers are managed; use `preInitContainers` / `extraInitContainers` to add custom ones | | Database env vars | `POSTGRESQL_ADMIN_PASSWORD` injected manually via `upstream.backstage.extraEnvVars` | `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD` auto-injected | +| Image digests | No dedicated field | Every image (`image`, `catalogIndex.image`, `intelligentAssistant.core.image`, etc.) has a `digest` field for pinning by digest | +| Global image registry | Not available | `global.imageRegistry` overrides the registry for all container images consistently — useful for disconnected / air-gapped environments | | Lightspeed | `global.lightspeed.*` | Rebranded to `intelligentAssistant.*` | | OpenShift Route | `route.*` | `openshift.route.*` | From e22d2229bba5251f8364be74d27ba1562409b572 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 2 Sep 2026 21:19:45 +0200 Subject: [PATCH 4/5] fix: default nameOverride to developer-hub for URL continuity Match the old backstage chart's nameOverride so that resource names (and OpenShift Route URLs) are preserved during migration. Ref: RHIDP-16514 --- charts/rhdh/README.md | 2 +- charts/rhdh/values.schema.json | 2 +- charts/rhdh/values.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/rhdh/README.md b/charts/rhdh/README.md index 1b001148..0830c8b5 100644 --- a/charts/rhdh/README.md +++ b/charts/rhdh/README.md @@ -271,7 +271,7 @@ Kubernetes: `>= 1.31.0-0` | intelligentAssistant.runtimeVolume.type | Volume type: "emptyDir" or "persistentVolumeClaim". | string | `"emptyDir"` | | livenessProbe | Liveness probe configuration. | object | `{"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}` | | metrics | Prometheus metrics configuration. | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}` | -| nameOverride | Override the chart name used in resource naming. | string | `""` | +| nameOverride | Override the chart name used in resource naming. | string | `"developer-hub"` | | nodeSelector | Node labels for pod assignment. | object | `{}` | | openshift | OpenShift-specific configuration. | object | `{"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}` | | openshift.clusterRouterBase | Cluster router base domain used to auto-generate the hostname. | string | `"apps.example.com"` | diff --git a/charts/rhdh/values.schema.json b/charts/rhdh/values.schema.json index 82d38fc8..30d9911c 100644 --- a/charts/rhdh/values.schema.json +++ b/charts/rhdh/values.schema.json @@ -1650,7 +1650,7 @@ "type": "object" }, "nameOverride": { - "default": "", + "default": "developer-hub", "title": "Override the chart name used in resource naming.", "type": "string" }, diff --git a/charts/rhdh/values.yaml b/charts/rhdh/values.yaml index a62983eb..94687ed2 100644 --- a/charts/rhdh/values.yaml +++ b/charts/rhdh/values.yaml @@ -14,7 +14,7 @@ global: # ── Chart metadata overrides ──────────────────────────────── # -- Override the chart name used in resource naming. -nameOverride: "" +nameOverride: developer-hub # -- Override the full resource name. fullnameOverride: "" # -- Labels applied to ALL chart resources. From 2379d1377d2be793733a87cd700e33d28710ac7f Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 2 Sep 2026 21:20:35 +0200 Subject: [PATCH 5/5] docs: note that nameOverride preserves resource names during migration Ref: RHIDP-16514 --- charts/rhdh/docs/migration-from-backstage-chart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/rhdh/docs/migration-from-backstage-chart.md b/charts/rhdh/docs/migration-from-backstage-chart.md index 7ca31c25..e45aaa35 100644 --- a/charts/rhdh/docs/migration-from-backstage-chart.md +++ b/charts/rhdh/docs/migration-from-backstage-chart.md @@ -37,7 +37,7 @@ flattens configuration to root-level keys. | Aspect | Old chart (`backstage`) | New chart (`redhat-developer-hub`) | |--------|------------------------|------------------------------------| -| Chart name | `backstage` | `redhat-developer-hub` | +| Chart name | `backstage` | `redhat-developer-hub` (but `nameOverride` defaults to `developer-hub`, so resource names and Route URLs are preserved) | | Template ownership | Delegates to upstream Backstage subchart | Owns all templates directly | | System volumes/mounts/env | User had to list them in full under `upstream.backstage.extraVolumes`, `extraVolumeMounts`, `extraEnvVars` | Hardcoded in templates; `extra*` keys only add user values | | Init containers | User had to specify the full init container array | System init containers are managed; use `preInitContainers` / `extraInitContainers` to add custom ones |