Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/actions/test-charts/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ runs:
--values "$VALUES_FILE" 2>&1) || { echo "$output"; exit 1; }
done

# Mirrored-registry and StorageClass assertions on the rendered manifests (no cluster needed).
- name: Rendered values assertions
if: steps.list-changed.outputs.changed == 'true' && inputs.chart == 'charts/rhdh'
shell: bash
env:
INPUT_CHART: ${{ inputs.chart }}
run: |
helm dependency build "$INPUT_CHART"
./hack/assert-rendered-values.sh "$INPUT_CHART"

- name: Generate KinD Config
if: steps.list-changed.outputs.changed == 'true'
shell: bash
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Before making a contribution to the charts in this repository, you will need to

- Run `helm template` on the changes you're making to ensure they are correctly rendered into Kubernetes manifests.
- Lint tests have been run for the Chart using the [Chart Testing](https://github.com/helm/chart-testing) tool and the `ct lint` command.
- For the [rhdh](./charts/rhdh) chart, run `./hack/assert-rendered-values.sh` (after `helm dependency build charts/rhdh`) to check that every rendered image honours `global.imageRegistry` and that the dynamic plugins volume honours the StorageClass settings. CI runs it too.
- For each Chart updated, version bumped in the corresponding `Chart.yaml` according to [Semantic Versioning](http://semver.org/).
- For each Chart updated, ensure variables are documented in the corresponding `values.yaml` file and the [pre-commit](https://pre-commit.com/) hook has been run with `pre-commit run --all-files` to generate the corresponding `README.md` documentation. The [pre-commit Workflow](./.github/workflows/pre-commit.yaml) will enforce this and warn you if needed.
- JSON Schema template updated and re-generated the raw schema via the `pre-commit` hook.
Expand Down
2 changes: 1 addition & 1 deletion charts/rhdh/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: redhat-developer-hub
type: application
version: 3.5.17
version: 3.5.18
appVersion: 2.2.0
annotations:
artifacthub.io/category: integration-delivery
Expand Down
4 changes: 2 additions & 2 deletions charts/rhdh/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# RHDH Helm Chart for OpenShift and Kubernetes

![Version: 3.5.17](https://img.shields.io/badge/Version-3.5.17-informational?style=flat-square)
![Version: 3.5.18](https://img.shields.io/badge/Version-3.5.18-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.
Expand Down Expand Up @@ -36,7 +36,7 @@ For the **Generally Available** version of this chart, see:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart

helm install my-rhdh redhat-developer/redhat-developer-hub --version 3.5.17
helm install my-rhdh redhat-developer/redhat-developer-hub --version 3.5.18
```

## Introduction
Expand Down
17 changes: 17 additions & 0 deletions charts/rhdh/ci/with-custom-storage-class-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# CI: provision the dynamic plugins ephemeral volume through an explicit StorageClass
# instead of the cluster default. The test action creates `custom-sc` before `ct install`.
dynamicPlugins:
includes: []
volume:
type: ephemeral
ephemeral:
storageClassName: custom-sc
intelligentAssistant:
plugins: []
okp:
route:
enabled: false
ingress:
enabled: false
orchestrator:
plugins: []
152 changes: 152 additions & 0 deletions hack/assert-rendered-values.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/env bash
#
# Renders the rhdh chart with `helm template` and asserts the values that a
# constrained cluster (mirrored registry only, no default StorageClass) relies on:
# - global.imageRegistry is applied to every rendered image reference,
# - the helm test pod image follows test.image.*,
# - the dynamic plugins volume honours the StorageClass settings.
#
# Usage: hack/assert-rendered-values.sh [chart-dir] (default: charts/rhdh)
# Requires helm and yq (mikefarah v4); run `helm dependency build <chart-dir>` first.

set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
CHART="${1:-${REPO_ROOT}/charts/rhdh}"
MIRROR="mirror.local"

failures=0
checks=0

pass() {
checks=$((checks + 1))
echo " ok: $1"
}

fail() {
checks=$((checks + 1))
failures=$((failures + 1))
echo " FAIL: $1" >&2
}

render() {
helm template test-release "${CHART}" "$@"
}

# Prints every image reference in the rendered manifests: `image` string fields
# (containers, initContainers, test pod, CRs) and *_IMAGE / *_IMAGES env values.
list_images() {
yq -N '
(.. | select(tag == "!!map" and has("image")) | .image | select(tag == "!!str")),
(.. | select(tag == "!!map" and has("name") and has("value"))
| select(.name | test("_IMAGES?$")) | .value | select(tag == "!!str")
| split(",") | .[] | sub("^[^=/]+=", ""))
' | { grep -v '^$' || true; } | sort -u
}

assert_images_mirrored() {
local label=$1
shift
local images
images=$(render --set global.imageRegistry="${MIRROR}" "$@" | list_images)
if [[ -z "${images}" ]]; then
fail "${label}: no image references found in the rendered output"
return
fi
local bad
bad=$(grep -v "^${MIRROR//./\\.}/" <<<"${images}" || true)
if [[ -n "${bad}" ]]; then
fail "${label}: images not under ${MIRROR}/: $(tr '\n' ' ' <<<"${bad}")"
else
pass "${label}: $(wc -l <<<"${images}" | tr -d ' ') images under ${MIRROR}/"
fi
}

assert_equals() {
local label=$1 expected=$2 actual=$3
if [[ "${actual}" == "${expected}" ]]; then
pass "${label}"
else
fail "${label}: expected '${expected}', got '${actual}'"
fi
}

plugins_root_volume() {
yq -N 'select(.kind == "Deployment") | .spec.template.spec.volumes[] | select(.name == "dynamic-plugins-root")'
}

echo "==> global.imageRegistry=${MIRROR} applies to every rendered image"
assert_images_mirrored "default values"
for ci_values in "${CHART}"/ci/*-values.yaml; do
[[ -f "${ci_values}" ]] || continue
assert_images_mirrored "$(basename "${ci_values}")" --values "${ci_values}"
done
# Optional images that no CI scenario enables.
assert_images_mirrored "optional images enabled" \
--set intelligentAssistant.okp.enabled=true \
--set orchestrator.enabled=true \
--set orchestrator.sonataflowPlatform.dataIndex.image.registry=quay.io \
--set orchestrator.sonataflowPlatform.dataIndex.image.repository=ci/data-index \
--set orchestrator.sonataflowPlatform.dataIndex.image.tag=1.0 \
--set orchestrator.sonataflowPlatform.jobService.image.registry=quay.io \
--set orchestrator.sonataflowPlatform.jobService.image.repository=ci/jobs-service \
--set orchestrator.sonataflowPlatform.jobService.image.tag=1.0 \
--set 'catalogIndex.extraImages[0].name=community' \
--set 'catalogIndex.extraImages[0].registry=ghcr.io' \
--set 'catalogIndex.extraImages[0].repository=ci/community-index' \
--set 'catalogIndex.extraImages[0].tag=1.0' \
--set 'catalogIndex.extraImages[1].registry=ghcr.io' \
--set 'catalogIndex.extraImages[1].repository=ci/other-index' \
--set 'catalogIndex.extraImages[1].tag=1.0'

echo "==> helm test pod image follows test.image.*"
test_image=$(render \
--set test.image.registry=registry.example.test \
--set test.image.repository=ci/curl \
--set test.image.tag=9.9.9 |
yq -N 'select(.metadata.annotations["helm.sh/hook"] == "test") | .spec.containers[].image')
assert_equals "test pod image" "registry.example.test/ci/curl:9.9.9" "${test_image}"

echo "==> dynamic plugins volume StorageClass"
# Default is an ephemeral claim with no storageClassName, so the cluster default applies.
spec_keys=$(render | plugins_root_volume | yq -N '.ephemeral.volumeClaimTemplate.spec // {} | keys | sort | join(",")')
assert_equals "ephemeral, nothing set: no storageClassName (cluster default)" "accessModes,resources" "${spec_keys}"

sc=$(render --set dynamicPlugins.volume.ephemeral.storageClassName=custom-sc |
plugins_root_volume | yq -N '.ephemeral.volumeClaimTemplate.spec.storageClassName')
assert_equals "ephemeral.storageClassName" "custom-sc" "${sc}"

sc=$(render --set global.defaultStorageClass=global-sc |
plugins_root_volume | yq -N '.ephemeral.volumeClaimTemplate.spec.storageClassName')
assert_equals "global.defaultStorageClass" "global-sc" "${sc}"

sc=$(render --set global.defaultStorageClass=global-sc \
--set dynamicPlugins.volume.ephemeral.storageClassName=custom-sc |
plugins_root_volume | yq -N '.ephemeral.volumeClaimTemplate.spec.storageClassName')
assert_equals "ephemeral.storageClassName overrides global.defaultStorageClass" "custom-sc" "${sc}"

sc=$(render \
--set workload.kind=StatefulSet \
--set dynamicPlugins.volume.type=statefulSetPVC \
--set dynamicPlugins.volume.statefulSetPVC.storageClassName=custom-sc |
yq -N 'select(.kind == "StatefulSet") | .spec.volumeClaimTemplates[]
| select(.metadata.name == "dynamic-plugins-root") | .spec.storageClassName')
assert_equals "statefulSetPVC.storageClassName" "custom-sc" "${sc}"

# emptyDir must not create any claim, even when a StorageClass is configured.
out=$(render --set dynamicPlugins.volume.type=emptyDir \
--set dynamicPlugins.volume.ephemeral.storageClassName=custom-sc)
vol=$(plugins_root_volume <<<"${out}" | yq -N -o=json -I=0 'keys | sort')
assert_equals "type=emptyDir: plugins volume is an emptyDir" '["emptyDir","name"]' "${vol}"
claims=$(yq ea -N '[select(.kind == "PersistentVolumeClaim"),
(.. | select(tag == "!!map" and has("volumeClaimTemplate")))]
| length' <<<"${out}")
assert_equals "type=emptyDir: no PVC or ephemeral claim rendered" "0" "${claims}"

echo
if ((failures > 0)); then
echo "${failures} of ${checks} rendered-values assertions failed" >&2
exit 1
fi
echo "All ${checks} rendered-values assertions passed"
Loading