OCPBUGS-105882: Remove dead etcd members during a revision rollout - #1688
OCPBUGS-105882: Remove dead etcd members during a revision rollout#1688hasbro17 wants to merge 1 commit into
Conversation
After a control-plane node is replaced, a stale unhealthy etcd member keeps the etcd-endpoints configmap churning, which keeps rolling revisions and keeps IsRevisionStable() false. Since sync() bailed out early while revisions were unstable, the member was never removed and the churn continued, so recovery only happened once the revision loop briefly settled (observed as 3-7 hours). Key member removal on the absence of the backing Node instead of the Machine, and run it before the revision gate. A rollout never deletes the Node (it only reinstalls the static pod), so a member with no Node is genuinely dead, while a transiently-unhealthy member mid-rollout still has its Node and is left alone. This covers both a true orphan and a half-orphan whose Machine is a tombstone pending deletion (the MHC/CPMS case). Removing an unhealthy member is always quorum-safe, so no quorum check is needed; the scale-down and learner paths stay behind the revision gate. Drop the comment claiming the EtcdEndpointsController pauses during a rollout: it no longer does, and the stale claim misstated the dependency this change reasons about. Assisted-by: Claude Code (Opus 4.8) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@hasbro17: This pull request references Jira Issue OCPBUGS-105882, which is valid. 3 validation(s) were run on this bug
The bug has been updated to refer to the pull request using the external bug tracker. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: openshift/coderabbit/.coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review. WalkthroughThe cluster-member-removal controller now checks Machine API availability, removes eligible unhealthy members without Nodes, preserves gate errors, and keeps scale-down restrictions for unstable revisions or unsynchronized endpoints. Tests cover these paths and related member states. ChangesCluster member removal
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to The change narrowly enables removal of genuinely dead etcd members during revision rollouts while preserving existing gates for other removal paths; no actionable merge-blocking risk remains. Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (13 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Some tools did not complete. Review the errors below. 🔧 golangci-lint (2.12.2)Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
That PR description is making my head hurt |
|
/pipeline required |
|
Scheduling required tests: |
|
/hold Need to verify via the e2e scaling tests |
|
/test e2e-aws-ovn-etcd-scaling |
|
/retest |
|
@hasbro17: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
|
/hold It would be best to get e2e coverage from the assisted-installer side. The existing etcd vertical-scaling suite tests normal Machine deletion and replacement through CPMS or Machine API. Its pre-drain hook intentionally keeps the Node and Machine involved until the etcd member is removed. This bug is triggered by the Agent late-binding unbind flow, which deletes the old host’s Node and Machine out of band while leaving its etcd membership behind. /cc @shay23bra |
@hasbro17 |
What
Remove an etcd member whose backing Node is gone and that etcd reports
unhealthy, even while a static-pod revision rollout is in progress. This runs
ahead of the revision-stability gate; the quorum-sensitive scale-down and
learner-removal paths still wait for revisions to stabilize.
This supersedes #1684. That PR moved orphan removal ahead of the revision gate
but only for members with no Machine, so it missed the case where the Machine is
still present as a tombstone pending deletion. Keying on Node absence instead of
Machine absence covers both.
Why
After a control-plane node is replaced, the stale (unhealthy) etcd member keeps
the
etcd-endpointsconfigmap churning, which keeps rolling new revisions, whichkeeps
IsRevisionStable()false.ClusterMemberRemovalController.sync()bailedout early whenever revisions were unstable, so the member was never removed and
the churn sustained itself. The stale member was both the cause of the
instability and the thing the instability blocked us from removing.
The fix keys removal on Node absence rather than Machine absence. A revision
rollout never deletes the Node object (it only reinstalls the static pod), so:
remove regardless of revision state;
is left alone.
The scenario this addresses is the assisted-installer late-binding master
replacement flow: a manual bind/unbind of the host through the Kube API (the
Agent CR). The old Node and Machine are torn down out of band, leaving the
member as a true orphan (no Machine and no Node) or a half-orphan (Machine still
present as a tombstone pending deletion); both are now removed.
MachineHealthCheck / CPMS remediation is unaffected: there the etcd
PreDrainhook keeps the Machine and the Node alive until the member is first removed, so
the member still has a Node and continues to be handled by the gated scale-down
path.
Removing an orphan member only lowers etcd's quorum threshold and never removes
a healthy member, so it is always quorum-safe and needs no quorum check. The
Machine-API-functional precondition is retained (it is required to classify
whether a member's Machine still exists).
Testing
TestSynctable test covering the full gate ordering: dead members(true orphan and half-orphan) are removed during a rollout; scale-down and
learner removal stay gated; machine-API / bootstrap / endpoints-lag gates; and
that an error from the dead-member removal is surfaced (not swallowed) when the
revision is unstable.
TestClusterMemberRemovalControllerupdated for the generalized predicate,with new cases for the half-orphan and the healthy-but-unbacked error.
make buildandmake verifypass.Reference: assisted-installer late-binding unbind flow
assisted-serviceinternal/controller/controllers/agent_controller.go:unbindHost— hub-side DB state only.cleanUnboundSpokeNode→removeSpokeResources(spoke-side):machine.openshift.io/machineannotation on the node;machine.openshift.io/delete-machine: trueandmachine.openshift.io/exclude-node-draining: true;Deleteon the Machine (and the BMH).Assisted does not touch etcd membership/configmaps; it expects the etcd operator
to remove the member once the Node/Machine are gone. Our predicate (Node gone +
Machine absent-or-pending-deletion + member unhealthy) matches both end-states of
this flow.
Summary by CodeRabbit
Bug Fixes
Tests