Skip to content

Commit b5addc7

Browse files
committed
Add HypervisorReadyController to centralize Ready condition logic
Introduces a new ReadyController that computes the Ready condition based on other conditions (Onboarding, Offboarded, Terminating, Evicting) and the maintenance spec field. Changes: - Add internal/controller/ready package with controller and tests - Remove Ready condition setting from OnboardingController - Remove Ready condition setting from MaintenanceController - Remove Ready condition setting from OffboardingController - Remove Ready condition setting from HypervisorController - Update OffboardingController to use Offboarded condition for state tracking The ReadyController uses a predicate that triggers on: - Status changes - Maintenance field changes (since it affects Ready condition) Ready condition priority: 1. Offboarded=True -> Ready=False 2. Terminating=True -> Ready=False 3. Onboarding in progress (Status=True) -> Ready=False 4. Maintenance mode (with eviction state) -> Ready=False 5. Onboarding not started/aborted/not succeeded -> Ready=False 6. All checks pass -> Ready=True
1 parent 499dcef commit b5addc7

File tree

7 files changed

+576
-72
lines changed

7 files changed

+576
-72
lines changed

cmd/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949

5050
kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
5151
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller"
52+
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller/ready"
5253
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global"
5354
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/logger"
5455

@@ -316,6 +317,14 @@ func main() {
316317
os.Exit(1)
317318
}
318319

320+
if err = (&ready.Controller{
321+
Client: mgr.GetClient(),
322+
Scheme: mgr.GetScheme(),
323+
}).SetupWithManager(mgr); err != nil {
324+
setupLog.Error(err, "unable to create controller", "controller", ready.ControllerName)
325+
os.Exit(1)
326+
}
327+
319328
// +kubebuilder:scaffold:builder
320329

321330
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {

internal/controller/hypervisor_controller.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,6 @@ func (hv *HypervisorController) Reconcile(ctx context.Context, req ctrl.Request)
112112
nodeTerminationCondition := FindNodeStatusCondition(node.Status.Conditions, "Terminating")
113113
if nodeTerminationCondition != nil && nodeTerminationCondition.Status == corev1.ConditionTrue {
114114
// Node might be terminating, propagate condition to hypervisor
115-
116-
if readyCondition := meta.FindStatusCondition(hypervisor.Status.Conditions, kvmv1.ConditionTypeReady); readyCondition == nil || readyCondition.Status == metav1.ConditionTrue {
117-
// Only set Terminating condition if Ready is still True, otherwise we might overwrite other controllers that already set Ready to False
118-
// In particular if the hypervisor is evicting
119-
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
120-
Type: kvmv1.ConditionTypeReady,
121-
Status: metav1.ConditionFalse,
122-
Reason: nodeTerminationCondition.Reason,
123-
Message: nodeTerminationCondition.Message,
124-
})
125-
}
126-
127115
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
128116
Type: kvmv1.ConditionTypeTerminating,
129117
Status: metav1.ConditionStatus(nodeTerminationCondition.Status),

internal/controller/hypervisor_maintenance_controller.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,6 @@ func (hec *HypervisorMaintenanceController) reconcileComputeService(ctx context.
109109
return nil
110110
}
111111

112-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
113-
Type: kvmv1.ConditionTypeReady,
114-
Status: metav1.ConditionTrue,
115-
Reason: kvmv1.ConditionReasonReadyReady,
116-
Message: "Hypervisor is ready",
117-
})
118-
119112
// We need to enable the host as per spec
120113
enableService := services.UpdateOpts{Status: services.ServiceEnabled}
121114
log.Info("Enabling hypervisor", "id", serviceId)
@@ -138,13 +131,6 @@ func (hec *HypervisorMaintenanceController) reconcileComputeService(ctx context.
138131
return nil
139132
}
140133

141-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
142-
Type: kvmv1.ConditionTypeReady,
143-
Status: metav1.ConditionFalse,
144-
Reason: kvmv1.ConditionReasonReadyMaintenance,
145-
Message: "Hypervisor is disabled",
146-
})
147-
148134
// We need to disable the host as per spec
149135
enableService := services.UpdateOpts{
150136
Status: services.ServiceDisabled,
@@ -194,22 +180,10 @@ func (hec *HypervisorMaintenanceController) reconcileEviction(ctx context.Contex
194180
message = "Evicted"
195181
reason = kvmv1.ConditionReasonSucceeded
196182
hv.Status.Evicted = true
197-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
198-
Type: kvmv1.ConditionTypeReady,
199-
Status: metav1.ConditionFalse,
200-
Reason: kvmv1.ConditionReasonReadyEvicted,
201-
Message: "Hypervisor is disabled and evicted",
202-
})
203183
} else {
204184
message = "Evicting"
205185
reason = kvmv1.ConditionReasonRunning
206186
hv.Status.Evicted = false
207-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
208-
Type: kvmv1.ConditionTypeReady,
209-
Status: metav1.ConditionFalse,
210-
Reason: kvmv1.ConditionReasonReadyEvicting,
211-
Message: "Hypervisor is disabled and evicting",
212-
})
213187
}
214188

