From 73b055207aee977d2e014abf8bdbfc12d077a878 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 22 Apr 2026 18:55:29 +0200 Subject: [PATCH 1/3] feat: Support configuring multiple catalog index images [RHIDP-12934] Add global.catalogIndex.extraImages to allow listing additional catalog index OCI images whose catalog entities are extracted for the Extensions UI. A new helper (rhdh.catalogIndex.extraImagesEnvValue) builds the comma-separated EXTRA_CATALOG_INDEX_IMAGES value, and the vendored deployment template conditionally injects it into the install-dynamic-plugins init container only when the list is non-empty. Assisted-by: Claude --- charts/backstage/Chart.yaml | 2 +- charts/backstage/README.md | 11 ++++--- charts/backstage/README.md.gotmpl | 4 ++- charts/backstage/templates/_helpers.tpl | 17 ++++++++++ charts/backstage/values.schema.json | 32 +++++++++++++++++++ charts/backstage/values.schema.tmpl.json | 32 +++++++++++++++++++ charts/backstage/values.yaml | 12 +++++++ .../templates/backstage-deployment.yaml | 9 +++++- docs/catalog-index-configuration.md | 25 +++++++++++++++ 9 files changed, 137 insertions(+), 7 deletions(-) diff --git a/charts/backstage/Chart.yaml b/charts/backstage/Chart.yaml index 57bf94d7..7522d155 100644 --- a/charts/backstage/Chart.yaml +++ b/charts/backstage/Chart.yaml @@ -47,4 +47,4 @@ sources: [] # Versions are expected to follow Semantic Versioning (https://semver.org/) # Note that when this chart is published to https://github.com/openshift-helm-charts/charts # it will follow the RHDH versioning 1.y.z -version: 5.8.1 +version: 5.9.0 diff --git a/charts/backstage/README.md b/charts/backstage/README.md index cec349e0..9f4cd26f 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -1,7 +1,7 @@ # RHDH Backstage Helm Chart for OpenShift -![Version: 5.8.1](https://img.shields.io/badge/Version-5.8.1-informational?style=flat-square) +![Version: 5.9.0](https://img.shields.io/badge/Version-5.9.0-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. @@ -29,7 +29,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-backstage redhat-developer/backstage --version 5.8.1 +helm install my-backstage redhat-developer/backstage --version 5.9.0 ``` ## Introduction @@ -168,7 +168,8 @@ Kubernetes: `>= 1.27.0-0` | global.auth.backend.enabled | Enable backend service to service authentication, unless configured otherwise it generates a secret value | bool | `true` | | global.auth.backend.existingSecret | Instead of generating a secret value, refer to existing secret | string | `""` | | global.auth.backend.value | Instead of generating a secret value, use the following value | string | `""` | -| global.catalogIndex | Catalog index configuration for automatic plugin discovery. The `install-dynamic-plugins.py` script pulls this image if the `CATALOG_INDEX_IMAGE` environment variable is set. The `dynamic-plugins.default.yaml` file will be extracted and written to `dynamic-plugins-root` volume mount. | object | `{"image":{"registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"1.10"}}` | +| global.catalogIndex | Catalog index configuration for automatic plugin discovery. The `install-dynamic-plugins.py` script pulls this image if the `CATALOG_INDEX_IMAGE` environment variable is set. The `dynamic-plugins.default.yaml` file will be extracted and written to `dynamic-plugins-root` volume mount. | object | `{"extraImages":[],"image":{"registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"1.10"}}` | +| global.catalogIndex.extraImages | Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include `registry`, `repository`, and `tag` fields; `name` is optional. Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). | list | `[]` | | global.clusterRouterBase | Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. | string | `"apps.example.com"` | | global.dynamic.includes | Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field. Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`). | list | `["dynamic-plugins.default.yaml"]` | | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | @@ -331,7 +332,9 @@ upstream: The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.catalogIndex.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. -For detailed information on configuring the catalog index, including how to override the default image or use a private registry, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). +You can also configure additional catalog index images via `global.catalogIndex.extraImages` to make plugins from other sources discoverable in the Extensions UI. Each extra image contributes catalog entities only (no `dynamic-plugins.default.yaml` handling). + +For detailed information on configuring the catalog index, including how to override the default image, use a private registry, or add extra catalog index images, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). ### Lightspeed diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index caf11499..6701b844 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -234,7 +234,9 @@ upstream: The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.catalogIndex.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. -For detailed information on configuring the catalog index, including how to override the default image or use a private registry, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). +You can also configure additional catalog index images via `global.catalogIndex.extraImages` to make plugins from other sources discoverable in the Extensions UI. Each extra image contributes catalog entities only (no `dynamic-plugins.default.yaml` handling). + +For detailed information on configuring the catalog index, including how to override the default image, use a private registry, or add extra catalog index images, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). ### Lightspeed diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 43f73eb3..d1b3b6dc 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -283,6 +283,23 @@ Return the Lightspeed ConfigMap volume name. {{- printf "lightspeed-config-%s" .name | trunc 63 | trimSuffix "-" -}} {{- end -}} +{{/* +Return the computed EXTRA_CATALOG_INDEX_IMAGES env var value from +global.catalogIndex.extraImages. Returns an empty string when no extra +images are configured. +*/}} +{{- define "rhdh.catalogIndex.extraImagesEnvValue" -}} +{{- $imgs := list -}} +{{- range (.Values.global.catalogIndex.extraImages | default list) -}} + {{- $ref := printf "%s/%s:%s" .registry .repository .tag -}} + {{- if .name -}} + {{- $ref = printf "%s=%s" .name $ref -}} + {{- end -}} + {{- $imgs = append $imgs $ref -}} +{{- end -}} +{{- join "," $imgs -}} +{{- end -}} + {{/* DEPRECATED: The following templates are deprecated. Please use the corresponding "rhdh.*" templates instead. */}} diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 0abf2b01..e45802b6 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -35,6 +35,38 @@ "catalogIndex": { "additionalProperties": false, "properties": { + "extraImages": { + "default": [], + "items": { + "additionalProperties": false, + "properties": { + "name": { + "title": "Optional name for the extra catalog index image. Produces cleaner extraction directory names (e.g., /extra/community/).", + "type": "string" + }, + "registry": { + "title": "Extra catalog index image registry", + "type": "string" + }, + "repository": { + "title": "Extra catalog index image repository", + "type": "string" + }, + "tag": { + "title": "Extra catalog index image tag", + "type": "string" + } + }, + "required": [ + "registry", + "repository", + "tag" + ], + "type": "object" + }, + "title": "Extra catalog index images for additional plugin discovery in the Extensions UI. Only catalog entities are extracted from extra images (no dynamic-plugins.default.yaml handling).", + "type": "array" + }, "image": { "additionalProperties": false, "properties": { diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index a287b19d..2dbbfd42 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -130,6 +130,38 @@ "default": "1.9" } } + }, + "extraImages": { + "title": "Extra catalog index images for additional plugin discovery in the Extensions UI. Only catalog entities are extracted from extra images (no dynamic-plugins.default.yaml handling).", + "type": "array", + "default": [], + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "registry", + "repository", + "tag" + ], + "properties": { + "name": { + "title": "Optional name for the extra catalog index image. Produces cleaner extraction directory names (e.g., /extra/community/).", + "type": "string" + }, + "registry": { + "title": "Extra catalog index image registry", + "type": "string" + }, + "repository": { + "title": "Extra catalog index image repository", + "type": "string" + }, + "tag": { + "title": "Extra catalog index image tag", + "type": "string" + } + } + } } } }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index bf261876..1934ff8b 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -35,6 +35,18 @@ global: registry: quay.io repository: rhdh/plugin-catalog-index tag: "1.10" + # -- Extra catalog index images for additional plugin discovery in the Extensions UI. + # Each item must include `registry`, `repository`, and `tag` fields; `name` is optional. + # Only catalog entities are extracted from extra images (no `dynamic-plugins.default.yaml` handling). + # @default -- `[]` + extraImages: [] + # - name: community + # registry: ghcr.io + # repository: redhat-developer/rhdh-plugin-community-index + # tag: "1.10" + # - registry: my-registry.example.com + # repository: my-org/my-rhdh-internal-plugin-catalog + # tag: "1.2.3" # -- Built-in Lightspeed feature configuration. # @default -- Use Lightspeed compatible settings / configurations. lightspeed: diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml index 540832bb..d39e422b 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml @@ -6,6 +6,7 @@ {{- if $lightspeed.enabled -}} {{- $lightspeedRuntimeVolumeType = include "rhdh.lightspeed.runtimeVolumeType" (dict "volume" $lightspeed.runtimeVolume "path" "global.lightspeed.runtimeVolume") -}} {{- end -}} +{{- $extraCatalogImages := include "rhdh.catalogIndex.extraImagesEnvValue" . | trim -}} --- apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} kind: Deployment @@ -114,7 +115,13 @@ spec: {{- if or .Values.backstage.initContainers $lightspeed.enabled }} initContainers: {{- if .Values.backstage.initContainers }} - {{- include "common.tplvalues.render" ( dict "value" .Values.backstage.initContainers "context" $) | nindent 8 }} + {{- range .Values.backstage.initContainers }} + {{- $container := include "common.tplvalues.render" (dict "value" . "context" $) | fromYaml }} + {{- if and $extraCatalogImages (eq (index $container "name") "install-dynamic-plugins") }} + {{- $_ := set $container "env" (append (default list (index $container "env")) (dict "name" "EXTRA_CATALOG_INDEX_IMAGES" "value" $extraCatalogImages)) }} + {{- end }} + - {{ $container | toYaml | nindent 10 | trim }} + {{- end }} {{- end }} {{- if $lightspeed.enabled }} - name: {{ $lightspeed.initContainer.name }} diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index 1cba59ee..fc3bda60 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -13,6 +13,31 @@ global: tag: "1.9" ``` +## Extra Catalog Index Images + +You can configure additional catalog index images alongside the primary one using `global.catalogIndex.extraImages`. Each extra image contributes catalog entities only to the Extensions UI — only the primary `CATALOG_INDEX_IMAGE` is used for extracting and handling the `dynamic-plugins.default.yaml`. + +```yaml +global: + catalogIndex: + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.10" + extraImages: + - name: community + registry: ghcr.io + repository: redhat-developer/rhdh-plugin-community-index + tag: "1.10" + - registry: my-registry.example.com + repository: my-org/my-rhdh-internal-plugin-catalog + tag: "1.2.3" +``` + +Each entry requires `registry`, `repository`, and `tag` fields. The optional `name` field produces cleaner extraction directory names (e.g., `/extensions/extra/community/`); when omitted, the name is auto-derived from the image reference. + +The chart constructs the `EXTRA_CATALOG_INDEX_IMAGES` environment variable for the `install-dynamic-plugins` init container as a comma-separated list. Named entries use the format `name=registry/repository:tag`, while unnamed entries use `registry/repository:tag`. + ## Using a Private Registry If your catalog index image is stored in a private registry that requires authentication, create a secret named `-dynamic-plugins-registry-auth` containing an `auth.json` file with your registry credentials. From 932edc33f926c05f726f8657561c7ac407a8a9dc Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Wed, 22 Apr 2026 21:12:17 +0200 Subject: [PATCH 2/3] Update docs/catalog-index-configuration.md --- docs/catalog-index-configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index fc3bda60..75200837 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -13,7 +13,7 @@ global: tag: "1.9" ``` -## Extra Catalog Index Images +## Extra catalog index images You can configure additional catalog index images alongside the primary one using `global.catalogIndex.extraImages`. Each extra image contributes catalog entities only to the Extensions UI — only the primary `CATALOG_INDEX_IMAGE` is used for extracting and handling the `dynamic-plugins.default.yaml`. From b136e761d784460a661051ec893cb130c29e8f79 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Fri, 24 Apr 2026 09:29:00 +0200 Subject: [PATCH 3/3] address review comments --- charts/backstage/templates/_helpers.tpl | 11 ++++++++--- charts/backstage/values.schema.json | 1 + charts/backstage/values.schema.tmpl.json | 1 + .../backstage/templates/backstage-deployment.yaml | 6 ++++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index d1b3b6dc..2e2a9c73 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -289,11 +289,16 @@ global.catalogIndex.extraImages. Returns an empty string when no extra images are configured. */}} {{- define "rhdh.catalogIndex.extraImagesEnvValue" -}} +{{- $root := . -}} {{- $imgs := list -}} {{- range (.Values.global.catalogIndex.extraImages | default list) -}} - {{- $ref := printf "%s/%s:%s" .registry .repository .tag -}} - {{- if .name -}} - {{- $ref = printf "%s=%s" .name $ref -}} + {{- $item := include "common.tplvalues.render" (dict "value" . "context" $root) | fromYaml -}} + {{- $ref := printf "%s/%s:%s" $item.registry $item.repository $item.tag -}} + {{- if $item.name -}} + {{- if or (contains "," $item.name) (contains "=" $item.name) -}} + {{- fail (printf "global.catalogIndex.extraImages[].name %q must not contain ',' or '='" $item.name) -}} + {{- end -}} + {{- $ref = printf "%s=%s" $item.name $ref -}} {{- end -}} {{- $imgs = append $imgs $ref -}} {{- end -}} diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index e45802b6..672b7544 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -41,6 +41,7 @@ "additionalProperties": false, "properties": { "name": { + "pattern": "^[A-Za-z0-9._-]+$", "title": "Optional name for the extra catalog index image. Produces cleaner extraction directory names (e.g., /extra/community/).", "type": "string" }, diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index 2dbbfd42..00bd3dd9 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -145,6 +145,7 @@ ], "properties": { "name": { + "pattern": "^[A-Za-z0-9._-]+$", "title": "Optional name for the extra catalog index image. Produces cleaner extraction directory names (e.g., /extra/community/).", "type": "string" }, diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml index d39e422b..da92a65b 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml @@ -118,8 +118,14 @@ spec: {{- range .Values.backstage.initContainers }} {{- $container := include "common.tplvalues.render" (dict "value" . "context" $) | fromYaml }} {{- if and $extraCatalogImages (eq (index $container "name") "install-dynamic-plugins") }} + {{- $hasExisting := false }} + {{- range (default list (index $container "env")) }} + {{- if eq (default "" .name) "EXTRA_CATALOG_INDEX_IMAGES" }}{{ $hasExisting = true }}{{ end }} + {{- end }} + {{- if not $hasExisting }} {{- $_ := set $container "env" (append (default list (index $container "env")) (dict "name" "EXTRA_CATALOG_INDEX_IMAGES" "value" $extraCatalogImages)) }} {{- end }} + {{- end }} - {{ $container | toYaml | nindent 10 | trim }} {{- end }} {{- end }}