test(kubernetes): chart-wide invariant for admin-kubeconfig guards
The per-template unittests in packages/apps/kubernetes/tests/ assert that cluster-autoscaler, kccm, and the csi controller each mount the admin-kubeconfig Secret optional and carry the wait-for-kubeconfig init. That locks in today's three Deployments by name - a fourth Deployment that mounts the same Secret but forgets the guard would slip past them. Add a bats-unit test that renders the entire chart, enumerates every Deployment whose spec mounts a Secret ending in -admin-kubeconfig, and asserts optional:true plus wait-for-kubeconfig init on all of them. Verified by temporarily removing optional:true from csi/deploy.yaml: the test correctly flagged invariant-kcsi-controller as an offender. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
parent
7b146cbe56
commit
bc5473d4fc
1 changed files with 72 additions and 0 deletions
72
hack/admin-kubeconfig-invariant.bats
Normal file
72
hack/admin-kubeconfig-invariant.bats
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env bats
|
||||
# -----------------------------------------------------------------------------
|
||||
# Chart-wide invariant for packages/apps/kubernetes:
|
||||
#
|
||||
# Every Deployment in this chart that mounts <release>-admin-kubeconfig as a
|
||||
# Secret volume MUST:
|
||||
# - declare that volume optional: true (so kubelet does not FailedMount
|
||||
# while Kamaji is still provisioning the Secret), AND
|
||||
# - include the wait-for-kubeconfig init container (so the pod becomes
|
||||
# Ready only after Kamaji publishes the Secret).
|
||||
#
|
||||
# The per-template unittests in packages/apps/kubernetes/tests/ lock in
|
||||
# today's three Deployments (cluster-autoscaler, kccm, csi controller) by
|
||||
# name. This invariant is stricter: any future Deployment added to this
|
||||
# chart that mounts the same Secret but forgets the guard will fail here.
|
||||
#
|
||||
# Requires: helm, yq (mikefarah v4+), jq. All three are available on the
|
||||
# project's CI runners and on the maintainer workstation.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@test "every Deployment mounting admin-kubeconfig has optional:true and wait-for-kubeconfig init" {
|
||||
values_file="packages/apps/kubernetes/tests/values-ci.yaml"
|
||||
[ -f "$values_file" ]
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
helm template invariant packages/apps/kubernetes \
|
||||
--namespace tenant-root \
|
||||
--values "$values_file" \
|
||||
2>/dev/null > "$tmp/rendered.yaml"
|
||||
|
||||
# yq streams one JSON object per input document. jq -s slurps the stream
|
||||
# into an array so we can treat all Deployments as a single collection.
|
||||
yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \
|
||||
| jq -s --raw-output '
|
||||
map(select(.kind == "Deployment")) |
|
||||
map({
|
||||
name: .metadata.name,
|
||||
volumes: (.spec.template.spec.volumes // []),
|
||||
initNames: ((.spec.template.spec.initContainers // []) | map(.name)),
|
||||
}) |
|
||||
map(
|
||||
.name as $n |
|
||||
.initNames as $ins |
|
||||
(.volumes[] | select(.secret.secretName | test("-admin-kubeconfig$")?))
|
||||
| {
|
||||
name: $n,
|
||||
optional: (.secret.optional == true),
|
||||
hasInit: ($ins | index("wait-for-kubeconfig") != null),
|
||||
}
|
||||
)
|
||||
' > "$tmp/summary.json"
|
||||
|
||||
# At least one Deployment must match; if a refactor removes every
|
||||
# admin-kubeconfig volume from this chart, the test must be updated
|
||||
# deliberately rather than silently passing.
|
||||
matched=$(jq 'length' "$tmp/summary.json")
|
||||
[ "$matched" -ge 1 ]
|
||||
|
||||
offenders=$(jq --raw-output '.[] | select(.optional != true or .hasInit != true) | .name' "$tmp/summary.json")
|
||||
|
||||
if [ -n "$offenders" ]; then
|
||||
echo "Deployments mounting *-admin-kubeconfig without optional:true + wait-for-kubeconfig init:" >&2
|
||||
echo "$offenders" >&2
|
||||
echo "Full summary:" >&2
|
||||
cat "$tmp/summary.json" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Invariant holds for $matched Deployment(s)"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue