Skip to content

feat!: introduce new standalone RHDH Chart [RHDHPLAN-1058]#438

Draft
rm3l wants to merge 83 commits into
redhat-developer:mainfrom
rm3l:RHDHPLAN-1058--improve-helm-chart-configuration-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency
Draft

feat!: introduce new standalone RHDH Chart [RHDHPLAN-1058]#438
rm3l wants to merge 83 commits into
redhat-developer:mainfrom
rm3l:RHDHPLAN-1058--improve-helm-chart-configuration-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency

Conversation

@rm3l

@rm3l rm3l commented Jun 17, 2026

Copy link
Copy Markdown
Member
  • feat: add standalone RHDH Helm chart without upstream subchart dependency
  • deprecate backstage chart in favor of the new standalone rhdh chart
  • run pre-commit hooks

Description of the change

Which issue(s) does this PR fix or relate to

ref RHDHPLAN-1058

How to test changes / Special notes to the reviewer

Checklist

  • For each Chart updated, version bumped in the corresponding Chart.yaml according to Semantic Versioning.
  • For each Chart updated, variables are documented in the values.yaml and added to the corresponding README.md. The pre-commit utility can be used to generate the necessary content. Run pre-commit run --all-files to run the hooks and then push any resulting changes. The pre-commit Workflow will enforce this and warn you if needed.
  • JSON Schema template updated and re-generated the raw schema via the pre-commit hook.
  • Tests pass using the Chart Testing tool and the ct lint command.
  • If you updated the orchestrator-infra chart, make sure the versions of the Knative CRDs are aligned with the versions of the CRDs installed by the OpenShift Serverless operators declared in the values.yaml file. See Installing Knative Eventing and Knative Serving CRDs for more details.

rm3l added 3 commits June 17, 2026 08:50
…ency

Helm cannot merge lists, so when users set extraVolumes/extraEnvVars on
the current chart, the entire default list is replaced — forcing them to
copy-paste all system defaults just to add one item. This is a Day 2
maintenance burden that grows with every release.

This new chart at charts/rhdh/ owns all Kubernetes templates directly
and uses an "add, don't replace" pattern: system-required volumes,
mounts, env vars, and init containers are hardcoded in the Deployment
template, while user-provided values are always appended. Users can now
add a volume without knowing or duplicating the system defaults.

The values layout is flattened to match helm-create conventions
(replicaCount, image, service at root level) — no more navigating
global.*/upstream.backstage.* nesting to set basic options.

Assisted-by: Claude
The new rhdh chart owns all Kubernetes templates directly and no
longer depends on the upstream Backstage subchart, so the weekly
sync workflow and its helper script are no longer needed.

Assisted-by: Claude
@rm3l rm3l changed the title feat!: introduce new standalone RHDH Chart [RHDHPLAN 1058] feat!: introduce new standalone RHDH Chart [RHDHPLAN-1058] Jun 17, 2026
Comment thread charts/rhdh/templates/tests/test-connection.yaml Fixed
rm3l added 17 commits June 17, 2026 09:27
…ove-helm-chart-configuration-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency

# Conflicts:
#	.github/workflows/sync-upstream-backstage.yaml
Port test scenarios from charts/backstage/ci/ with key paths adjusted
for the flat values layout. The custom-dynamic-pvc-claim-spec scenario
is dropped because the new chart hardcodes the dynamic-plugins-root
volume (user volumes are appended, not replaced).

Assisted-by: Claude
Add global.imageRegistry, global.imagePullSecrets, and
global.defaultStorageClass so they flow through to both the postgresql
subchart and the rhdh chart's own templates. Image helpers now delegate
to bitnami common's common.images.image, and imagePullSecrets are
merged from both global and root-level sources. Lightspeed container
images converted from strings to structured registry/repository/tag
maps so global.imageRegistry applies uniformly to all containers.

Also pins the test pod image to curl/curl:8.9.1 instead of latest,
adds automountServiceAccountToken: false and ephemeral-storage
requests to the test pod (SonarCloud findings).

Assisted-by: Claude
The previous version (12.10.0) was far behind. The new version
requires global.security.allowInsecureImages=true since we use a
Fedora-based PostgreSQL image instead of the bitnami one.

Assisted-by: Claude
…ion-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency
…ove-helm-chart-configuration-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency

# Conflicts:
#	.github/workflows/sync-upstream-backstage.yaml
…anch

chart-testing's --upgrade flag checks out the target branch and tries
to build dependencies for the chart there. For brand-new charts like
charts/rhdh/ that do not exist on main yet, this causes helm
dependency build to fail.

Make --upgrade conditional: when a specific chart is tested, check
whether its Chart.yaml exists on the target branch first. If not,
skip the upgrade test and only run a fresh install.

Also rename the backstageChartChanged output to orchestratorCrdsNeeded
and include charts/rhdh so that Knative and SonataFlow CRDs are
installed for both charts' orchestrator CI scenarios.
On vanilla K8s (KinD), there is no SCC to assign a common UID to all
containers in a pod. Set fsGroup so shared volumes (e.g. RAG data)
are group-writable across init containers and sidecars that may run
as different UIDs. Also disable the route, which is not available on
KinD.
Without a default appConfig, no app-config ConfigMap is created and
the RHDH application lacks essential configuration (base URLs, CORS,
database connection, backend auth), causing it to fail to start.

Add a default appConfig matching the backstage chart, providing:
- app.baseUrl and backend.baseUrl from rhdh.hostname
- backend.cors.origin
- backend.database.connection (postgres user, password from env var)
- backend.auth.externalAccess (legacy service-to-service auth)
…ion-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency
rm3l added 2 commits July 7, 2026 18:54
Accept incoming changes, bumping backstage chart to 6.2.1.
Keep our deletion of sync-upstream-backstage.yaml.
…[RHIDP-14726]

Align the rhdh chart with the backstage chart change from PR redhat-developer#453:
use `enabled: true` instead of `disabled: false` for dynamic plugin
entries in values, schema, CI files, and documentation.

Assisted-by: Claude
rm3l added 3 commits July 7, 2026 19:02
…ack to 0.5.2

Use --no-preserve=mode,ownership when copying RAG data so the sidecar
(UID 1001) can access files written by the init container (UID 65532).
Pre-create the notebooks subdirectory and chmod the copied data to
prevent PermissionError on vanilla Kubernetes.

Also bump lightspeed-stack sidecar from 0.5.1 to 0.5.2.

Refs:
- redhat-developer#460
- redhat-developer#461

Assisted-by: Claude
The RAG init container permission fix (--no-preserve=mode,ownership +
chmod) makes a shared UID unnecessary. Only fsGroup is needed, matching
the backstage chart CI setup.

Assisted-by: Claude
rm3l added 29 commits July 16, 2026 01:12
The `next` catalog index image is currently unstable. Pin to 1.10.2
until it stabilizes.

Assisted-by: Claude
Reflects the same bump from redhat-developer#475 on the main branch.

Assisted-by: Claude
…ntainer

- Replace auth.backend.existingSecret with auth.backend.existingSecretRef
  (name + key fields, key defaults to "backend-secret")
- Split envFrom into envFromOverride (full replace) and extraEnvFrom (append),
  both accepting raw Kubernetes envFrom entries with tplvalues.render support
- Make install-dynamic-plugins init container configurable: commandOverride,
  argsOverride, extraEnv, extraVolumeMounts, resources, and securityContext
  (falls back to containerSecurityContext when empty)

Assisted-by: Claude
The default appConfig referenced ${POSTGRESQL_ADMIN_PASSWORD} but the
deployment template injects POSTGRES_PASSWORD into the RHDH pod.
POSTGRESQL_ADMIN_PASSWORD only exists on the postgresql subchart pod.

Assisted-by: Claude
Replace toYaml with common.tplvalues.render for all user-facing values
so that Go template expressions embedded in values.yaml are evaluated
at render time. This enables patterns like:

  commonAnnotations:
    custom/sha: "{{ .Release.Name }}-{{ .Chart.Version }}"

Changes across 14 template files:
- _helpers.tpl: commonLabels in rhdh.labels
- deployment.yaml: podSecurityContext, containerSecurityContext,
  resources, 3 probes, init container securityContext, 3 volume specs
- commonAnnotations in all resource templates
- ingress.yaml: ingress.annotations
- servicemonitor.yaml: serviceMonitor.labels and .annotations
- httproute.yaml: parentRefs and hostnames

Kept toYaml for: deep-copy idiom (_helpers.tpl), internal helper output,
service.yaml CIDR/ipFamilies, httproute matches/filters/timeouts, tests.

Assisted-by: Claude
…tions

Change lightspeed type from ["boolean", "object"] to "object" and set
additionalProperties to false for stricter validation.

Add schema definitions for all lightspeed sub-fields:
- config: stack/server/profile with existingConfigMap {name, key}
- existingSecretRef: string for envFrom secret injection
- ragInit: image, imagePullPolicy, commandOverride, argsOverride,
  extraEnv, extraVolumeMounts, resources, securityContext
- core: same shape as ragInit

Assisted-by: Claude
All sub-containers (dynamicPlugins.initContainer, lightspeed.core,
lightspeed.ragInit) already use commandOverride. Rename the main
container's field for API consistency.

Assisted-by: Claude
Convention: existingSecretRef: {name, key} for single-key references,
existingSecret: "name" for whole-secret injection via envFrom.

Renames:
- lightspeed.existingSecretRef → lightspeed.existingSecret
- orchestrator.sonataflowPlatform.externalDB.secretRef →
  orchestrator.sonataflowPlatform.externalDB.existingSecret

auth.backend.existingSecretRef is unchanged (correctly uses {name, key}
for single-key reference).

Assisted-by: Claude
Replace .Release.Name with rhdh.fullname in resource names so that
nameOverride and fullnameOverride are respected consistently.

Changes:
- _helpers.tpl: rhdh.backend-secret-name, rhdh.lightspeed.configMapName,
  rhdh.orchestrator.dbJobName
