@@ -27,6 +27,7 @@ import (
2727 "time"
2828
2929 corev1 "k8s.io/api/core/v1"
30+ "k8s.io/apimachinery/pkg/api/equality"
3031 "k8s.io/apimachinery/pkg/api/meta"
3132 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3233 "k8s.io/apimachinery/pkg/runtime"
@@ -107,6 +108,7 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
107108 // check condition reason
108109 status := meta .FindStatusCondition (hv .Status .Conditions , kvmv1 .ConditionTypeOnboarding )
109110 if status == nil {
111+ base := hv .DeepCopy ()
110112 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
111113 Type : kvmv1 .ConditionTypeReady ,
112114 Status : metav1 .ConditionFalse ,
@@ -120,7 +122,7 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
120122 Reason : kvmv1 .ConditionReasonInitial ,
121123 Message : "Initial onboarding" ,
122124 })
123- return ctrl.Result {}, r .Status (). Update ( ctx , hv )
125+ return ctrl.Result {}, r .patchStatus ( ctx , hv , base )
124126 }
125127
126128 switch status .Reason {
@@ -145,7 +147,7 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
145147 return nil
146148 }
147149
148- changed := false
150+ base := hv . DeepCopy ()
149151 ready := meta .FindStatusCondition (hv .Status .Conditions , kvmv1 .ConditionTypeReady )
150152 if ready != nil {
151153 // Only undo ones own readiness status reporting
@@ -156,23 +158,21 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
156158 Reason : kvmv1 .ConditionReasonOnboarding ,
157159 Message : "Onboarding aborted" ,
158160 })
159- changed = true
160161 }
161162 }
162163
163- if meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
164+ meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
164165 Type : kvmv1 .ConditionTypeOnboarding ,
165166 Status : metav1 .ConditionFalse ,
166167 Reason : kvmv1 .ConditionReasonAborted ,
167168 Message : "Aborted due to LifecycleEnabled being false" ,
168- }) {
169- changed = true
170- }
169+ })
171170
172- if ! changed {
171+ if equality . Semantic . DeepEqual ( hv , base ) {
173172 // Already aborted
174173 return nil
175174 }
175+
176176 if err := r .deleteTestServers (ctx , computeHost ); err != nil {
177177 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
178178 Type : kvmv1 .ConditionTypeOnboarding ,
@@ -181,9 +181,14 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
181181 Message : err .Error (),
182182 })
183183
184- return errors .Join (err , r .Status ().Update (ctx , hv ))
184+ if equality .Semantic .DeepEqual (hv , base ) {
185+ return err
186+ }
187+
188+ return errors .Join (err , r .patchStatus (ctx , hv , base ))
185189 }
186- return r .Status ().Update (ctx , hv )
190+
191+ return r .patchStatus (ctx , hv , base )
187192}
188193
189194func (r * OnboardingController ) initialOnboarding (ctx context.Context , hv * kvmv1.Hypervisor , host string ) error {
@@ -233,13 +238,14 @@ func (r *OnboardingController) initialOnboarding(ctx context.Context, hv *kvmv1.
233238 return result .Err
234239 }
235240
241+ base := hv .DeepCopy ()
236242 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
237243 Type : kvmv1 .ConditionTypeOnboarding ,
238244 Status : metav1 .ConditionTrue ,
239245 Reason : kvmv1 .ConditionReasonTesting ,
240246 Message : "Running onboarding tests" ,
241247 })
242- return r .Status (). Update ( ctx , hv )
248+ return r .patchStatus ( ctx , hv , base )
243249}
244250
245251func (r * OnboardingController ) smokeTest (ctx context.Context , hv * kvmv1.Hypervisor , host string ) (ctrl.Result , error ) {
@@ -261,14 +267,15 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
261267 return ctrl.Result {RequeueAfter : defaultWaitTime }, nil
262268 }
263269
270+ base := hv .DeepCopy ()
264271 // Set condition back to testing
265272 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
266273 Type : kvmv1 .ConditionTypeOnboarding ,
267274 Status : metav1 .ConditionTrue ,
268275 Reason : kvmv1 .ConditionReasonTesting ,
269276 Message : "Server ended up in error state: " + server .Fault .Message ,
270277 })
271- if err = r .Status (). Update ( ctx , hv ); err != nil {
278+ if err = r .patchStatus ( ctx , hv , base ); err != nil {
272279 return ctrl.Result {}, err
273280 }
274281
@@ -281,13 +288,14 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
281288 case "ACTIVE" :
282289 consoleOutput , err := servers .ShowConsoleOutput (ctx , r .testComputeClient , server .ID , servers.ShowConsoleOutputOpts {Length : 11 }).Extract ()
283290 if err != nil {
291+ base := hv .DeepCopy ()
284292 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
285293 Type : kvmv1 .ConditionTypeOnboarding ,
286294 Status : metav1 .ConditionTrue ,
287295 Reason : kvmv1 .ConditionReasonTesting ,
288296 Message : fmt .Sprintf ("could not get console output %v" , err ),
289297 })
290- if err := r .Status (). Update ( ctx , hv ); err != nil {
298+ if err := r .patchStatus ( ctx , hv , base ); err != nil {
291299 return ctrl.Result {}, err
292300 }
293301 return ctrl.Result {RequeueAfter : defaultWaitTime }, nil
@@ -298,13 +306,14 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
298306 }
299307
300308 if err = servers .Delete (ctx , r .testComputeClient , server .ID ).ExtractErr (); err != nil {
309+ base := hv .DeepCopy ()
301310 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
302311 Type : kvmv1 .ConditionTypeOnboarding ,
303312 Status : metav1 .ConditionTrue ,
304313 Reason : kvmv1 .ConditionReasonTesting ,
305314 Message : fmt .Sprintf ("failed to terminate instance %v" , err ),
306315 })
307- if err := r .Status (). Update ( ctx , hv ); err != nil {
316+ if err := r .patchStatus ( ctx , hv , base ); err != nil {
308317 return ctrl.Result {}, err
309318 }
310319 return ctrl.Result {RequeueAfter : defaultWaitTime }, nil
@@ -321,13 +330,14 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
321330
322331 err := r .deleteTestServers (ctx , host )
323332 if err != nil {
333+ base := hv .DeepCopy ()
324334 if meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
325335 Type : kvmv1 .ConditionTypeOnboarding ,
326336 Status : metav1 .ConditionTrue , // No cleanup, so we are still "onboarding"
327337 Reason : kvmv1 .ConditionReasonAborted ,
328338 Message : err .Error (),
329339 }) {
330- return ctrl.Result {}, errors .Join (err , r .Status (). Update ( ctx , hv ))
340+ return ctrl.Result {}, errors .Join (err , r .patchStatus ( ctx , hv , base ))
331341 }
332342
333343 return ctrl.Result {}, err
@@ -350,6 +360,7 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
350360 return ctrl.Result {}, err
351361 }
352362
363+ base := hv .DeepCopy ()
353364 // Set hypervisor ready condition
354365 meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
355366 Type : kvmv1 .ConditionTypeReady ,
@@ -365,7 +376,7 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
365376 Reason : kvmv1 .ConditionReasonSucceeded ,
366377 Message : "Onboarding completed" ,
367378 })
368- return ctrl.Result {}, r .Status (). Update ( ctx , hv )
379+ return ctrl.Result {}, r .patchStatus ( ctx , hv , base )
369380}
370381
371382func (r * OnboardingController ) deleteTestServers (ctx context.Context , host string ) error {
@@ -438,9 +449,10 @@ func (r *OnboardingController) ensureNovaProperties(ctx context.Context, hv *kvm
438449 return fmt .Errorf ("could not find exact match for %v" , shortHypervisorAddress )
439450 }
440451
452+ base := hv .DeepCopy ()
441453 hv .Status .HypervisorID = myHypervisor .ID
442454 hv .Status .ServiceID = myHypervisor .Service .ID
443- return r .Status (). Update ( ctx , hv )
455+ return r .patchStatus ( ctx , hv , base )
444456}
445457
446458func (r * OnboardingController ) createOrGetTestServer (ctx context.Context , zone , computeHost string , nodeUid types.UID ) (* servers.Server , error ) {
@@ -592,6 +604,10 @@ func (r *OnboardingController) findTestFlavor(ctx context.Context) (string, erro
592604 return "" , errors .New ("couldn't find flavor" )
593605}
594606
607+ func (r * OnboardingController ) patchStatus (ctx context.Context , hv , base * kvmv1.Hypervisor ) error {
608+ return r .Status ().Patch (ctx , hv , k8sclient .MergeFromWithOptions (base , k8sclient.MergeFromWithOptimisticLock {}), k8sclient .FieldOwner (OnboardingControllerName ))
609+ }
610+
595611// SetupWithManager sets up the controller with the Manager.
596612func (r * OnboardingController ) SetupWithManager (mgr ctrl.Manager ) error {
597613 ctx := context .Background ()
0 commit comments