feat(stalwart): spread each node group over nodes and give each one a PDB
Validate Helm Charts / Resource quantities (pull_request) Successful in 20s
Validate Helm Charts / Selector match (pull_request) Successful in 14s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 1m20s
Validate Helm Charts / Build stalwart (pull_request) Successful in 21s
Validate Helm Charts / Trivy config stalwart (pull_request) Successful in 42s
Install-test / Install-test stalwart (pull_request) Successful in 4m31s
Validate Helm Charts / Install-test (pull_request) Successful in 4m55s
Validate Helm Charts / Resource quantities (pull_request) Successful in 20s
Validate Helm Charts / Selector match (pull_request) Successful in 14s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 1m20s
Validate Helm Charts / Build stalwart (pull_request) Successful in 21s
Validate Helm Charts / Trivy config stalwart (pull_request) Successful in 42s
Install-test / Install-test stalwart (pull_request) Successful in 4m31s
Validate Helm Charts / Install-test (pull_request) Successful in 4m55s
A two-replica node group was redundancy on paper: nothing kept both pods off one node, and no PodDisruptionBudget kept a drain from taking both at once. Both objects are now rendered per node group, gated on that group's COMPUTED replica count being >= 2. The distribution is a promise, not an effort: maxSkew 1 on kubernetes.io/hostname with whenUnsatisfiable DoNotSchedule, selecting only this group's own pods, so an "mx" and a "full" pod may share a node. The selector comes from the chart (stalwart.groupLabels), never from the operator - a spread constraint whose selector matches no pod is trivially satisfied, distributes nothing and reports nothing. nodeAffinityPolicy: Ignore is set explicitly, and that is the load-bearing detail. Its API default is Honor, under which a narrowing nodeSelector shrinks the set of counted domains until both replicas fit into one: skew 0, both pods co-located, no Pending, no event, and a selector that is correct - so no check can see it. With Ignore the same narrowing gives skew 2 and the second pod is Pending. A render abort was the alternative and would also have forbidden a nodeSelector spanning five nodes, which is legal. A user entry colliding with the chart's own on (topologyKey, whenUnsatisfiable) aborts the render naming both values, because the API rejects the duplicate with a message about a list index and an apply-based path merges the two over patchMergeKey: topologyKey silently, dropping one selector. Minor rather than major, proved with a diff rather than argued: with the shipped defaults (full: 1, mx: 0) and with ci/stalwart/test-values.yaml, helm template renders byte-for-byte what 1.0.1+upv0.16.24 rendered - both diffs empty. New in CI, over every chart on every PR: ci/run-selector-match-test.sh holds every rendered PodDisruptionBudget selector and every topologySpreadConstraints labelSelector against the labels of the pod templates in the same render. Helm itself is the YAML parser (ci/yaml2json), because the runners have neither pyyaml nor yq and a hand-written parser could read nothing and report nothing. podAffinity/podAntiAffinity are out of scope; matchExpressions-only selectors are reported as not checked rather than counted as passing. Two anti-vacuum guards: a chart with an overlay under ci/selector-match/ that renders no selector fails, and a run that checks no selector at all fails. Fixes #96
This commit is contained in:
14 files changed
+1125
-8
No files matched your search
@@ -173,6 +173,36 @@ jobs:
|
||||
- name: "Render every chart with bare integer quantities"
|
||||
run: ci/run-quantity-render-test.sh
|
||||
|
||||
selector-match:
|
||||
name: "Selector match"
|
||||
runs-on: ubuntu-latest
|
||||
# The second job that ignores the changed-chart matrix and runs over *every*
|
||||
# chart (Gitea #96), and for the same reason as quantity-render above: the
|
||||
# mistake arrives by copy into a chart whose own diff nobody reads for it.
|
||||
#
|
||||
# What it asserts: every PodDisruptionBudget selector and every
|
||||
# topologySpreadConstraints labelSelector a chart renders really matches the
|
||||
# labels of a pod template in the SAME render. Both objects fail SILENTLY
|
||||
# when their selector matches nothing - the spread constraint becomes a
|
||||
# condition over zero pods and is trivially satisfied, the budget does its
|
||||
# arithmetic over zero pods and never blocks an eviction - so neither a
|
||||
# render error nor the install-test can catch it, and with
|
||||
# whenUnsatisfiable: DoNotSchedule the object reads like a guarantee while
|
||||
# distributing nothing.
|
||||
#
|
||||
# It needs no cluster and no Trivy: ~14 seconds for the whole repository,
|
||||
# depends on no other job, and finishes well inside build-chart. The YAML is
|
||||
# parsed by Helm itself through ci/yaml2json, because the runners have
|
||||
# neither pyyaml nor yq and a hand-written parser would be able to read
|
||||
# nothing and report nothing - see the script's header.
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
- name: "Install Helm"
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5
|
||||
- name: "Check every rendered selector against the rendered pod labels"
|
||||
run: ci/run-selector-match-test.sh
|
||||
|
||||
trivy-config:
|
||||
name: "Trivy config ${{ matrix.chart }}"
|
||||
needs: detect-changed-charts
|
||||
|
||||
Reference in new issue
Block a user