215189
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{

internal/controller/offboarding_controller.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,14 @@ func (r *HypervisorOffboardingReconciler) Reconcile(ctx context.Context, req ctr
6868
return ctrl.Result{}, nil
6969
}
7070

71-
if meta.IsStatusConditionTrue(hv.Status.Conditions, kvmv1.ConditionTypeReady) {
71+
// Check if offboarding has already started or completed
72+
offboardedCondition := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeOffboarded)
73+
if offboardedCondition == nil {
74+
// Start offboarding
7275
return r.setOffboardingCondition(ctx, hv, "Hypervisor is being offboarded, removing host from nova")
7376
}
7477

75-
if meta.IsStatusConditionTrue(hv.Status.Conditions, kvmv1.ConditionTypeOffboarded) {
78+
if offboardedCondition.Status == metav1.ConditionTrue {
7679
return ctrl.Result{}, nil
7780
}
7881

@@ -145,7 +148,7 @@ func (r *HypervisorOffboardingReconciler) Reconcile(ctx context.Context, req ctr
145148
func (r *HypervisorOffboardingReconciler) setOffboardingCondition(ctx context.Context, hv *kvmv1.Hypervisor, message string) (ctrl.Result, error) {
146149
base := hv.DeepCopy()
147150
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
148-
Type: kvmv1.ConditionTypeReady,
151+
Type: kvmv1.ConditionTypeOffboarded,
149152
Status: metav1.ConditionFalse,
150153
Reason: "Offboarding",
151154
Message: message,
@@ -165,12 +168,6 @@ func (r *HypervisorOffboardingReconciler) markOffboarded(ctx context.Context, hv
165168
Reason: "Offboarded",
166169
Message: "Offboarding successful",
167170
})
168-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
169-
Type: kvmv1.ConditionTypeReady,
170-
Status: metav1.ConditionFalse,
171-
Reason: "Offboarded",
172-
Message: "Offboarding successful",
173-
})
174171
if err := r.Status().Patch(ctx, hv, k8sclient.MergeFromWithOptions(base,
175172
k8sclient.MergeFromWithOptimisticLock{}), k8sclient.FieldOwner(OffboardingControllerName)); err != nil {
176173
return fmt.Errorf("cannot update hypervisor status due to %w", err)

internal/controller/onboarding_controller.go

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,6 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
110110
status := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeOnboarding)
111111
if status == nil {
112112
base := hv.DeepCopy()
113-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
114-
Type: kvmv1.ConditionTypeReady,
115-
Status: metav1.ConditionFalse,
116-
Reason: kvmv1.ConditionReasonOnboarding,
117-
Message: "Onboarding in progress",
118-
})
119113

120114
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
121115
Type: kvmv1.ConditionTypeOnboarding,
@@ -151,18 +145,6 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
151145
}
152146

153147
base := hv.DeepCopy()
154-
ready := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeReady)
155-
if ready != nil {
156-
// Only undo ones own readiness status reporting
157-
if ready.Reason == kvmv1.ConditionReasonOnboarding {
158-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
159-
Type: kvmv1.ConditionTypeReady,
160-
Status: metav1.ConditionFalse,
161-
Reason: kvmv1.ConditionReasonOnboarding,
162-
Message: "Onboarding aborted",
163-
})
164-
}
165-
}
166148

167149
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
168150
Type: kvmv1.ConditionTypeOnboarding,
@@ -354,13 +336,6 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
354336
Message: "Onboarding completed",
355337
})
356338

357-
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
358-
Type: kvmv1.ConditionTypeReady,
359-
Status: metav1.ConditionTrue,
360-
Reason: kvmv1.ConditionReasonReadyReady,
361-
Message: "Hypervisor is ready",
362-
})
363-
364339
return ctrl.Result{}, r.patchStatus(ctx, hv, base)
365340
}
366341

0 commit comments

Comments
 (0)