Skip to content

Ensure StatefulSetSelector matches deployed labels. - #2220

Merged
Zerpet merged 2 commits into
mainfrom
fix-disallow-selector-edits
Aug 11, 2026
Merged

Ensure StatefulSetSelector matches deployed labels.#2220
Zerpet merged 2 commits into
mainfrom
fix-disallow-selector-edits

Conversation

@MirahImage

Copy link
Copy Markdown
Member

This closes #2218

@MirahImage
MirahImage force-pushed the fix-disallow-selector-edits branch from 17d88ba to 2e10a6b Compare August 7, 2026 12:33
@MirahImage
MirahImage requested a review from Zerpet August 7, 2026 12:41
@Zerpet Zerpet added this to the v2.22.4 milestone Aug 11, 2026
@Zerpet

Zerpet commented Aug 11, 2026

Copy link
Copy Markdown
Member

🤖 AI code review — this was generated by Claude Code (an AI coding agent) and is being posted by a human reviewer who is checking these findings before acting on them. Treat as input to review, not as an authoritative verdict.

Ran a high-effort automated review of this PR's new StatefulSet-selector validation guard. 5 findings, all independently verified:

Correctness

  1. internal/webhook/v1beta1/rabbitmqcluster_webhook.go:78ValidateUpdate ignores the old object and rejects any update to a CR whose already-persisted StatefulSet selector override doesn't match its pod template labels, with no grandfathering. A CR created before this webhook that already has a mismatched selector override (previously accepted) would have every future update rejected — even unrelated ones like bumping replicas or changing the image tag — until the mismatch itself is fixed in the same request.

  2. internal/metadata/label.go:58ValidateStatefulSetSelector only runs when spec.override.statefulSet.spec.selector is explicitly set. A pod-template-label-only override (e.g. overwriting app.kubernetes.io/name via spec.override.statefulSet.spec.template.metadata.labels) breaks the default selector match but is never validated by either the webhook or StatefulSetBuilder.Build(), since both skip validation when override.Spec.Selector is nil. The StatefulSet update is then rejected by the API server, leaving the cluster stuck in ReconcileSuccess=False — the exact failure mode this guard is meant to prevent.

  3. internal/metadata/label.go:62 — A non-nil but empty selector override (spec.override.statefulSet.spec.selector: {}) converts to labels.Everything() via metav1.LabelSelectorAsSelector, so it always "matches" and passes validation, even though Kubernetes rejects empty StatefulSet selectors outright. Same permanent-failure outcome as Add clustering #2.

Cleanup

  1. internal/webhook/v1beta1/rabbitmqcluster_webhook.go:176 vs internal/resource/statefulset.go:96-99 — the block extracting templateLabelOverrides from override.Spec.Template is duplicated verbatim between the webhook and the builder. A future change to how template label overrides are represented is likely to update only one copy, silently reintroducing a webhook/builder mismatch.

  2. internal/controller/rabbitmqcluster_controller.go:207 — the new setReconcileSuccess call for builder.Build() errors uses the generic reason "Error", unlike every other failure path in this function (FailedReconcilePVC, InvalidConfiguration, FailedVersionAnnotation, FailedCLICommand). Dashboards/alerts filtering on status.conditions[].reason can't distinguish a selector-override misconfiguration from any other builder failure.

Findings 1 and 2 share the same root cause: validation only considers the new object's selector-vs-template state in isolation, and only when a selector override is explicitly present.

Widens ValidateStatefulSetSelector to run whenever a StatefulSet
override is present, not just when spec.override.statefulSet.spec.selector
is explicitly set, so a pod-template-label-only override that breaks the
default selector match is caught before the API server rejects the
StatefulSet and reconciliation gets stuck permanently failing. Also
rejects an explicit empty selector, which would otherwise match every
pod in the namespace and pass validation trivially.

Gives selector-override failures a distinct reconcile-failure reason
(InvalidStatefulSetSelectorOverride) instead of the generic "Error",
following the existing ErrInvalidEnvConfig/InvalidConfiguration pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Zerpet
Zerpet merged commit 346a71c into main Aug 11, 2026
41 checks passed
@Zerpet
Zerpet deleted the fix-disallow-selector-edits branch August 11, 2026 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StatefulSet selector override causes permanent reconciliation failure (Forbidden / selector mismatch)

2 participants