From ae436b122b74b68beb93299e00df0d0d2023909a Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Mon, 8 Dec 2025 00:05:50 +0000 Subject: [PATCH 01/16] feat: RHIDP-9764-Add-catalog-index-support Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 1 + charts/backstage/values.schema.json | 16 ++++++++++++++++ charts/backstage/values.schema.tmpl.json | 12 ++++++++++++ charts/backstage/values.yaml | 8 ++++++++ 4 files changed, 37 insertions(+) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index b83c32af..ae4a0b18 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -173,6 +173,7 @@ Kubernetes: `>= 1.27.0-0` | 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.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.catalogIndex | Catalog index configuration for automatic plugin discovery. The `install-dynamic-plugins.py` script will pull this image if the `CATALOG_INDEX_IMAGE` environment variable is set, extract `dynamic-plugins.default.yaml`, and write it to `dynamic-plugins-root` volume mount. | object | `{"image":"quay.io/rhdh/plugin-catalog-index:1.9"}` | | 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 `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 728c6d48..00edc36a 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -40,6 +40,18 @@ "dynamic": { "additionalProperties": false, "properties": { + "catalogIndex": { + "additionalProperties": false, + "properties": { + "image": { + "default": "quay.io/rhdh/plugin-catalog-index:1.9", + "title": "Catalog index OCI image reference", + "type": "string" + } + }, + "title": "Catalog index configuration for automatic plugin discovery", + "type": "object" + }, "includes": { "default": [ "dynamic-plugins.default.yaml" @@ -4619,6 +4631,10 @@ { "name": "MAX_ENTRY_SIZE", "value": "30000000" + }, + { + "name": "CATALOG_INDEX_IMAGE", + "value": "{{ .Values.global.dynamic.catalogIndex.image }}" } ], "image": "{{ include \"backstage.image\" . }}", diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index 0b5fb37f..297b5f6f 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -72,6 +72,18 @@ "type": "string" }, "default": [] + }, + "catalogIndex": { + "title": "Catalog index configuration for automatic plugin discovery", + "type": "object", + "additionalProperties": false, + "properties": { + "image": { + "title": "Catalog index OCI image reference", + "type": "string", + "default": "quay.io/rhdh/plugin-catalog-index:1.9" + } + } } } }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 5517209e..f3f6468b 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -14,6 +14,12 @@ global: # listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). plugins: [] + # -- Catalog index configuration for automatic plugin discovery. + # The `install-dynamic-plugins.py` script will pull this image if the `CATALOG_INDEX_IMAGE` environment variable is set, extract `dynamic-plugins.default.yaml`, + # and write it to `dynamic-plugins-root` volume mount. + catalogIndex: + image: "quay.io/rhdh/plugin-catalog-index:1.9" + # -- 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. clusterRouterBase: "apps.example.com" # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. @@ -213,6 +219,8 @@ upstream: # This following variable is required for orchestrator to startup properly. - name: MAX_ENTRY_SIZE value: "30000000" + - name: CATALOG_INDEX_IMAGE + value: '{{ .Values.global.dynamic.catalogIndex.image }}' imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /dynamic-plugins-root From fba5b670082ae58671b804cc1aba67b78a3f133f Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Mon, 8 Dec 2025 00:17:57 +0000 Subject: [PATCH 02/16] chart update Signed-off-by: Fortune Ndlovu --- charts/backstage/Chart.yaml | 2 +- charts/backstage/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/backstage/Chart.yaml b/charts/backstage/Chart.yaml index b78c6b04..4e939324 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: 4.8.0 +version: 4.9.0 diff --git a/charts/backstage/README.md b/charts/backstage/README.md index ae4a0b18..eb8e12bf 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -1,7 +1,7 @@ # RHDH Backstage Helm Chart for OpenShift -![Version: 4.8.0](https://img.shields.io/badge/Version-4.8.0-informational?style=flat-square) +![Version: 4.9.0](https://img.shields.io/badge/Version-4.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. @@ -30,7 +30,7 @@ helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add backstage https://backstage.github.io/charts helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart -helm install my-backstage redhat-developer/backstage --version 4.8.0 +helm install my-backstage redhat-developer/backstage --version 4.9.0 ``` ## Introduction From 3cc96e540e92f6491c5f27fa1402fc4cede36ee4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Dec 2025 12:50:05 +0000 Subject: [PATCH 03/16] chore(pre-commit): Auto-fix hooks Co-authored-by: Fortune-Ndlovu --- charts/backstage/values.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index e298541b..03aa10fc 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -4638,7 +4638,7 @@ } ], "image": "{{ include \"backstage.image\" . }}", - "imagePullPolicy": "", + "imagePullPolicy": "IfNotPresent", "name": "install-dynamic-plugins", "resources": { "limits": { From 6e485ad63465891d5b7cb9f4b887746a1ef1adb6 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Wed, 10 Dec 2025 13:26:40 +0000 Subject: [PATCH 04/16] Add Document the catalog index configuration, including how it works, default behavior, and configuration options Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 6 ++ charts/backstage/README.md.gotmpl | 6 ++ docs/catalog-index-configuration.md | 103 ++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 docs/catalog-index-configuration.md diff --git a/charts/backstage/README.md b/charts/backstage/README.md index eb8e12bf..0b64f558 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -301,6 +301,12 @@ upstream: origin: 'https://{{- include "janus-idp.hostname" . }}' ``` +### Catalog Index Configuration + +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.dynamic.catalogIndex.image` and allows you to 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). + ### Vanilla Kubernetes compatibility mode In order to deploy this chart on vanilla Kubernetes or any other non-OCP platform, please make sure to apply the following changes. Note that further customizations may be required, depending on your exact Kubernetes setup: diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index c68a7119..6634254b 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -234,6 +234,12 @@ upstream: origin: 'https://{{"{{"}}- include "janus-idp.hostname" . {{"}}"}}' ``` +### Catalog Index Configuration + +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.dynamic.catalogIndex.image` and allows you to 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). + ### Vanilla Kubernetes compatibility mode In order to deploy this chart on vanilla Kubernetes or any other non-OCP platform, please make sure to apply the following changes. Note that further customizations may be required, depending on your exact Kubernetes setup: diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md new file mode 100644 index 00000000..ed7cd92e --- /dev/null +++ b/docs/catalog-index-configuration.md @@ -0,0 +1,103 @@ +# Catalog Index Configuration + +The catalog index is an OCI artifact that contains `dynamic-plugins.default.yaml`, which defines the default set of dynamic plugins to be installed. The Helm chart automatically configures the `install-dynamic-plugins` init container to pull and extract this catalog index. + +By default, the chart sets the `CATALOG_INDEX_IMAGE` environment variable in the `install-dynamic-plugins` init container: + +```yaml +env: + - name: CATALOG_INDEX_IMAGE + value: "quay.io/rhdh/plugin-catalog-index:1.9" +``` + +The `install-dynamic-plugins.py` script: +1. Pulls the catalog index OCI image using `skopeo` +2. Extracts the image layers to a temporary directory (`.catalog-index-temp`) +3. Locates `dynamic-plugins.default.yaml` within the extracted content +4. Replaces the `dynamic-plugins.default.yaml` reference in your `includes` list with the extracted catalog index version + +### Overriding the Catalog Index Image + +To use a different catalog index image, such as a newer version or a mirrored image, use the `global.dynamic.catalogIndex.image` field in your values file: + +```yaml +# values.yaml +global: + dynamic: + catalogIndex: + image: "quay.io/rhdh/plugin-catalog-index:1.9" +``` + +Alternatively, you can override it via the command line: + +```console +helm upgrade -i redhat-developer/backstage \ + --set global.dynamic.catalogIndex.image="quay.io/rhdh/plugin-catalog-index:1.9" +``` + +### Disabling the Catalog Index + +To disable the catalog index feature entirely and not pull any external catalog index image, set the image to an empty string: + +```yaml +# values.yaml +global: + dynamic: + catalogIndex: + image: "" +``` + +When disabled, the `install-dynamic-plugins.py` script will skip the catalog index extraction and rely solely on the `dynamic-plugins.default.yaml` file bundled within the Backstage container image. + +### Using a Private Registry + +If your catalog index image is stored in a private registry that requires authentication, you can provide credentials via the `dynamic-plugins-registry-auth` secret. + +The `auth.json` file is the standard [containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md) format used by `skopeo`, `podman`, and other container tools. It stores registry credentials that allow these tools to pull images from authenticated registries. + +**1:** Create the `auth.json` file with your registry credentials: + +```json +{ + "auths": { + "my-registry.example.com": { + "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=" + } + } +} +``` + +The `auth` value is a base64-encoded string of `username:password`. You can generate it with: + +```console +echo -n 'myusername:mypassword' | base64 +``` + +**2:** Create the Kubernetes secret from the `auth.json` file: + +```console +kubectl create secret generic -dynamic-plugins-registry-auth \ + --from-file=auth.json=./auth.json \ + -n +``` + +Or if you prefer a declarative YAML manifest: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: -dynamic-plugins-registry-auth +type: Opaque +stringData: + auth.json: | + { + "auths": { + "my-registry.example.com": { + "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=" + } + } + } +``` + +This secret is automatically mounted into the `install-dynamic-plugins` init container at `/opt/app-root/src/.config/containers`, allowing `skopeo` to authenticate when pulling images from private registries. From 18ea0dbc2c39ac685b6a6cffc590c4067c72bd8b Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:06:43 +0000 Subject: [PATCH 05/16] update: small tweaks based on google developer documentation style guide Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 6 +++--- charts/backstage/README.md.gotmpl | 4 ++-- charts/backstage/values.yaml | 4 ++-- docs/catalog-index-configuration.md | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 0b64f558..274dac02 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -173,7 +173,7 @@ Kubernetes: `>= 1.27.0-0` | 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.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.catalogIndex | Catalog index configuration for automatic plugin discovery. The `install-dynamic-plugins.py` script will pull this image if the `CATALOG_INDEX_IMAGE` environment variable is set, extract `dynamic-plugins.default.yaml`, and write it to `dynamic-plugins-root` volume mount. | object | `{"image":"quay.io/rhdh/plugin-catalog-index:1.9"}` | +| global.dynamic.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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | | 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 `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | @@ -303,13 +303,13 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.dynamic.catalogIndex.image` and allows you to use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This image configured via `global.dynamic.catalogIndex.image` 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). ### Vanilla Kubernetes compatibility mode -In order to deploy this chart on vanilla Kubernetes or any other non-OCP platform, please make sure to apply the following changes. Note that further customizations may be required, depending on your exact Kubernetes setup: +To deploy this chart on vanilla Kubernetes or any other non-OCP platform, apply the following changes. Note that further customizations might be required, depending on your exact Kubernetes setup: ```yaml # values.yaml diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index 6634254b..21527f9f 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,13 +236,13 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `global.dynamic.catalogIndex.image` and allows you to use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This image configured via `global.dynamic.catalogIndex.image` 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). ### Vanilla Kubernetes compatibility mode -In order to deploy this chart on vanilla Kubernetes or any other non-OCP platform, please make sure to apply the following changes. Note that further customizations may be required, depending on your exact Kubernetes setup: +To deploy this chart on vanilla Kubernetes or any other non-OCP platform, apply the following changes. Note that further customizations might be required, depending on your exact Kubernetes setup: ```yaml # values.yaml diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 8091254f..1acbdc7d 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -15,8 +15,8 @@ global: plugins: [] # -- Catalog index configuration for automatic plugin discovery. - # The `install-dynamic-plugins.py` script will pull this image if the `CATALOG_INDEX_IMAGE` environment variable is set, extract `dynamic-plugins.default.yaml`, - # and write it to `dynamic-plugins-root` volume mount. + # 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. catalogIndex: image: "quay.io/rhdh/plugin-catalog-index:1.9" diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index ed7cd92e..d21db9ed 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -47,11 +47,11 @@ global: image: "" ``` -When disabled, the `install-dynamic-plugins.py` script will skip the catalog index extraction and rely solely on the `dynamic-plugins.default.yaml` file bundled within the Backstage container image. +When disabled, the `install-dynamic-plugins.py` script skips the catalog index extraction and relies solely on the `dynamic-plugins.default.yaml` file bundled within the Backstage container image. ### Using a Private Registry -If your catalog index image is stored in a private registry that requires authentication, you can provide credentials via the `dynamic-plugins-registry-auth` secret. +If your catalog index image is stored in a private registry that requires authentication, you can provide credentials by using the `dynamic-plugins-registry-auth` secret. The `auth.json` file is the standard [containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md) format used by `skopeo`, `podman`, and other container tools. It stores registry credentials that allow these tools to pull images from authenticated registries. @@ -67,7 +67,7 @@ The `auth.json` file is the standard [containers-auth.json(5)](https://github.co } ``` -The `auth` value is a base64-encoded string of `username:password`. You can generate it with: +The `auth` value is a base64-encoded string of `username:password`. You can generate it with the following commands: ```console echo -n 'myusername:mypassword' | base64 @@ -81,7 +81,7 @@ kubectl create secret generic -dynamic-plugins-registry-auth \ -n ``` -Or if you prefer a declarative YAML manifest: +Alternatively, you can use a declarative YAML manifest: ```yaml apiVersion: v1 From 4661d33eecbc2b75c7793c794ca0c48643499c2f Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:11:24 +0000 Subject: [PATCH 06/16] Move configuration from global.dynamic.catalogIndex to pluginCatalogIndex at the root level Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 5 +- charts/backstage/README.md.gotmpl | 2 +- charts/backstage/values.schema.json | 4 +- charts/backstage/values.yaml | 370 ++++++++++++++-------------- docs/catalog-index-configuration.md | 16 +- 5 files changed, 197 insertions(+), 200 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 274dac02..fe2b2595 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -173,7 +173,6 @@ Kubernetes: `>= 1.27.0-0` | 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.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.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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | | 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 `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | @@ -198,6 +197,8 @@ Kubernetes: `>= 1.27.0-0` | orchestrator.sonataflowPlatform.resources.limits.memory | | string | `"1Gi"` | | orchestrator.sonataflowPlatform.resources.requests.cpu | | string | `"250m"` | | orchestrator.sonataflowPlatform.resources.requests.memory | | string | `"64Mi"` | +| pluginCatalogIndex | 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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | +| pluginCatalogIndex.image | OCI image for the plugin catalog index. Set to empty string to disable. | string | `"quay.io/rhdh/plugin-catalog-index:1.9"` | | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | | route.annotations | Route specific annotations | object | `{}` | | route.enabled | Enable the creation of the route resource | bool | `true` | @@ -303,7 +304,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This image configured via `global.dynamic.catalogIndex.image` and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` 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). diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index 21527f9f..60582c4d 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,7 +236,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This image configured via `global.dynamic.catalogIndex.image` and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` 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). diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 03aa10fc..09e51851 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -4634,11 +4634,11 @@ }, { "name": "CATALOG_INDEX_IMAGE", - "value": "{{ .Values.global.dynamic.catalogIndex.image }}" + "value": "{{ .Values.pluginCatalogIndex.image }}" } ], "image": "{{ include \"backstage.image\" . }}", - "imagePullPolicy": "IfNotPresent", + "imagePullPolicy": "", "name": "install-dynamic-plugins", "resources": { "limits": { diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 1acbdc7d..b463e2e5 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -1,25 +1,26 @@ nameOverride: developer-hub + +# -- 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. +pluginCatalogIndex: + # -- OCI image for the plugin catalog index. Set to empty string to disable. + image: "quay.io/rhdh/plugin-catalog-index:1.9" + global: dynamic: # -- 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`). includes: - # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. - # This file ONLY works with the `janus-idp/backstage-showcase` container image. - - "dynamic-plugins.default.yaml" - + # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. + # This file ONLY works with the `janus-idp/backstage-showcase` container image. + - "dynamic-plugins.default.yaml" # -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files. # Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin # listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). plugins: [] - # -- 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. - catalogIndex: - image: "quay.io/rhdh/plugin-catalog-index:1.9" - # -- 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. clusterRouterBase: "apps.example.com" # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. @@ -70,15 +71,15 @@ upstream: user: postgres auth: externalAccess: - - type: legacy - options: - subject: legacy-default-config - secret: ${BACKEND_SECRET} + - type: legacy + options: + subject: legacy-default-config + secret: ${BACKEND_SECRET} containerSecurityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: - drop: ["ALL"] + drop: [ "ALL" ] runAsNonRoot: true seccompProfile: type: "RuntimeDefault" @@ -131,121 +132,120 @@ upstream: successThreshold: 1 timeoutSeconds: 4 extraEnvVars: - - name: BACKEND_SECRET - valueFrom: - secretKeyRef: - key: backend-secret - name: '{{ include "janus-idp.backend-secret-name" $ }}' - - name: POSTGRESQL_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: '{{- include "janus-idp.postgresql.secretName" . }}' + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{- include "janus-idp.postgresql.secretName" . }}' args: - # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. - - "--config" - - dynamic-plugins-root/app-config.dynamic-plugins.yaml + # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. + - "--config" + - dynamic-plugins-root/app-config.dynamic-plugins.yaml extraVolumeMounts: - # The initContainer below will install dynamic plugins in this volume mount. - - name: dynamic-plugins-root - mountPath: /opt/app-root/src/dynamic-plugins-root - - name: temp - mountPath: /tmp + # The initContainer below will install dynamic plugins in this volume mount. + - name: dynamic-plugins-root + mountPath: /opt/app-root/src/dynamic-plugins-root + - name: temp + mountPath: /tmp extraVolumes: - # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. - - name: dynamic-plugins-root - ephemeral: - volumeClaimTemplate: - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. - storage: 5Gi - # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. - # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. - - name: dynamic-plugins - configMap: - defaultMode: 420 - name: '{{ printf "%s-dynamic-plugins" .Release.Name }}' - optional: true - # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) - # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. - - name: dynamic-plugins-npmrc - secret: - defaultMode: 420 - optional: true - secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}' - # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret) - # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer. - - name: dynamic-plugins-registry-auth - secret: - defaultMode: 416 - optional: true - secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}' - - name: npmcacache - emptyDir: {} - - name: temp - emptyDir: {} + # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. + - name: dynamic-plugins-root + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. + storage: 5Gi + # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. + # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. + - name: dynamic-plugins + configMap: + defaultMode: 420 + name: '{{ printf "%s-dynamic-plugins" .Release.Name }}' + optional: true + # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) + # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}' + # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret) + # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-registry-auth + secret: + defaultMode: 416 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}' + - name: npmcacache + emptyDir: {} + - name: temp + emptyDir: {} initContainers: - - name: install-dynamic-plugins - resources: - requests: - cpu: 250m - memory: 256Mi - limits: - cpu: 1000m - memory: 2.5Gi - ephemeral-storage: 5Gi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" - # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. - # It could be replaced by a custom image based on this one. - # @default -- `quay.io/janus-idp/backstage-showcase:latest` - image: '{{ include "backstage.image" . }}' - command: - - ./install-dynamic-plugins.sh - - /dynamic-plugins-root - env: - - name: NPM_CONFIG_USERCONFIG - value: /opt/app-root/src/.npmrc.dynamic-plugins - # This following variable is required for orchestrator to startup properly. - - name: MAX_ENTRY_SIZE - value: "30000000" - - name: CATALOG_INDEX_IMAGE - value: '{{ .Values.global.dynamic.catalogIndex.image }}' - imagePullPolicy: IfNotPresent - volumeMounts: - - mountPath: /dynamic-plugins-root - name: dynamic-plugins-root - - mountPath: /opt/app-root/src/dynamic-plugins.yaml - name: dynamic-plugins - readOnly: true - subPath: dynamic-plugins.yaml - - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins - name: dynamic-plugins-npmrc - readOnly: true - subPath: .npmrc - - mountPath: /opt/app-root/src/.config/containers - name: dynamic-plugins-registry-auth - readOnly: true - - mountPath: /opt/app-root/src/.npm/_cacache - name: npmcacache - - name: temp - mountPath: /tmp - workingDir: /opt/app-root/src + - name: install-dynamic-plugins + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" + # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. + # It could be replaced by a custom image based on this one. + # @default -- `quay.io/janus-idp/backstage-showcase:latest` + image: '{{ include "backstage.image" . }}' + command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + # This following variable is required for orchestrator to startup properly. + - name: MAX_ENTRY_SIZE + value: "30000000" + - name: CATALOG_INDEX_IMAGE + value: '{{ .Values.pluginCatalogIndex.image }}' + imagePullPolicy: "" + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/dynamic-plugins.yaml + name: dynamic-plugins + readOnly: true + subPath: dynamic-plugins.yaml + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + - mountPath: /opt/app-root/src/.config/containers + name: dynamic-plugins-registry-auth + readOnly: true + - mountPath: /opt/app-root/src/.npm/_cacache + name: npmcacache + - name: temp + mountPath: /tmp + workingDir: /opt/app-root/src installDir: /opt/app-root/src podAnnotations: checksum/dynamic-plugins: >- - {{- include "common.tplvalues.render" ( dict "value" - .Values.global.dynamic "context" $) | sha256sum }} + {{- include "common.tplvalues.render" ( dict "value" .Values.global.dynamic "context" $) | sha256sum }} ingress: host: "{{ .Values.global.host }}" metrics: @@ -275,7 +275,7 @@ upstream: allowPrivilegeEscalation: false capabilities: drop: - - ALL + - ALL resources: requests: cpu: 250m @@ -289,16 +289,16 @@ upstream: size: 1Gi mountPath: /var/lib/pgsql/data extraEnvVars: - - name: POSTGRESQL_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: '{{- include "postgresql.v1.secretName" . }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{- include "postgresql.v1.secretName" . }}' service: extraPorts: - - name: http-metrics - port: 9464 - targetPort: 9464 + - name: http-metrics + port: 9464 + targetPort: 9464 # -- OpenShift Route parameters route: @@ -412,56 +412,56 @@ orchestrator: # -- Orchestrator plugins and their configuration plugins: - # RHDHBUGS-1464: Note that the plugins here fetch the packages from their direct HTTP download URLs from the (official) Red Hat NPM Registry. - # Previously, we were using the "@redhat/plugin@version" form along with injecting a .npmrc Secret to resolve the "@redhat" scope, - # but this caused conflicting issues with user-provided .npmrc secrets. - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz" - integrity: sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ== - pluginConfig: - orchestrator: - dataIndexService: - url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz" - integrity: sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw== - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-orchestrator: - appIcons: - - name: orchestratorIcon - importName: OrchestratorIcon - dynamicRoutes: - - path: /orchestrator - importName: OrchestratorPage - menuItem: - icon: orchestratorIcon - text: Orchestrator - entityTabs: - - path: /workflows - title: Workflows - mountPoint: entity.page.workflows - mountPoints: - - mountPoint: entity.page.workflows/cards - importName: OrchestratorCatalogTab - config: - layout: - gridColumn: "1 / -1" - if: - anyOf: - - IsOrchestratorCatalogTabAvailable - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz" - integrity: sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ== - pluginConfig: - orchestrator: - dataIndexService: - url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz" - integrity: sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw== - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} + # RHDHBUGS-1464: Note that the plugins here fetch the packages from their direct HTTP download URLs from the (official) Red Hat NPM Registry. + # Previously, we were using the "@redhat/plugin@version" form along with injecting a .npmrc Secret to resolve the "@redhat" scope, + # but this caused conflicting issues with user-provided .npmrc secrets. + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz" + integrity: sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ== + pluginConfig: + orchestrator: + dataIndexService: + url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz" + integrity: sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw== + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-orchestrator: + appIcons: + - name: orchestratorIcon + importName: OrchestratorIcon + dynamicRoutes: + - path: /orchestrator + importName: OrchestratorPage + menuItem: + icon: orchestratorIcon + text: Orchestrator + entityTabs: + - path: /workflows + title: Workflows + mountPoint: entity.page.workflows + mountPoints: + - mountPoint: entity.page.workflows/cards + importName: OrchestratorCatalogTab + config: + layout: + gridColumn: "1 / -1" + if: + anyOf: + - IsOrchestratorCatalogTabAvailable + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz" + integrity: sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ== + pluginConfig: + orchestrator: + dataIndexService: + url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz" + integrity: sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw== + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index d21db9ed..33f9e921 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -18,21 +18,19 @@ The `install-dynamic-plugins.py` script: ### Overriding the Catalog Index Image -To use a different catalog index image, such as a newer version or a mirrored image, use the `global.dynamic.catalogIndex.image` field in your values file: +To use a different catalog index image, such as a newer version or a mirrored image, use the `pluginCatalogIndex.image` field in your values file: ```yaml # values.yaml -global: - dynamic: - catalogIndex: - image: "quay.io/rhdh/plugin-catalog-index:1.9" +pluginCatalogIndex: + image: "quay.io/rhdh/plugin-catalog-index:1.9" ``` Alternatively, you can override it via the command line: ```console helm upgrade -i redhat-developer/backstage \ - --set global.dynamic.catalogIndex.image="quay.io/rhdh/plugin-catalog-index:1.9" + --set pluginCatalogIndex.image="quay.io/rhdh/plugin-catalog-index:1.9" ``` ### Disabling the Catalog Index @@ -41,10 +39,8 @@ To disable the catalog index feature entirely and not pull any external catalog ```yaml # values.yaml -global: - dynamic: - catalogIndex: - image: "" +pluginCatalogIndex: + image: "" ``` When disabled, the `install-dynamic-plugins.py` script skips the catalog index extraction and relies solely on the `dynamic-plugins.default.yaml` file bundled within the Backstage container image. From da9316c7b43d766dd8acae2d140cbb4cbd43f016 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:21:20 +0000 Subject: [PATCH 07/16] Update documentation to be chart specific Signed-off-by: Fortune Ndlovu --- docs/catalog-index-configuration.md | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index 33f9e921..91f5d10c 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -1,22 +1,10 @@ # Catalog Index Configuration -The catalog index is an OCI artifact that contains `dynamic-plugins.default.yaml`, which defines the default set of dynamic plugins to be installed. The Helm chart automatically configures the `install-dynamic-plugins` init container to pull and extract this catalog index. +The Helm chart supports loading default plugin configurations from an OCI container image (catalog index). For general information about how the catalog index works, see [Using a Catalog Index Image for Default Plugin Configurations](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/installing-plugins.md#using-a-catalog-index-image-for-default-plugin-configurations). -By default, the chart sets the `CATALOG_INDEX_IMAGE` environment variable in the `install-dynamic-plugins` init container: +By default, the chart sets `pluginCatalogIndex.image` to `quay.io/rhdh/plugin-catalog-index:1.9`. -```yaml -env: - - name: CATALOG_INDEX_IMAGE - value: "quay.io/rhdh/plugin-catalog-index:1.9" -``` - -The `install-dynamic-plugins.py` script: -1. Pulls the catalog index OCI image using `skopeo` -2. Extracts the image layers to a temporary directory (`.catalog-index-temp`) -3. Locates `dynamic-plugins.default.yaml` within the extracted content -4. Replaces the `dynamic-plugins.default.yaml` reference in your `includes` list with the extracted catalog index version - -### Overriding the Catalog Index Image +## Overriding the Catalog Index Image To use a different catalog index image, such as a newer version or a mirrored image, use the `pluginCatalogIndex.image` field in your values file: @@ -33,9 +21,9 @@ helm upgrade -i redhat-developer/backstage \ --set pluginCatalogIndex.image="quay.io/rhdh/plugin-catalog-index:1.9" ``` -### Disabling the Catalog Index +## Disabling the Catalog Index -To disable the catalog index feature entirely and not pull any external catalog index image, set the image to an empty string: +To disable the catalog index feature and use only the `dynamic-plugins.default.yaml` bundled in the container image, set the image to an empty string: ```yaml # values.yaml @@ -43,9 +31,7 @@ pluginCatalogIndex: image: "" ``` -When disabled, the `install-dynamic-plugins.py` script skips the catalog index extraction and relies solely on the `dynamic-plugins.default.yaml` file bundled within the Backstage container image. - -### Using a Private Registry +## Using a Private Registry If your catalog index image is stored in a private registry that requires authentication, you can provide credentials by using the `dynamic-plugins-registry-auth` secret. From e98292dee61d17963e29a9ca7b24c2747a447926 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:40:34 +0000 Subject: [PATCH 08/16] Use pre-commit run -a to apply changes Signed-off-by: Fortune Ndlovu --- charts/backstage/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index b463e2e5..7684e06c 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -15,6 +15,7 @@ global: # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. # This file ONLY works with the `janus-idp/backstage-showcase` container image. - "dynamic-plugins.default.yaml" + # -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files. # Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin From 83ed7d9d66a40404f9e95083d8a9f714b361bf77 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:46:20 +0000 Subject: [PATCH 09/16] Update Signed-off-by: Fortune Ndlovu --- charts/backstage/values.yaml | 355 ++++++++++++++++++----------------- 1 file changed, 178 insertions(+), 177 deletions(-) diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 7684e06c..e8904987 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -12,9 +12,9 @@ global: # -- 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`). includes: - # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. - # This file ONLY works with the `janus-idp/backstage-showcase` container image. - - "dynamic-plugins.default.yaml" + # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. + # This file ONLY works with the `janus-idp/backstage-showcase` container image. + - "dynamic-plugins.default.yaml" # -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files. # Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), @@ -72,15 +72,15 @@ upstream: user: postgres auth: externalAccess: - - type: legacy - options: - subject: legacy-default-config - secret: ${BACKEND_SECRET} + - type: legacy + options: + subject: legacy-default-config + secret: ${BACKEND_SECRET} containerSecurityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: - drop: [ "ALL" ] + drop: ["ALL"] runAsNonRoot: true seccompProfile: type: "RuntimeDefault" @@ -133,120 +133,121 @@ upstream: successThreshold: 1 timeoutSeconds: 4 extraEnvVars: - - name: BACKEND_SECRET - valueFrom: - secretKeyRef: - key: backend-secret - name: '{{ include "janus-idp.backend-secret-name" $ }}' - - name: POSTGRESQL_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: '{{- include "janus-idp.postgresql.secretName" . }}' + - name: BACKEND_SECRET + valueFrom: + secretKeyRef: + key: backend-secret + name: '{{ include "janus-idp.backend-secret-name" $ }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{- include "janus-idp.postgresql.secretName" . }}' args: - # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. - - "--config" - - dynamic-plugins-root/app-config.dynamic-plugins.yaml + # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. + - "--config" + - dynamic-plugins-root/app-config.dynamic-plugins.yaml extraVolumeMounts: - # The initContainer below will install dynamic plugins in this volume mount. - - name: dynamic-plugins-root - mountPath: /opt/app-root/src/dynamic-plugins-root - - name: temp - mountPath: /tmp - extraVolumes: - # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. - - name: dynamic-plugins-root - ephemeral: - volumeClaimTemplate: - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. - storage: 5Gi - # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. - # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. - - name: dynamic-plugins - configMap: - defaultMode: 420 - name: '{{ printf "%s-dynamic-plugins" .Release.Name }}' - optional: true - # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) - # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. - - name: dynamic-plugins-npmrc - secret: - defaultMode: 420 - optional: true - secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}' - # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret) - # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer. - - name: dynamic-plugins-registry-auth - secret: - defaultMode: 416 - optional: true - secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}' - - name: npmcacache - emptyDir: {} - - name: temp - emptyDir: {} - initContainers: - - name: install-dynamic-plugins - resources: - requests: - cpu: 250m - memory: 256Mi - limits: - cpu: 1000m - memory: 2.5Gi - ephemeral-storage: 5Gi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: [ "ALL" ] - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" - # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. - # It could be replaced by a custom image based on this one. - # @default -- `quay.io/janus-idp/backstage-showcase:latest` - image: '{{ include "backstage.image" . }}' - command: - - ./install-dynamic-plugins.sh - - /dynamic-plugins-root - env: - - name: NPM_CONFIG_USERCONFIG - value: /opt/app-root/src/.npmrc.dynamic-plugins - # This following variable is required for orchestrator to startup properly. - - name: MAX_ENTRY_SIZE - value: "30000000" - - name: CATALOG_INDEX_IMAGE - value: '{{ .Values.pluginCatalogIndex.image }}' - imagePullPolicy: "" - volumeMounts: - - mountPath: /dynamic-plugins-root - name: dynamic-plugins-root - - mountPath: /opt/app-root/src/dynamic-plugins.yaml - name: dynamic-plugins - readOnly: true - subPath: dynamic-plugins.yaml - - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins - name: dynamic-plugins-npmrc - readOnly: true - subPath: .npmrc - - mountPath: /opt/app-root/src/.config/containers - name: dynamic-plugins-registry-auth - readOnly: true - - mountPath: /opt/app-root/src/.npm/_cacache - name: npmcacache + # The initContainer below will install dynamic plugins in this volume mount. + - name: dynamic-plugins-root + mountPath: /opt/app-root/src/dynamic-plugins-root - name: temp mountPath: /tmp - workingDir: /opt/app-root/src + extraVolumes: + # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. + - name: dynamic-plugins-root + ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + # -- Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. + storage: 5Gi + # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. + # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. + - name: dynamic-plugins + configMap: + defaultMode: 420 + name: '{{ printf "%s-dynamic-plugins" .Release.Name }}' + optional: true + # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) + # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}' + # Optional volume that allows adding a container registry `auth.json` file (through a `dynamic-plugins-registry-auth` secret) + # to be used when installing plugins from secure container registries during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-registry-auth + secret: + defaultMode: 416 + optional: true + secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}' + - name: npmcacache + emptyDir: {} + - name: temp + emptyDir: {} + initContainers: + - name: install-dynamic-plugins + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" + # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. + # It could be replaced by a custom image based on this one. + # @default -- `quay.io/janus-idp/backstage-showcase:latest` + image: '{{ include "backstage.image" . }}' + command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + # This following variable is required for orchestrator to startup properly. + - name: MAX_ENTRY_SIZE + value: "30000000" + - name: CATALOG_INDEX_IMAGE + value: '{{ .Values.pluginCatalogIndex.image }}' + imagePullPolicy: "" + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/dynamic-plugins.yaml + name: dynamic-plugins + readOnly: true + subPath: dynamic-plugins.yaml + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + - mountPath: /opt/app-root/src/.config/containers + name: dynamic-plugins-registry-auth + readOnly: true + - mountPath: /opt/app-root/src/.npm/_cacache + name: npmcacache + - name: temp + mountPath: /tmp + workingDir: /opt/app-root/src installDir: /opt/app-root/src podAnnotations: checksum/dynamic-plugins: >- - {{- include "common.tplvalues.render" ( dict "value" .Values.global.dynamic "context" $) | sha256sum }} + {{- include "common.tplvalues.render" ( dict "value" + .Values.global.dynamic "context" $) | sha256sum }} ingress: host: "{{ .Values.global.host }}" metrics: @@ -276,7 +277,7 @@ upstream: allowPrivilegeEscalation: false capabilities: drop: - - ALL + - ALL resources: requests: cpu: 250m @@ -290,16 +291,16 @@ upstream: size: 1Gi mountPath: /var/lib/pgsql/data extraEnvVars: - - name: POSTGRESQL_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: '{{- include "postgresql.v1.secretName" . }}' + - name: POSTGRESQL_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: postgres-password + name: '{{- include "postgresql.v1.secretName" . }}' service: extraPorts: - - name: http-metrics - port: 9464 - targetPort: 9464 + - name: http-metrics + port: 9464 + targetPort: 9464 # -- OpenShift Route parameters route: @@ -413,56 +414,56 @@ orchestrator: # -- Orchestrator plugins and their configuration plugins: - # RHDHBUGS-1464: Note that the plugins here fetch the packages from their direct HTTP download URLs from the (official) Red Hat NPM Registry. - # Previously, we were using the "@redhat/plugin@version" form along with injecting a .npmrc Secret to resolve the "@redhat" scope, - # but this caused conflicting issues with user-provided .npmrc secrets. - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz" - integrity: sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ== - pluginConfig: - orchestrator: - dataIndexService: - url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz" - integrity: sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw== - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-orchestrator: - appIcons: - - name: orchestratorIcon - importName: OrchestratorIcon - dynamicRoutes: - - path: /orchestrator - importName: OrchestratorPage - menuItem: - icon: orchestratorIcon - text: Orchestrator - entityTabs: - - path: /workflows - title: Workflows - mountPoint: entity.page.workflows - mountPoints: - - mountPoint: entity.page.workflows/cards - importName: OrchestratorCatalogTab - config: - layout: - gridColumn: "1 / -1" - if: - anyOf: - - IsOrchestratorCatalogTabAvailable - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz" - integrity: sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ== - pluginConfig: - orchestrator: - dataIndexService: - url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} - - disabled: false - package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz" - integrity: sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw== - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} + # RHDHBUGS-1464: Note that the plugins here fetch the packages from their direct HTTP download URLs from the (official) Red Hat NPM Registry. + # Previously, we were using the "@redhat/plugin@version" form along with injecting a .npmrc Secret to resolve the "@redhat" scope, + # but this caused conflicting issues with user-provided .npmrc secrets. + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz" + integrity: sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ== + pluginConfig: + orchestrator: + dataIndexService: + url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz" + integrity: sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw== + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-orchestrator: + appIcons: + - name: orchestratorIcon + importName: OrchestratorIcon + dynamicRoutes: + - path: /orchestrator + importName: OrchestratorPage + menuItem: + icon: orchestratorIcon + text: Orchestrator + entityTabs: + - path: /workflows + title: Workflows + mountPoint: entity.page.workflows + mountPoints: + - mountPoint: entity.page.workflows/cards + importName: OrchestratorCatalogTab + config: + layout: + gridColumn: "1 / -1" + if: + anyOf: + - IsOrchestratorCatalogTabAvailable + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz" + integrity: sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ== + pluginConfig: + orchestrator: + dataIndexService: + url: http://sonataflow-platform-data-index-service.{{ .Release.Namespace }} + - disabled: false + package: "https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz" + integrity: sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw== + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} \ No newline at end of file From 952184626f10e6bcea77895bc003b3a82f558cc7 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:49:09 +0000 Subject: [PATCH 10/16] fix lint Signed-off-by: Fortune Ndlovu --- charts/backstage/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index e8904987..b92bd9c1 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -466,4 +466,4 @@ orchestrator: pluginConfig: dynamicPlugins: frontend: - red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} \ No newline at end of file + red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {} From 11ad7d56b1edab6776293ccc56b2683191b73047 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Thu, 11 Dec 2025 11:53:57 +0000 Subject: [PATCH 11/16] Add Values.global.pluginCatalogIndex.image Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 4 ++-- charts/backstage/values.schema.json | 2 +- charts/backstage/values.yaml | 15 +++++++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index fe2b2595..e9dec640 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -177,6 +177,8 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | +| global.pluginCatalogIndex | 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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | +| global.pluginCatalogIndex.image | OCI image for the plugin catalog index. Set to empty string to disable. | string | `"quay.io/rhdh/plugin-catalog-index:1.9"` | | nameOverride | | string | `"developer-hub"` | | orchestrator.enabled | | bool | `false` | | orchestrator.plugins | Orchestrator plugins and their configuration | list | `[{"disabled":false,"integrity":"sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz","pluginConfig":{"orchestrator":{"dataIndexService":{"url":"http://sonataflow-platform-data-index-service.{{ .Release.Namespace }}"}}}},{"disabled":false,"integrity":"sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-orchestrator":{"appIcons":[{"importName":"OrchestratorIcon","name":"orchestratorIcon"}],"dynamicRoutes":[{"importName":"OrchestratorPage","menuItem":{"icon":"orchestratorIcon","text":"Orchestrator"},"path":"/orchestrator"}],"entityTabs":[{"mountPoint":"entity.page.workflows","path":"/workflows","title":"Workflows"}],"mountPoints":[{"config":{"if":{"anyOf":["IsOrchestratorCatalogTabAvailable"]},"layout":{"gridColumn":"1 / -1"}},"importName":"OrchestratorCatalogTab","mountPoint":"entity.page.workflows/cards"}]}}}}},{"disabled":false,"integrity":"sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz","pluginConfig":{"orchestrator":{"dataIndexService":{"url":"http://sonataflow-platform-data-index-service.{{ .Release.Namespace }}"}}}},{"disabled":false,"integrity":"sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets":{}}}}}]` | @@ -197,8 +199,6 @@ Kubernetes: `>= 1.27.0-0` | orchestrator.sonataflowPlatform.resources.limits.memory | | string | `"1Gi"` | | orchestrator.sonataflowPlatform.resources.requests.cpu | | string | `"250m"` | | orchestrator.sonataflowPlatform.resources.requests.memory | | string | `"64Mi"` | -| pluginCatalogIndex | 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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | -| pluginCatalogIndex.image | OCI image for the plugin catalog index. Set to empty string to disable. | string | `"quay.io/rhdh/plugin-catalog-index:1.9"` | | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | | route.annotations | Route specific annotations | object | `{}` | | route.enabled | Enable the creation of the route resource | bool | `true` | diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 09e51851..bc1ba55d 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -4634,7 +4634,7 @@ }, { "name": "CATALOG_INDEX_IMAGE", - "value": "{{ .Values.pluginCatalogIndex.image }}" + "value": "{{ .Values.global.pluginCatalogIndex.image }}" } ], "image": "{{ include \"backstage.image\" . }}", diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index b92bd9c1..f0e8eecb 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -1,13 +1,12 @@ nameOverride: developer-hub -# -- 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. -pluginCatalogIndex: - # -- OCI image for the plugin catalog index. Set to empty string to disable. - image: "quay.io/rhdh/plugin-catalog-index:1.9" - global: + # -- 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. + pluginCatalogIndex: + # -- OCI image for the plugin catalog index. Set to empty string to disable. + image: "quay.io/rhdh/plugin-catalog-index:1.9" dynamic: # -- 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`). @@ -222,7 +221,7 @@ upstream: - name: MAX_ENTRY_SIZE value: "30000000" - name: CATALOG_INDEX_IMAGE - value: '{{ .Values.pluginCatalogIndex.image }}' + value: '{{ .Values.global.pluginCatalogIndex.image }}' imagePullPolicy: "" volumeMounts: - mountPath: /dynamic-plugins-root From 5c8e2b8c61b1a3741c97e518bf1b93c5c6f2809d Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Fri, 12 Dec 2025 13:07:25 +0000 Subject: [PATCH 12/16] Update: Move the field from global.pluginCatalogIndex to the root level and Update the CATALOG_INDEX_IMAGE environment variable in the install-dynamic-plugins init container to construct the image reference. Also simplify the catalog index documentation by removing duplicated private registry authentication instructions and linking to the official Red Hat Developer Hub documentation instead Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 5 +- charts/backstage/README.md.gotmpl | 2 +- charts/backstage/values.schema.json | 43 +++++++++---- charts/backstage/values.schema.tmpl.json | 41 +++++++++---- charts/backstage/values.yaml | 17 +++--- docs/catalog-index-configuration.md | 77 ++++-------------------- 6 files changed, 84 insertions(+), 101 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index e9dec640..b6c93c53 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -177,8 +177,6 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.pluginCatalogIndex | 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":"quay.io/rhdh/plugin-catalog-index:1.9"}` | -| global.pluginCatalogIndex.image | OCI image for the plugin catalog index. Set to empty string to disable. | string | `"quay.io/rhdh/plugin-catalog-index:1.9"` | | nameOverride | | string | `"developer-hub"` | | orchestrator.enabled | | bool | `false` | | orchestrator.plugins | Orchestrator plugins and their configuration | list | `[{"disabled":false,"integrity":"sha512-6G0YguzCM5nCDpOrIGJpLTXVMr6EBdIVqSXtsLH9RvBH25RTuFpfJ7q6eEp26DqveaiqUCfBpJ51smdjcsEzFQ==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-backend-dynamic/-/backstage-plugin-orchestrator-backend-dynamic-1.8.2.tgz","pluginConfig":{"orchestrator":{"dataIndexService":{"url":"http://sonataflow-platform-data-index-service.{{ .Release.Namespace }}"}}}},{"disabled":false,"integrity":"sha512-rnUA6iZ2JVAyASfwS4P9HeFmpqCgH6FQouzzg4s6lCPAsYUFvu6tifJ3df5lThXPUTJ2cDvvQgamU+4DiHP2jw==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator/-/backstage-plugin-orchestrator-1.8.2.tgz","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-orchestrator":{"appIcons":[{"importName":"OrchestratorIcon","name":"orchestratorIcon"}],"dynamicRoutes":[{"importName":"OrchestratorPage","menuItem":{"icon":"orchestratorIcon","text":"Orchestrator"},"path":"/orchestrator"}],"entityTabs":[{"mountPoint":"entity.page.workflows","path":"/workflows","title":"Workflows"}],"mountPoints":[{"config":{"if":{"anyOf":["IsOrchestratorCatalogTabAvailable"]},"layout":{"gridColumn":"1 / -1"}},"importName":"OrchestratorCatalogTab","mountPoint":"entity.page.workflows/cards"}]}}}}},{"disabled":false,"integrity":"sha512-N2hCn9RI/QVEoK56FAkGkSDbvfQCOIzVsJTwDX0kf//npO++2crRSJpB1Lr/m2UtYxfaXZX53p8sPcK3g8yWkQ==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic/-/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic-1.8.2.tgz","pluginConfig":{"orchestrator":{"dataIndexService":{"url":"http://sonataflow-platform-data-index-service.{{ .Release.Namespace }}"}}}},{"disabled":false,"integrity":"sha512-Pe0dn3g+YTK3jbl36E8nt4zdyH/3w+MWgRyFWPc2B0eV4/L/aRfRC4KxcktmHPdamRGXTIaXL6cFae8TZl8Htw==","package":"https://npm.registry.redhat.com/@redhat/backstage-plugin-orchestrator-form-widgets/-/backstage-plugin-orchestrator-form-widgets-1.8.2.tgz","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets":{}}}}}]` | @@ -199,6 +197,7 @@ Kubernetes: `>= 1.27.0-0` | orchestrator.sonataflowPlatform.resources.limits.memory | | string | `"1Gi"` | | orchestrator.sonataflowPlatform.resources.requests.cpu | | string | `"250m"` | | orchestrator.sonataflowPlatform.resources.requests.memory | | string | `"64Mi"` | +| pluginCatalogIndex | 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.9"}}` | | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | | route.annotations | Route specific annotations | object | `{}` | | route.enabled | Enable the creation of the route resource | bool | `true` | @@ -304,7 +303,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.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). diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index 60582c4d..85fbd611 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,7 +236,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.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). diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index bc1ba55d..3aa09142 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -40,18 +40,6 @@ "dynamic": { "additionalProperties": false, "properties": { - "catalogIndex": { - "additionalProperties": false, - "properties": { - "image": { - "default": "quay.io/rhdh/plugin-catalog-index:1.9", - "title": "Catalog index OCI image reference", - "type": "string" - } - }, - "title": "Catalog index configuration for automatic plugin discovery", - "type": "object" - }, "includes": { "default": [ "dynamic-plugins.default.yaml" @@ -292,6 +280,35 @@ "title": "orchestrator configuration", "type": "object" }, + "pluginCatalogIndex": { + "additionalProperties": false, + "properties": { + "image": { + "additionalProperties": false, + "properties": { + "registry": { + "default": "quay.io", + "title": "Plugin catalog index image registry", + "type": "string" + }, + "repository": { + "default": "rhdh/plugin-catalog-index", + "title": "Plugin catalog index image repository", + "type": "string" + }, + "tag": { + "default": "1.9", + "title": "Plugin catalog index image tag", + "type": "string" + } + }, + "title": "Plugin catalog index image settings", + "type": "object" + } + }, + "title": "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.", + "type": "object" + }, "route": { "additionalProperties": false, "properties": { @@ -4634,7 +4651,7 @@ }, { "name": "CATALOG_INDEX_IMAGE", - "value": "{{ .Values.global.pluginCatalogIndex.image }}" + "value": "{{ .Values.pluginCatalogIndex.image.registry }}/{{ .Values.pluginCatalogIndex.image.repository }}:{{ .Values.pluginCatalogIndex.image.tag }}" } ], "image": "{{ include \"backstage.image\" . }}", diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index f10cc33d..aefd9518 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -72,18 +72,6 @@ "type": "string" }, "default": [] - }, - "catalogIndex": { - "title": "Catalog index configuration for automatic plugin discovery", - "type": "object", - "additionalProperties": false, - "properties": { - "image": { - "title": "Catalog index OCI image reference", - "type": "string", - "default": "quay.io/rhdh/plugin-catalog-index:1.9" - } - } } } }, @@ -209,6 +197,35 @@ } } }, + "pluginCatalogIndex": { + "title": "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.", + "type": "object", + "additionalProperties": false, + "properties": { + "image": { + "title": "Plugin catalog index image settings", + "type": "object", + "additionalProperties": false, + "properties": { + "registry": { + "title": "Plugin catalog index image registry", + "type": "string", + "default": "quay.io" + }, + "repository": { + "title": "Plugin catalog index image repository", + "type": "string", + "default": "rhdh/plugin-catalog-index" + }, + "tag": { + "title": "Plugin catalog index image tag", + "type": "string", + "default": "1.9" + } + } + } + } + }, "test": { "title": "Test configuration for the Backstage chart.", "type": "object", diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index f0e8eecb..c6b2d1a6 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -1,12 +1,6 @@ nameOverride: developer-hub global: - # -- 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. - pluginCatalogIndex: - # -- OCI image for the plugin catalog index. Set to empty string to disable. - image: "quay.io/rhdh/plugin-catalog-index:1.9" dynamic: # -- 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`). @@ -221,7 +215,7 @@ upstream: - name: MAX_ENTRY_SIZE value: "30000000" - name: CATALOG_INDEX_IMAGE - value: '{{ .Values.global.pluginCatalogIndex.image }}' + value: '{{ .Values.pluginCatalogIndex.image.registry }}/{{ .Values.pluginCatalogIndex.image.repository }}:{{ .Values.pluginCatalogIndex.image.tag }}' imagePullPolicy: "" volumeMounts: - mountPath: /dynamic-plugins-root @@ -344,6 +338,15 @@ route: #
While each router may make its own decisions on which ports to expose, this is normally port 80. The only valid values are None, Redirect, or empty for disabled. insecureEdgeTerminationPolicy: "Redirect" +# -- 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. +pluginCatalogIndex: + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.9" + # -- Test pod parameters test: # -- Whether to enable the test-connection pod used for testing the Release using `helm test`. diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index 91f5d10c..e8177d27 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -2,84 +2,31 @@ The Helm chart supports loading default plugin configurations from an OCI container image (catalog index). For general information about how the catalog index works, see [Using a Catalog Index Image for Default Plugin Configurations](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/installing-plugins.md#using-a-catalog-index-image-for-default-plugin-configurations). -By default, the chart sets `pluginCatalogIndex.image` to `quay.io/rhdh/plugin-catalog-index:1.9`. - -## Overriding the Catalog Index Image - -To use a different catalog index image, such as a newer version or a mirrored image, use the `pluginCatalogIndex.image` field in your values file: +By default, the chart configures the plugin catalog index image using `pluginCatalogIndex.image` with `registry`, `repository`, and `tag` fields. You can override these values in your values file to use a different version or a mirrored image: ```yaml -# values.yaml pluginCatalogIndex: - image: "quay.io/rhdh/plugin-catalog-index:1.9" -``` - -Alternatively, you can override it via the command line: - -```console -helm upgrade -i redhat-developer/backstage \ - --set pluginCatalogIndex.image="quay.io/rhdh/plugin-catalog-index:1.9" + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.9" ``` ## Disabling the Catalog Index -To disable the catalog index feature and use only the `dynamic-plugins.default.yaml` bundled in the container image, set the image to an empty string: +To disable the catalog index feature and use only the `dynamic-plugins.default.yaml` bundled in the container image, set the image fields to empty strings: ```yaml # values.yaml pluginCatalogIndex: - image: "" + image: + registry: "" + repository: "" + tag: "" ``` ## Using a Private Registry -If your catalog index image is stored in a private registry that requires authentication, you can provide credentials by using the `dynamic-plugins-registry-auth` secret. - -The `auth.json` file is the standard [containers-auth.json(5)](https://github.com/containers/image/blob/main/docs/containers-auth.json.5.md) format used by `skopeo`, `podman`, and other container tools. It stores registry credentials that allow these tools to pull images from authenticated registries. - -**1:** Create the `auth.json` file with your registry credentials: - -```json -{ - "auths": { - "my-registry.example.com": { - "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=" - } - } -} -``` - -The `auth` value is a base64-encoded string of `username:password`. You can generate it with the following commands: - -```console -echo -n 'myusername:mypassword' | base64 -``` - -**2:** Create the Kubernetes secret from the `auth.json` file: - -```console -kubectl create secret generic -dynamic-plugins-registry-auth \ - --from-file=auth.json=./auth.json \ - -n -``` - -Alternatively, you can use a declarative YAML manifest: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: -dynamic-plugins-registry-auth -type: Opaque -stringData: - auth.json: | - { - "auths": { - "my-registry.example.com": { - "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=" - } - } - } -``` +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. -This secret is automatically mounted into the `install-dynamic-plugins` init container at `/opt/app-root/src/.config/containers`, allowing `skopeo` to authenticate when pulling images from private registries. +For detailed instructions on configuring private registry authentication, see the [official Red Hat Developer Hub documentation](https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.8/html/installing_and_viewing_plugins_in_red_hat_developer_hub/assembly-third-party-plugins#proc-load-plugin-oci-image_assembly-install-third-party-plugins-rhdh). From 359a2e3b984afd982a8f55a3b51d630a83c21b4f Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Fri, 12 Dec 2025 13:13:12 +0000 Subject: [PATCH 13/16] fixup: update to no show how to disable the index since the dynamic-plugins.default.yaml file is being moved from the RHDH container to the catalog index image Signed-off-by: Fortune Ndlovu --- docs/catalog-index-configuration.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index e8177d27..57ba8738 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -12,19 +12,6 @@ pluginCatalogIndex: tag: "1.9" ``` -## Disabling the Catalog Index - -To disable the catalog index feature and use only the `dynamic-plugins.default.yaml` bundled in the container image, set the image fields to empty strings: - -```yaml -# values.yaml -pluginCatalogIndex: - image: - 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 99875dda0ac7a4a8bbd6fd11424181e35d2bd70a Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Fri, 12 Dec 2025 14:03:36 +0000 Subject: [PATCH 14/16] Rename and moved from pluginCatalogIndex to upstream.catalog-index Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 4 +-- charts/backstage/README.md.gotmpl | 2 +- charts/backstage/values.schema.json | 31 +----------------------- charts/backstage/values.schema.tmpl.json | 29 ---------------------- charts/backstage/values.yaml | 19 +++++++-------- docs/catalog-index-configuration.md | 13 +++++----- 6 files changed, 20 insertions(+), 78 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index b6c93c53..4adc5f19 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -197,7 +197,6 @@ Kubernetes: `>= 1.27.0-0` | orchestrator.sonataflowPlatform.resources.limits.memory | | string | `"1Gi"` | | orchestrator.sonataflowPlatform.resources.requests.cpu | | string | `"250m"` | | orchestrator.sonataflowPlatform.resources.requests.memory | | string | `"64Mi"` | -| pluginCatalogIndex | 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.9"}}` | | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | | route.annotations | Route specific annotations | object | `{}` | | route.enabled | Enable the creation of the route resource | bool | `true` | @@ -222,6 +221,7 @@ Kubernetes: `>= 1.27.0-0` | upstream.backstage.extraVolumes[0] | Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. | object | `{"ephemeral":{"volumeClaimTemplate":{"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}}}}},"name":"dynamic-plugins-root"}` | | upstream.backstage.extraVolumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage | Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. | string | `"5Gi"` | | upstream.backstage.initContainers[0].image | Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. It could be replaced by a custom image based on this one. | string | `quay.io/janus-idp/backstage-showcase:latest` | +| upstream.catalog-index | 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.9"}}` | ## Opinionated Backstage deployment @@ -303,7 +303,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `upstream.catalog-index.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). diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index 85fbd611..850b5750 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,7 +236,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `pluginCatalogIndex.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. +The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `upstream.catalog-index.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). diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 3aa09142..35a2c363 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -280,35 +280,6 @@ "title": "orchestrator configuration", "type": "object" }, - "pluginCatalogIndex": { - "additionalProperties": false, - "properties": { - "image": { - "additionalProperties": false, - "properties": { - "registry": { - "default": "quay.io", - "title": "Plugin catalog index image registry", - "type": "string" - }, - "repository": { - "default": "rhdh/plugin-catalog-index", - "title": "Plugin catalog index image repository", - "type": "string" - }, - "tag": { - "default": "1.9", - "title": "Plugin catalog index image tag", - "type": "string" - } - }, - "title": "Plugin catalog index image settings", - "type": "object" - } - }, - "title": "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.", - "type": "object" - }, "route": { "additionalProperties": false, "properties": { @@ -4651,7 +4622,7 @@ }, { "name": "CATALOG_INDEX_IMAGE", - "value": "{{ .Values.pluginCatalogIndex.image.registry }}/{{ .Values.pluginCatalogIndex.image.repository }}:{{ .Values.pluginCatalogIndex.image.tag }}" + "value": "{{ (index .Values \"catalog-index\").image.registry }}/{{ (index .Values \"catalog-index\").image.repository }}:{{ (index .Values \"catalog-index\").image.tag }}" } ], "image": "{{ include \"backstage.image\" . }}", diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index aefd9518..dd43885c 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -197,35 +197,6 @@ } } }, - "pluginCatalogIndex": { - "title": "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.", - "type": "object", - "additionalProperties": false, - "properties": { - "image": { - "title": "Plugin catalog index image settings", - "type": "object", - "additionalProperties": false, - "properties": { - "registry": { - "title": "Plugin catalog index image registry", - "type": "string", - "default": "quay.io" - }, - "repository": { - "title": "Plugin catalog index image repository", - "type": "string", - "default": "rhdh/plugin-catalog-index" - }, - "tag": { - "title": "Plugin catalog index image tag", - "type": "string", - "default": "1.9" - } - } - } - } - }, "test": { "title": "Test configuration for the Backstage chart.", "type": "object", diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index c6b2d1a6..c6d723fd 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -215,7 +215,7 @@ upstream: - name: MAX_ENTRY_SIZE value: "30000000" - name: CATALOG_INDEX_IMAGE - value: '{{ .Values.pluginCatalogIndex.image.registry }}/{{ .Values.pluginCatalogIndex.image.repository }}:{{ .Values.pluginCatalogIndex.image.tag }}' + value: '{{ (index .Values "catalog-index").image.registry }}/{{ (index .Values "catalog-index").image.repository }}:{{ (index .Values "catalog-index").image.tag }}' imagePullPolicy: "" volumeMounts: - mountPath: /dynamic-plugins-root @@ -248,6 +248,14 @@ upstream: enabled: false path: /metrics port: http-metrics + # -- 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. + catalog-index: + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.9" postgresql: enabled: true postgresqlDataDir: /var/lib/pgsql/data/userdata @@ -338,15 +346,6 @@ route: #
While each router may make its own decisions on which ports to expose, this is normally port 80. The only valid values are None, Redirect, or empty for disabled. insecureEdgeTerminationPolicy: "Redirect" -# -- 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. -pluginCatalogIndex: - image: - registry: quay.io - repository: rhdh/plugin-catalog-index - tag: "1.9" - # -- Test pod parameters test: # -- Whether to enable the test-connection pod used for testing the Release using `helm test`. diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index 57ba8738..2dd952d1 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -2,14 +2,15 @@ The Helm chart supports loading default plugin configurations from an OCI container image (catalog index). For general information about how the catalog index works, see [Using a Catalog Index Image for Default Plugin Configurations](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/installing-plugins.md#using-a-catalog-index-image-for-default-plugin-configurations). -By default, the chart configures the plugin catalog index image using `pluginCatalogIndex.image` with `registry`, `repository`, and `tag` fields. You can override these values in your values file to use a different version or a mirrored image: +By default, the chart configures the catalog index image using `upstream.catalog-index.image` with `registry`, `repository`, and `tag` fields. You can override these values in your values file to use a different version or a mirrored image: ```yaml -pluginCatalogIndex: - image: - registry: quay.io - repository: rhdh/plugin-catalog-index - tag: "1.9" +upstream: + catalog-index: + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.9" ``` ## Using a Private Registry From 1b33fb81b8b7e1462bee6ac09557be048612400a Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Tue, 16 Dec 2025 09:43:53 +0000 Subject: [PATCH 15/16] reference global.catalogIndex Signed-off-by: Fortune Ndlovu --- charts/backstage/README.md | 4 ++-- charts/backstage/README.md.gotmpl | 2 +- charts/backstage/values.schema.json | 2 +- charts/backstage/values.yaml | 19 ++++++++++--------- docs/catalog-index-configuration.md | 6 +++--- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 4adc5f19..add2999e 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -172,6 +172,7 @@ 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.9"}}` | | 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 `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | @@ -221,7 +222,6 @@ Kubernetes: `>= 1.27.0-0` | upstream.backstage.extraVolumes[0] | Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. | object | `{"ephemeral":{"volumeClaimTemplate":{"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}}}}},"name":"dynamic-plugins-root"}` | | upstream.backstage.extraVolumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage | Size of the volume that will contain the dynamic plugins. It should be large enough to contain all the plugins. | string | `"5Gi"` | | upstream.backstage.initContainers[0].image | Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. It could be replaced by a custom image based on this one. | string | `quay.io/janus-idp/backstage-showcase:latest` | -| upstream.catalog-index | 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.9"}}` | ## Opinionated Backstage deployment @@ -303,7 +303,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `upstream.catalog-index.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. +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). diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index 850b5750..bb364cc8 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,7 +236,7 @@ upstream: ### Catalog Index Configuration -The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via `upstream.catalog-index.image` (with `registry`, `repository`, and `tag` fields) and lets you use a pre-defined set of dynamic plugins. +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). diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 35a2c363..62968477 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -4622,7 +4622,7 @@ }, { "name": "CATALOG_INDEX_IMAGE", - "value": "{{ (index .Values \"catalog-index\").image.registry }}/{{ (index .Values \"catalog-index\").image.repository }}:{{ (index .Values \"catalog-index\").image.tag }}" + "value": "{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}" } ], "image": "{{ include \"backstage.image\" . }}", diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index c6d723fd..0456b8ae 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -31,6 +31,15 @@ global: # -- Instead of generating a secret value, use the following value value: "" + # -- 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. + catalogIndex: + image: + registry: quay.io + repository: rhdh/plugin-catalog-index + tag: "1.9" + # -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) # @default -- Use Openshift compatible settings upstream: @@ -215,7 +224,7 @@ upstream: - name: MAX_ENTRY_SIZE value: "30000000" - name: CATALOG_INDEX_IMAGE - value: '{{ (index .Values "catalog-index").image.registry }}/{{ (index .Values "catalog-index").image.repository }}:{{ (index .Values "catalog-index").image.tag }}' + value: '{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}' imagePullPolicy: "" volumeMounts: - mountPath: /dynamic-plugins-root @@ -248,14 +257,6 @@ upstream: enabled: false path: /metrics port: http-metrics - # -- 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. - catalog-index: - image: - registry: quay.io - repository: rhdh/plugin-catalog-index - tag: "1.9" postgresql: enabled: true postgresqlDataDir: /var/lib/pgsql/data/userdata diff --git a/docs/catalog-index-configuration.md b/docs/catalog-index-configuration.md index 2dd952d1..e36411a5 100644 --- a/docs/catalog-index-configuration.md +++ b/docs/catalog-index-configuration.md @@ -2,11 +2,11 @@ The Helm chart supports loading default plugin configurations from an OCI container image (catalog index). For general information about how the catalog index works, see [Using a Catalog Index Image for Default Plugin Configurations](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/installing-plugins.md#using-a-catalog-index-image-for-default-plugin-configurations). -By default, the chart configures the catalog index image using `upstream.catalog-index.image` with `registry`, `repository`, and `tag` fields. You can override these values in your values file to use a different version or a mirrored image: +By default, the chart configures the catalog index image using `global.catalogIndex.image` with `registry`, `repository`, and `tag` fields. You can override these values in your values file to use a different version or a mirrored image: ```yaml -upstream: - catalog-index: +global: + catalogIndex: image: registry: quay.io repository: rhdh/plugin-catalog-index From dc95d69e6d854279be95e5f4f7bdb3aec5b54653 Mon Sep 17 00:00:00 2001 From: Fortune Ndlovu Date: Wed, 17 Dec 2025 11:49:16 +0000 Subject: [PATCH 16/16] fixup: added the catalogIndex schema to the template file values.schema.tmpl.json. This is the source file that pre-commit uses to generate values.schema.json. Signed-off-by: Fortune Ndlovu --- charts/backstage/values.schema.json | 29 ++++++++++++++++++++++++ charts/backstage/values.schema.tmpl.json | 29 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 62968477..4a98733d 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -32,6 +32,35 @@ "title": "Enable service authentication within Backstage instance", "type": "object" }, + "catalogIndex": { + "additionalProperties": false, + "properties": { + "image": { + "additionalProperties": false, + "properties": { + "registry": { + "default": "quay.io", + "title": "Catalog index image registry", + "type": "string" + }, + "repository": { + "default": "rhdh/plugin-catalog-index", + "title": "Catalog index image repository", + "type": "string" + }, + "tag": { + "default": "1.9", + "title": "Catalog index image tag", + "type": "string" + } + }, + "title": "Catalog index image configuration", + "type": "object" + } + }, + "title": "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.", + "type": "object" + }, "clusterRouterBase": { "default": "apps.example.com", "title": "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.", diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index dd43885c..5e461a16 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -103,6 +103,35 @@ } } } + }, + "catalogIndex": { + "title": "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.", + "type": "object", + "additionalProperties": false, + "properties": { + "image": { + "title": "Catalog index image configuration", + "type": "object", + "additionalProperties": false, + "properties": { + "registry": { + "title": "Catalog index image registry", + "type": "string", + "default": "quay.io" + }, + "repository": { + "title": "Catalog index image repository", + "type": "string", + "default": "rhdh/plugin-catalog-index" + }, + "tag": { + "title": "Catalog index image tag", + "type": "string", + "default": "1.9" + } + } + } + } } } },