Skip to content

Remove PatchHypervisorStatusWithRetry after all controllers migrated to SSA#346

Open
fwiesel wants to merge 12 commits into
mainfrom
ssa-cleanup
Open

Remove PatchHypervisorStatusWithRetry after all controllers migrated to SSA#346
fwiesel wants to merge 12 commits into
mainfrom
ssa-cleanup

Conversation

@fwiesel

@fwiesel fwiesel commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

With all controllers migrated to Status().Apply(), the last caller of PatchHypervisorStatusWithRetry is gone. Remove the helper and the StatusPatchBackoff it used.

This PR must merge last, after all controller-migration PRs are merged:

The GitHub PR view will show this branch as containing all those commits until they merge into main, at which point only the internal/utils/status_patch.go deletion remains.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@fwiesel, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e71febe4-4950-420f-bc43-730d27402d50

📥 Commits

Reviewing files that changed from the base of the PR and between 71421ef and 2a49eb5.

📒 Files selected for processing (13)
  • internal/controller/aggregates_controller.go
  • internal/controller/eviction_controller.go
  • internal/controller/hypervisor_controller.go
  • internal/controller/hypervisor_maintenance_controller.go
  • internal/controller/hypervisor_maintenance_controller_test.go
  • internal/controller/hypervisor_taint_controller.go
  • internal/controller/offboarding_controller.go
  • internal/controller/onboarding_controller.go
  • internal/controller/ready/controller.go
  • internal/controller/traits_controller.go
  • internal/utils/conditions.go
  • internal/utils/conditions_test.go
  • internal/utils/status_patch.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ssa-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fwiesel

fwiesel commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

fwiesel added 12 commits July 13, 2026 21:54
Introduce ConditionFromStatus and SetApplyConfigurationStatusCondition
as the foundation for migrating all controllers to server-side apply
of status subresources.