- orchestrator/network-policies.yaml: all 4 NetworkPolicy names

PostgreSQL helpers intentionally kept using .Release.Name — the bitnami
subchart names its resources that way.

Assisted-by: Claude
Add extraArgs field to dynamicPlugins.initContainer, lightspeed.ragInit,
and lightspeed.core. extraArgs appends arguments after defaults when
argsOverride is not set; ignored when argsOverride provides full
replacement.

Assisted-by: Claude
Add externalDatabase section for connecting to an external PostgreSQL
instance when the built-in subchart is disabled (postgresql.enabled:
false).

New values:
  externalDatabase:
    host: ""
    port: 5432
    user: "postgres"
    existingSecretRef:
      name: ""
      key: "password"

When postgresql.enabled is false and externalDatabase.host is set,
the deployment injects POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER,
and POSTGRES_PASSWORD env vars from the external config. When neither
is set, no database env vars are injected (BYO via extraEnv).

Also updates rhdh.postgresql.host helper to return externalDatabase.host
when the built-in database is disabled.

Adds CI test values: with-external-db-values.yaml and
with-extra-app-config-values.yaml.

Assisted-by: Claude
Wire the Bitnami common.storage.class helper into the ephemeral volume
spec so that global.defaultStorageClass is applied automatically.

Add dynamicPlugins.volume.storageClassName for direct overrides. When
empty, the cluster default StorageClass is used. Set to "-" to
explicitly disable dynamic provisioning (renders storageClassName: "").

An empty string is never rendered as storageClassName — only non-empty
values or the explicit "-" opt-out produce the field, avoiding the
Kubernetes semantic difference between omitted and empty-string.

Assisted-by: Claude
Replace the nested ephemeral.volumeClaimTemplate.spec structure with
flat fields under dynamicPlugins.volume.ephemeral (storageClassName,
accessModes, resources). The deployment template builds the proper
Kubernetes ephemeral volume spec from these fields.

Move storageClassName into the ephemeral section since it only applies
to that volume type.

Assisted-by: Claude
Reserve version headroom for potential updates to the legacy chart
before the rhdh chart is merged, making rebase conflicts explicit.

Assisted-by: Claude
…ove-helm-chart-configuration-experience-via-standalone-rhdh-helm-chart-without-backstage-subchart-dependency
…ction flags

Use a fixed `ct-charts` namespace for all `ct install` runs so that
pre-created Kubernetes resources (Secrets, ConfigMaps) persist across
ci/ values file tests. This replaces the per-chart test injection flags
(`test.injectTestNpmrcSecret`, `test.injectTestLightspeedResources`)
with resource creation in the CI action, keeping the chart API clean.

Also sets up an external PostgreSQL instance for the `with-external-db`
CI test, deployed via the same Bitnami chart version and image declared
in the rhdh chart dependency.

Assisted-by: Claude
Remove openshift.route.enabled and test.enabled from ci/ values files
since these are already set via --helm-extra-set-args in the CI action.

Assisted-by: Claude
The dynamic-plugins-npmrc volume is optional in the deployment, so no
dedicated ci/ values file is needed to exercise it. Comment out the
corresponding secret creation in the CI action for future reference.

Assisted-by: Claude
The Bitnami common.storage.class helper does not treat "-" as a special
value to disable dynamic provisioning.

Assisted-by: Claude
… setup

Add dynamicPlugins.maxEntrySize to values.yaml so users can configure
the MAX_ENTRY_SIZE env var for the install-dynamic-plugins init container.

Fix the external PostgreSQL CI setup to pass the Fedora/sclorg-specific
env var (POSTGRESQL_ADMIN_PASSWORD) and data directory, which the image
requires to start.

Assisted-by: Claude
…initImage

Reduce ci/ values files from 9 to 4 by merging related test scenarios:
- with-external-db now also tests orchestrator with external DB
- with-custom-configuration merges extraAppConfig, lightspeed existing
  config, lightspeed service host, and orchestrator
- Drop low-value files (custom test pod image, disabled test pod)

Remove dbCreationJob.initImage — the wait-for-db init container now
reuses dbCreationJob.image.

Assisted-by: Claude
Skip plugin installation in CI to speed up test cycles. The chart
features under test (deployment, config, probes) don't depend on
actual plugins.

Assisted-by: Claude
Prevents a race condition where Backstage starts before the bundled
PostgreSQL is ready, causing built-in plugins to fail with
ECONNREFUSED and the pod to get stuck (alive but not ready).

The init container reuses the chart's PostgreSQL image, runs after
the dynamic-plugins and lightspeed-rag-init init containers, and is
conditionally included only when a database is configured
(postgresql.enabled or externalDatabase.host).

Assisted-by: Claude
With persistence disabled in CI, PostgreSQL writes to an emptyDir
that counts against the 20Mi ephemeral-storage limit, causing the
pod to be evicted during initdb. Raise to 200Mi.

Assisted-by: Claude
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
3.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants