@@ -100,14 +100,15 @@ func (r *EvictionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
100100
101101 statusCondition := meta .FindStatusCondition (eviction .Status .Conditions , kvmv1 .ConditionTypeEvicting )
102102 if statusCondition == nil {
103- // No status condition, so we need to add it
104- if r .addCondition (ctx , eviction , metav1 .ConditionTrue , "Running" , kvmv1 .ConditionReasonRunning ) {
105- log .Info ("running" )
106- return ctrl.Result {}, nil
107- }
108- // We just checked if the condition is there, so this should never
109- // be reached, but let's cover our bass
110- return ctrl.Result {RequeueAfter : 1 * time .Second }, nil
103+ base := eviction .DeepCopy ()
104+ meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
105+ Type : kvmv1 .ConditionTypeEvicting ,
106+ Status : metav1 .ConditionTrue ,
107+ Message : "Running" ,
108+ Reason : kvmv1 .ConditionReasonRunning ,
109+ })
110+
111+ return ctrl.Result {}, r .updateStatus (ctx , eviction , base )
111112 }
112113
113114 switch statusCondition .Status {
@@ -139,6 +140,7 @@ func (r *EvictionReconciler) handleRunning(ctx context.Context, eviction *kvmv1.
139140 return r .evictNext (ctx , eviction )
140141 }
141142
143+ base := eviction .DeepCopy ()
142144 meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
143145 Type : kvmv1 .ConditionTypeEvicting ,
144146 Status : metav1 .ConditionFalse ,
@@ -148,10 +150,15 @@ func (r *EvictionReconciler) handleRunning(ctx context.Context, eviction *kvmv1.
148150
149151 eviction .Status .OutstandingRamMb = 0
150152 logger .FromContext (ctx ).Info ("succeeded" )
151- return ctrl.Result {}, r .Status ().Update (ctx , eviction )
153+ return ctrl.Result {}, r .updateStatus (ctx , eviction , base )
154+ }
155+
156+ func (r * EvictionReconciler ) updateStatus (ctx context.Context , eviction , base * kvmv1.Eviction ) error {
157+ return r .Status ().Patch (ctx , eviction , client .MergeFromWithOptions (base , client.MergeFromWithOptimisticLock {}), client .FieldOwner (EvictionControllerName ))
152158}
153159
154160func (r * EvictionReconciler ) handlePreflight (ctx context.Context , eviction * kvmv1.Eviction ) (ctrl.Result , error ) {
161+ base := eviction .DeepCopy ()
155162 hypervisorName := eviction .Spec .Hypervisor
156163
157164 // Does the hypervisor even exist? Is it enabled/disabled?
@@ -176,7 +183,7 @@ func (r *EvictionReconciler) handlePreflight(ctx context.Context, eviction *kvmv
176183 Message : err .Error (),
177184 Reason : kvmv1 .ConditionReasonFailed ,
178185 })
179- return ctrl.Result {}, r .Status (). Update ( ctx , eviction )
186+ return ctrl.Result {}, r .updateStatus ( ctx , eviction , base )
180187 } else {
181188 // That is (likely) an eviction for a node that never registered
182189 // so we are good to go
@@ -189,7 +196,7 @@ func (r *EvictionReconciler) handlePreflight(ctx context.Context, eviction *kvmv
189196 })
190197 eviction .Status .OutstandingRamMb = 0
191198 logger .FromContext (ctx ).Info (msg )
192- return ctrl.Result {}, r .Status (). Update ( ctx , eviction )
199+ return ctrl.Result {}, r .updateStatus ( ctx , eviction , base )
193200 }
194201 }
195202
@@ -204,7 +211,7 @@ func (r *EvictionReconciler) handlePreflight(ctx context.Context, eviction *kvmv
204211 Message : err .Error (),
205212 Reason : kvmv1 .ConditionReasonFailed ,
206213 })
207- return ctrl.Result {}, r .Status (). Update ( ctx , eviction )
214+ return ctrl.Result {}, r .updateStatus ( ctx , eviction , base )
208215 }
209216
210217 if ! meta .IsStatusConditionTrue (eviction .Status .Conditions , kvmv1 .ConditionTypeHypervisorDisabled ) {
@@ -235,15 +242,18 @@ func (r *EvictionReconciler) handlePreflight(ctx context.Context, eviction *kvmv
235242 Message : "Preflight checks passed, hypervisor is disabled and ready for eviction" ,
236243 Reason : kvmv1 .ConditionReasonSucceeded ,
237244 })
238- return ctrl.Result {}, r .Status (). Update ( ctx , eviction )
245+ return ctrl.Result {}, r .updateStatus ( ctx , eviction , base )
239246}
240247
241248// Tries to handle the NotFound-error by updating the status
242- func (r * EvictionReconciler ) handleNotFound (ctx context.Context , eviction * kvmv1.Eviction , err error ) error {
249+ func (r * EvictionReconciler ) handleNotFound (ctx context.Context , eviction , base * kvmv1.Eviction , err error ) error {
243250 if ! gophercloud .ResponseCodeIs (err , http .StatusNotFound ) {
244251 return err
245252 }
246253 logger .FromContext (ctx ).Info ("Instance is gone" )
254+ if base == nil {
255+ base = eviction .DeepCopy ()
256+ }
247257 instances := & eviction .Status .OutstandingInstances
248258 uuid := (* instances )[len (* instances )- 1 ]
249259 * instances = (* instances )[:len (* instances )- 1 ]
@@ -253,10 +263,11 @@ func (r *EvictionReconciler) handleNotFound(ctx context.Context, eviction *kvmv1
253263 Message : fmt .Sprintf ("Instance %s is gone" , uuid ),
254264 Reason : kvmv1 .ConditionReasonSucceeded ,
255265 })
256- return r .Status (). Update ( ctx , eviction )
266+ return r .updateStatus ( ctx , eviction , base )
257267}
258268
259269func (r * EvictionReconciler ) evictNext (ctx context.Context , eviction * kvmv1.Eviction ) (ctrl.Result , error ) {
270+ base := eviction .DeepCopy ()
260271 instances := & eviction .Status .OutstandingInstances
261272 uuid := (* instances )[len (* instances )- 1 ]
262273 log := logger .FromContext (ctx ).WithName ("Evict" ).WithValues ("server" , uuid )
@@ -266,7 +277,7 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
266277 vm , err := res .Extract ()
267278
268279 if err != nil {
269- if err2 := r .handleNotFound (ctx , eviction , err ); err2 != nil {
280+ if err2 := r .handleNotFound (ctx , eviction , base , err ); err2 != nil {
270281 return ctrl.Result {}, err2
271282 } else {
272283 return ctrl.Result {RequeueAfter : shortRetryTime }, nil
@@ -293,7 +304,7 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
293304 Message : fmt .Sprintf ("Migration of instance %s failed: %s" , vm .ID , vm .Fault .Message ),
294305 Reason : kvmv1 .ConditionReasonFailed ,
295306 })
296- if err := r .Status (). Update ( ctx , eviction ); err != nil {
307+ if err := r .updateStatus ( ctx , eviction , base ); err != nil {
297308 return ctrl.Result {}, err
298309 }
299310
@@ -314,7 +325,7 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
314325 // So, it is already off this one, do we need to verify it?
315326 if vm .Status == "VERIFY_RESIZE" {
316327 err := servers .ConfirmResize (ctx , r .computeClient , vm .ID ).ExtractErr ()
317- if err2 := r .handleNotFound (ctx , eviction , err ); err2 != nil {
328+ if err2 := r .handleNotFound (ctx , eviction , base , err ); err2 != nil {
318329 // Retry confirm in next reconciliation
319330 return ctrl.Result {}, err2
320331 } else {
@@ -325,7 +336,7 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
325336
326337 // All done
327338 * instances = (* instances )[:len (* instances )- 1 ]
328- return ctrl.Result {}, r .Status (). Update ( ctx , eviction )
339+ return ctrl.Result {}, r .updateStatus ( ctx , eviction , base )
329340 }
330341
331342 if vm .TaskState == "deleting" { //nolint:gocritic
@@ -339,14 +350,14 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
339350 Message : fmt .Sprintf ("Live migration of terminating instance %s skipped" , vm .ID ),
340351 Reason : kvmv1 .ConditionReasonFailed ,
341352 })
342- if err2 := r .Status (). Update ( ctx , eviction ); err2 != nil {
353+ if err2 := r .updateStatus ( ctx , eviction , base ); err2 != nil {
343354 return ctrl.Result {}, fmt .Errorf ("could update status due to %w" , err2 )
344355 }
345356 } else if vm .Status == "ACTIVE" || vm .PowerState == 1 {
346357 log .Info ("trigger live-migration" )
347358 err := r .liveMigrate (ctx , vm .ID , eviction )
348359 if err != nil {
349- if err2 := r .handleNotFound (ctx , eviction , err ); err2 != nil {
360+ if err2 := r .handleNotFound (ctx , eviction , base , err ); err2 != nil {
350361 return ctrl.Result {}, err2
351362 } else {
352363 return ctrl.Result {RequeueAfter : shortRetryTime }, nil
@@ -356,7 +367,7 @@ func (r *EvictionReconciler) evictNext(ctx context.Context, eviction *kvmv1.Evic
356367 log .Info ("trigger cold-migration" )
357368 err := r .coldMigrate (ctx , vm .ID , eviction )
358369 if err != nil {
359- if err2 := r .handleNotFound (ctx , eviction , err ); err2 != nil {
370+ if err2 := r .handleNotFound (ctx , eviction , base , err ); err2 != nil {
360371 return ctrl.Result {}, err2
361372 } else {
362373 return ctrl.Result {RequeueAfter : shortRetryTime }, nil
@@ -389,9 +400,9 @@ func (r *EvictionReconciler) handleFinalizer(ctx context.Context, eviction *kvmv
389400 }
390401 }
391402
392- evictionBase := eviction .DeepCopy ()
403+ base := eviction .DeepCopy ()
393404 controllerutil .RemoveFinalizer (eviction , evictionFinalizerName )
394- return r .Patch (ctx , eviction , client .MergeFromWithOptions (evictionBase , client.MergeFromWithOptimisticLock {}))
405+ return r .Patch (ctx , eviction , client .MergeFromWithOptions (base , client.MergeFromWithOptimisticLock {}))
395406}
396407
397408func (r * EvictionReconciler ) enableHypervisorService (ctx context.Context , eviction * kvmv1.Eviction ) error {
@@ -400,18 +411,20 @@ func (r *EvictionReconciler) enableHypervisorService(ctx context.Context, evicti
400411 hypervisor , err := openstack .GetHypervisorByName (ctx , r .computeClient , eviction .Spec .Hypervisor , false )
401412 if err != nil {
402413 if errors .Is (err , openstack .ErrNoHypervisor ) {
414+ base := eviction .DeepCopy ()
403415 changed := meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
404416 Type : kvmv1 .ConditionTypeHypervisorReEnabled ,
405417 Status : metav1 .ConditionTrue ,
406418 Message : "Hypervisor is gone, no need to re-enable" ,
407419 Reason : kvmv1 .ConditionReasonSucceeded ,
408420 })
409421 if changed {
410- return r .Status (). Update ( ctx , eviction )
422+ return r .updateStatus ( ctx , eviction , base )
411423 } else {
412424 return nil
413425 }
414426 } else {
427+ base := eviction .DeepCopy ()
415428 errorMessage := fmt .Sprintf ("failed to get hypervisor due to %s" , err )
416429 // update the condition to reflect the error, and retry the reconciliation
417430 changed := meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
@@ -422,7 +435,7 @@ func (r *EvictionReconciler) enableHypervisorService(ctx context.Context, evicti
422435 })
423436
424437 if changed {
425- if err2 := r .Status (). Update ( ctx , eviction ); err2 != nil {
438+ if err2 := r .updateStatus ( ctx , eviction , base ); err2 != nil {
426439 log .Error (err , "failed to store error message in condition" , "message" , errorMessage )
427440 return err2
428441 }
@@ -433,14 +446,15 @@ func (r *EvictionReconciler) enableHypervisorService(ctx context.Context, evicti
433446 }
434447
435448 if hypervisor .Service .DisabledReason != r .evictionReason (eviction ) {
449+ base := eviction .DeepCopy ()
436450 changed := meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
437451 Type : kvmv1 .ConditionTypeHypervisorReEnabled ,
438452 Status : metav1 .ConditionTrue ,
439453 Message : "Hypervisor already re-enabled for reason:" + hypervisor .Service .DisabledReason ,
440454 Reason : kvmv1 .ConditionReasonSucceeded ,
441455 })
442456 if changed {
443- return r .Status (). Update ( ctx , eviction )
457+ return r .updateStatus ( ctx , eviction , base )
444458 } else {
445459 return nil
446460 }
@@ -451,6 +465,7 @@ func (r *EvictionReconciler) enableHypervisorService(ctx context.Context, evicti
451465 _ , err = services .Update (ctx , r .computeClient , hypervisor .Service .ID , enableService ).Extract ()
452466
453467 if err != nil {
468+ base := eviction .DeepCopy ()
454469 errorMessage := fmt .Sprintf ("failed to enable hypervisor due to %s" , err )
455470 changed := meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
456471 Type : kvmv1 .ConditionTypeHypervisorReEnabled ,
@@ -459,20 +474,21 @@ func (r *EvictionReconciler) enableHypervisorService(ctx context.Context, evicti
459474 Reason : kvmv1 .ConditionReasonFailed ,
460475 })
461476 if changed {
462- if err2 := r .Status (). Update ( ctx , eviction ); err2 != nil {
477+ if err2 := r .updateStatus ( ctx , eviction , base ); err2 != nil {
463478 log .Error (err , "failed to store error message in condition" , "message" , errorMessage )
464479 }
465480 }
466481 return ErrRetry
467482 } else {
483+ base := eviction .DeepCopy ()
468484 changed := meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
469485 Type : kvmv1 .ConditionTypeHypervisorReEnabled ,
470486 Status : metav1 .ConditionTrue ,
471487 Message : "Hypervisor re-enabled successfully" ,
472488 Reason : kvmv1 .ConditionReasonSucceeded ,
473489 })
474490 if changed {
475- return r .Status (). Update ( ctx , eviction )
491+ return r .updateStatus ( ctx , eviction , base )
476492 } else {
477493 return nil
478494 }
@@ -486,26 +502,28 @@ func (r *EvictionReconciler) disableHypervisor(ctx context.Context, hypervisor *
486502 disabledReason := hypervisor .Service .DisabledReason
487503
488504 if disabledReason != "" && disabledReason != evictionReason {
505+ base := eviction .DeepCopy ()
489506 // Disabled for another reason already
490507 meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
491508 Type : kvmv1 .ConditionTypeHypervisorDisabled ,
492509 Status : metav1 .ConditionTrue ,
493510 Message : fmt .Sprintf ("Hypervisor already disabled for reason %q" , disabledReason ),
494511 Reason : kvmv1 .ConditionReasonSucceeded ,
495512 })
496- return r .Status (). Update ( ctx , eviction )
513+ return r .updateStatus ( ctx , eviction , base )
497514 }
498515
499516 if ! controllerutil .ContainsFinalizer (eviction , evictionFinalizerName ) {
500- evictionBase := eviction .DeepCopy ()
517+ base := eviction .DeepCopy ()
501518 controllerutil .AddFinalizer (eviction , evictionFinalizerName )
502- return r .Patch (ctx , eviction , client .MergeFromWithOptions (evictionBase , client.MergeFromWithOptimisticLock {}))
519+ return r .Patch (ctx , eviction , client .MergeFromWithOptions (base , client.MergeFromWithOptimisticLock {}), client . FieldOwner ( EvictionControllerName ))
503520 }
504521
505522 disableService := services.UpdateOpts {Status : services .ServiceDisabled ,
506523 DisabledReason : r .evictionReason (eviction )}
507524
508525 _ , err := services .Update (ctx , r .computeClient , hypervisor .Service .ID , disableService ).Extract ()
526+ base := eviction .DeepCopy ()
509527 if err != nil {
510528 // We expect OpenStack calls to be transient errors, so we retry for the next reconciliation
511529 meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
@@ -514,7 +532,7 @@ func (r *EvictionReconciler) disableHypervisor(ctx context.Context, hypervisor *
514532 Message : fmt .Sprintf ("Failed to disable hypervisor: %v" , err ),
515533 Reason : kvmv1 .ConditionReasonFailed ,
516534 })
517- return r .Status (). Update ( ctx , eviction )
535+ return r .updateStatus ( ctx , eviction , base )
518536 }
519537
520538 meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
@@ -523,7 +541,7 @@ func (r *EvictionReconciler) disableHypervisor(ctx context.Context, hypervisor *
523541 Message : "Hypervisor disabled successfully" ,
524542 Reason : kvmv1 .ConditionReasonSucceeded ,
525543 })
526- return r .Status (). Update ( ctx , eviction )
544+ return r .updateStatus ( ctx , eviction , base )
527545}
528546
529547func (r * EvictionReconciler ) liveMigrate (ctx context.Context , uuid string , eviction * kvmv1.Eviction ) error {
@@ -568,28 +586,6 @@ func (r *EvictionReconciler) coldMigrate(ctx context.Context, uuid string, evict
568586 return nil
569587}
570588
571- // addCondition adds a condition to the Eviction status and updates the status
572- func (r * EvictionReconciler ) addCondition (ctx context.Context , eviction * kvmv1.Eviction ,
573- status metav1.ConditionStatus , message string , reason string ) bool {
574-
575- if ! meta .SetStatusCondition (& eviction .Status .Conditions , metav1.Condition {
576- Type : kvmv1 .ConditionTypeEvicting ,
577- Status : status ,
578- Message : message ,
579- Reason : reason ,
580- }) {
581- return false
582- }
583-
584- if err := r .Status ().Update (ctx , eviction ); err != nil {
585- log := logger .FromContext (ctx )
586- log .Error (err , "Failed to update conditions" )
587- return false
588- }
589-
590- return true
591- }
592-
593589// SetupWithManager sets up the controller with the Manager.
594590func (r * EvictionReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
595591 ctx := context .Background ()
0 commit comments