ConditionFromStatus converts a single metav1.Condition (as stored in
a status subresource) to a ConditionApplyConfiguration suitable for
SSA. ObservedGeneration is preserved so gating logic (e.g. the taint
controller's skip-check) keeps working.

SetApplyConfigurationStatusCondition mirrors the semantics of
meta.SetStatusCondition on the apply-configuration slice: append or
update by Type, refresh LastTransitionTime only when Status changes,
and guard against nil/empty Type to prevent panics.

Together they enable per-condition seeding so each controller claims
field ownership only over the conditions it actually manages, without
disturbing conditions owned by other field managers on Apply.
Replace MergeFromWithOptimisticLock + retry with Status().Apply() for
all eviction status updates. The evictionStatusCfg helper seeds every
apply with the full set of owned fields so SSA never prunes values
between reconcile cycles. As the sole owner of every condition on the
Eviction CR, the reconciler seeds all three condition types on each
apply.

The apply configuration constructor for the cluster-scoped Eviction
resource takes only a name (no namespace).
Replace PatchHypervisorStatusWithRetry with Status().Apply() for the
InternalIP scalar and ConditionTypeTerminating condition. Re-fetch the
hypervisor after the status apply so the subsequent spec patch sees a
fresh resourceVersion.

Seed only ConditionTypeTerminating (the sole condition owned by this
controller) so SSA does not claim ownership over conditions written by
other controllers.

WithInternalIP is only called when the node reports a NodeInternalIP.
Combined with ForceOwnership, applying an empty string would clobber a
previously stored valid IP whenever the node briefly reports no IP
(e.g. during kubelet restart or bootstrap).

The AgentPodsEvicted=False branch previously returned early with a
requeue before running syncLabelsAndAnnotations, so node label changes
were not propagated to the Hypervisor while terminating. Move the
requeue after the spec patch so labels stay in sync.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for the
ConditionTypeTainted condition. Only ConditionTypeTainted is seeded
into the apply so SSA does not claim ownership over conditions written
by other controllers.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for
ConditionTypeHypervisorDisabled, ConditionTypeEvicting, and the
Evicted scalar. ConditionTypeEvicting is removed by omitting it from
the apply — SSA prunes map-list entries no longer claimed by the sole
owner.

The status config is built once in Reconcile and passed to
reconcileComputeService and reconcileEviction which mutate it
directly. This eliminates intermediate condition return values and
makes the single-apply-per-reconcile explicit. The early-return guard
for already-enabled/disabled state is inlined into each branch.

Seed only the conditions owned by this controller so SSA does not
claim ownership over conditions written by others. For the
delete-by-omission case, owned conditions are seeded selectively so
the target condition is simply absent from the payload.

Also clear the forced_down flag when enabling a compute service so an
earlier HA event that set forced_down=true does not leave the service
reachable but treated as down.

SetupWithManager now delegates to registerWithManager instead of
inlining the same ctrl.NewControllerManagedBy call, which had left
registerWithManager unreachable.
Replace Create + SetControllerReference with Apply for the Eviction CR.
The owner reference and labels are set in the apply configuration
metadata, and SSA handles the upsert. A Get is still performed after
the apply to read the current eviction status conditions.

The apply configuration constructor for the cluster-scoped Eviction
resource takes only a name (no namespace).
Replace PatchHypervisorStatusWithRetry with Status().Apply(). The
Nova ID lookup is inlined into Reconcile and combined with the initial
condition in a single apply, avoiding two applies from the same field
manager in one reconcile cycle which would cause SSA to prune the IDs.
HypervisorID and ServiceID are included in every subsequent apply to
retain ownership.

The status config is built once at the top of Reconcile and threaded
through to all sub-functions (abortOnboarding, initialOnboarding,
smokeTest, completeOnboarding) which mutate it directly. An apply
closure is also passed so each function calls apply() when it has
determined the desired condition, rather than building and applying
the config itself. The flow becomes fully declarative: compute desired
state, then apply once.

Seed only the condition owned by this controller (ConditionTypeOnboarding)
so SSA does not claim ownership over conditions written by other
controllers.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for the
ConditionTypeOffboarded condition. Seed only that condition so SSA
does not claim ownership over conditions written by other controllers.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for
ConditionTypeAggregatesUpdated and the Aggregates slice. The error
path includes the current Aggregates in the apply to prevent SSA from
pruning previously-set values on a transient OpenStack error.

Clearing aggregates to an empty slice uses a targeted merge patch to
work around the omitempty limitation in the generated apply
configuration type.

Seed only ConditionTypeAggregatesUpdated so SSA does not claim
ownership over conditions written by other controllers.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for
ConditionTypeTraitsUpdated and the Traits slice. Error paths pass the
current hv.Status.Traits to retain ownership and avoid SSA releasing
it on transient placement API failures.

Seed only ConditionTypeTraitsUpdated so SSA does not claim ownership
over conditions written by other controllers.
Replace PatchHypervisorStatusWithRetry with Status().Apply() for
ConditionTypeReady. Seed only that condition so SSA does not claim
ownership over conditions written by other controllers.
With all controllers migrated to Status().Apply(), the last caller of
PatchHypervisorStatusWithRetry is gone. Remove the helper and the
StatusPatchBackoff it used.
@github-actions

Copy link
Copy Markdown

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller 69.35% (+0.44%) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/ready 73.21% (+1.28%) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/utils 90.38% (+17.05%) 🎉

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/aggregates_controller.go 76.34% (-8.27%) 93 (+28) 71 (+16) 22 (+12) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/eviction_controller.go 61.27% (+0.06%) 173 (+8) 106 (+5) 67 (+3) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_controller.go 78.99% (-1.01%) 119 (-1) 94 (-2) 25 (+1) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_maintenance_controller.go 80.00% (+1.59%) 80 (-8) 64 (-5) 16 (-3) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_taint_controller.go 90.48% (-2.38%) 21 (+7) 19 (+6) 2 (+1) 👎
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/offboarding_controller.go 73.97% (+1.12%) 73 (+3) 54 (+3) 19 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/onboarding_controller.go 56.39% (+1.33%) 227 (-20) 128 (-8) 99 (-12) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/ready/controller.go 73.21% (+1.28%) 56 (-1) 41 15 (-1) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/traits_controller.go 75.41% (+1.97%) 61 (-3) 46 (-1) 15 (-2) 👍
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/utils/conditions.go 95.45% (+95.45%) 44 (+44) 42 (+42) 2 (+2) 🌟
github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/utils/status_patch.go 0.00% (-85.71%) 0 (-7) 0 (-6) 0 (-1) 💀 💀 💀 💀 💀

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/hypervisor_maintenance_controller_test.go
  • github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/utils/conditions_test.go

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.

1 participant