@@ -167,18 +167,6 @@ func (r *MachineReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr e
167
167
}
168
168
169
169
defer func () {
170
- // Always update the readyCondition with the summary of the machine conditions.
171
- conditions .SetSummary (m ,
172
- conditions .WithConditions (
173
- clusterv1 .BootstrapReadyCondition ,
174
- clusterv1 .InfrastructureReadyCondition ,
175
- // TODO: add MHC conditions here
176
- ),
177
- conditions .WithStepCounterIfOnly (
178
- clusterv1 .BootstrapReadyCondition ,
179
- clusterv1 .InfrastructureReadyCondition ,
180
- ),
181
- )
182
170
183
171
r .reconcilePhase (ctx , m )
184
172
@@ -188,7 +176,7 @@ func (r *MachineReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr e
188
176
if reterr == nil {
189
177
patchOpts = append (patchOpts , patch.WithStatusObservedGeneration {})
190
178
}
191
- if err := patchHelper . Patch (ctx , m , patchOpts ... ); err != nil {
179
+ if err := patchMachine (ctx , patchHelper , m , patchOpts ... ); err != nil {
192
180
reterr = kerrors .NewAggregate ([]error {reterr , err })
193
181
}
194
182
}()
@@ -214,6 +202,37 @@ func (r *MachineReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr e
214
202
return r .reconcile (ctx , cluster , m )
215
203
}
216
204
205
+ func patchMachine (ctx context.Context , patchHelper * patch.Helper , machine * clusterv1.Machine , options ... patch.Option ) error {
206
+ // Always update the readyCondition by summarizing the state of other conditions.
207
+ // A step counter is added to represent progress during the provisioning process (instead we are hiding it
208
+ // after provisioning - e.g. when a MHC condition exists - or during the deletion process).
209
+ conditions .SetSummary (machine ,
210
+ conditions .WithConditions (
211
+ clusterv1 .BootstrapReadyCondition ,
212
+ clusterv1 .InfrastructureReadyCondition ,
213
+ // TODO: add MHC conditions here
214
+ ),
215
+ conditions .WithStepCounterIf (machine .ObjectMeta .DeletionTimestamp .IsZero ()),
216
+ conditions .WithStepCounterIfOnly (
217
+ clusterv1 .BootstrapReadyCondition ,
218
+ clusterv1 .InfrastructureReadyCondition ,
219
+ ),
220
+ )
221
+
222
+ // Patch the object, ignoring conflicts on the conditions owned by this controller.
223
+ // Also, if requested, we are adding additional options like e.g. Patch ObservedGeneration when issuing the
224
+ // patch at the end of the reconcile loop.
225
+ options = append (options ,
226
+ patch.WithOwnedConditions {Conditions : []clusterv1.ConditionType {
227
+ clusterv1 .ReadyCondition ,
228
+ clusterv1 .BootstrapReadyCondition ,
229
+ clusterv1 .InfrastructureReadyCondition ,
230
+ }},
231
+ )
232
+
233
+ return patchHelper .Patch (ctx , machine , options ... )
234
+ }
235
+
217
236
func (r * MachineReconciler ) reconcile (ctx context.Context , cluster * clusterv1.Cluster , m * clusterv1.Machine ) (ctrl.Result , error ) {
218
237
logger := r .Log .WithValues ("machine" , m .Name , "namespace" , m .Namespace )
219
238
logger = logger .WithValues ("cluster" , cluster .Name )
@@ -270,20 +289,38 @@ func (r *MachineReconciler) reconcileDelete(ctx context.Context, cluster *cluste
270
289
}
271
290
272
291
if isDeleteNodeAllowed {
273
- // Drain node before deletion.
292
+ // Drain node before deletion and issue a patch in order to make this operation visible to the users .
274
293
if _ , exists := m .ObjectMeta .Annotations [clusterv1 .ExcludeNodeDrainingAnnotation ]; ! exists {
294
+ patchHelper , err := patch .NewHelper (m , r .Client )
295
+ if err != nil {
296
+ return ctrl.Result {}, err
297
+ }
298
+
275
299
logger .Info ("Draining node" , "node" , m .Status .NodeRef .Name )
300
+ conditions .MarkFalse (m , "DrainingSucceeded" , "Draining" , clusterv1 .ConditionSeverityInfo , "Draining the node before deletion" )
301
+ if err := patchMachine (ctx , patchHelper , m ); err != nil {
302
+ return ctrl.Result {}, errors .Wrap (err , "failed to patch Machine" )
303
+ }
304
+
276
305
if err := r .drainNode (ctx , cluster , m .Status .NodeRef .Name , m .Name ); err != nil {
306
+ conditions .MarkFalse (m , "DrainingSucceeded" , "DrainingError" , clusterv1 .ConditionSeverityWarning , err .Error ())
277
307
r .recorder .Eventf (m , corev1 .EventTypeWarning , "FailedDrainNode" , "error draining Machine's node %q: %v" , m .Status .NodeRef .Name , err )
278
308
return ctrl.Result {}, err
279
309
}
310
+
311
+ conditions .MarkTrue (m , "DrainingSucceeded" )
280
312
r .recorder .Eventf (m , corev1 .EventTypeNormal , "SuccessfulDrainNode" , "success draining Machine's node %q" , m .Status .NodeRef .Name )
281
313
}
282
314
}
283
315
284
- if ok , err := r .reconcileDeleteExternal (ctx , m ); ! ok || err != nil {
285
- // Return early and don't remove the finalizer if we got an error or
286
- // the external reconciliation deletion isn't ready.
316
+ // Return early and don't remove the finalizer if we got an error or
317
+ // the external reconciliation deletion isn't ready.
318
+
319
+ if ok , err := r .reconcileDeleteInfrastructure (ctx , m ); ! ok || err != nil {
320
+ return ctrl.Result {}, err
321
+ }
322
+
323
+ if ok , err := r .reconcileDeleteBootstrap (ctx , m ); ! ok || err != nil {
287
324
return ctrl.Result {}, err
288
325
}
289
326
@@ -430,41 +467,70 @@ func (r *MachineReconciler) deleteNode(ctx context.Context, cluster *clusterv1.C
430
467
return nil
431
468
}
432
469
433
- // reconcileDeleteExternal tries to delete external references, returning true if it cannot find any.
434
- func (r * MachineReconciler ) reconcileDeleteExternal (ctx context.Context , m * clusterv1.Machine ) (bool , error ) {
435
- objects := []* unstructured.Unstructured {}
436
- references := []* corev1.ObjectReference {
437
- m .Spec .Bootstrap .ConfigRef ,
438
- & m .Spec .InfrastructureRef ,
470
+ func (r * MachineReconciler ) reconcileDeleteBootstrap (ctx context.Context , m * clusterv1.Machine ) (bool , error ) {
471
+ obj , err := r .reconcileDeleteExternal (ctx , m , m .Spec .Bootstrap .ConfigRef )
472
+ if err != nil {
473
+ return false , err
439
474
}
440
475
441
- // Loop over the references and try to retrieve it with the client.
442
- for _ , ref := range references {
443
- if ref == nil {
444
- continue
445
- }
476
+ if obj == nil {
477
+ // Marks the bootstrap as deleted
478
+ conditions . MarkFalse ( m , clusterv1 . BootstrapReadyCondition , clusterv1 . DeletedReason , clusterv1 . ConditionSeverityInfo , "" )
479
+ return true , nil
480
+ }
446
481
447
- obj , err := external .Get (ctx , r .Client , ref , m .Namespace )
448
- if err != nil && ! apierrors .IsNotFound (errors .Cause (err )) {
449
- return false , errors .Wrapf (err , "failed to get %s %q for Machine %q in namespace %q" ,
450
- ref .GroupVersionKind (), ref .Name , m .Name , m .Namespace )
451
- }
452
- if obj != nil {
453
- objects = append (objects , obj )
454
- }
482
+ // Report a summary of current status of the bootstrap object defined for this machine.
483
+ conditions .SetMirror (m , clusterv1 .BootstrapReadyCondition ,
484
+ conditions .UnstructuredGetter (obj ),
485
+ conditions .WithFallbackValue (false , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" ),
486
+ )
487
+ return false , nil
488
+ }
489
+
490
+ func (r * MachineReconciler ) reconcileDeleteInfrastructure (ctx context.Context , m * clusterv1.Machine ) (bool , error ) {
491
+ obj , err := r .reconcileDeleteExternal (ctx , m , & m .Spec .InfrastructureRef )
492
+ if err != nil {
493
+ return false , err
494
+ }
495
+
496
+ if obj == nil {
497
+ // Marks the infrastructure as deleted
498
+ conditions .MarkFalse (m , clusterv1 .InfrastructureReadyCondition , clusterv1 .DeletedReason , clusterv1 .ConditionSeverityInfo , "" )
499
+ return true , nil
500
+ }
501
+
502
+ // Report a summary of current status of the bootstrap object defined for this machine.
503
+ conditions .SetMirror (m , clusterv1 .InfrastructureReadyCondition ,
504
+ conditions .UnstructuredGetter (obj ),
505
+ conditions .WithFallbackValue (false , clusterv1 .DeletingReason , clusterv1 .ConditionSeverityInfo , "" ),
506
+ )
507
+ return false , nil
508
+ }
509
+
510
+ // reconcileDeleteExternal tries to delete external references.
511
+ func (r * MachineReconciler ) reconcileDeleteExternal (ctx context.Context , m * clusterv1.Machine , ref * corev1.ObjectReference ) (* unstructured.Unstructured , error ) {
512
+ if ref == nil {
513
+ return nil , nil
514
+ }
515
+
516
+ // get the external object
517
+ obj , err := external .Get (ctx , r .Client , ref , m .Namespace )
518
+ if err != nil && ! apierrors .IsNotFound (errors .Cause (err )) {
519
+ return nil , errors .Wrapf (err , "failed to get %s %q for Machine %q in namespace %q" ,
520
+ ref .GroupVersionKind (), ref .Name , m .Name , m .Namespace )
455
521
}
456
522
457
- // Issue a delete request for any object that has been found.
458
- for _ , obj := range objects {
523
+ if obj != nil {
524
+ // Issue a delete request.
459
525
if err := r .Client .Delete (ctx , obj ); err != nil && ! apierrors .IsNotFound (err ) {
460
- return false , errors .Wrapf (err ,
526
+ return obj , errors .Wrapf (err ,
461
527
"failed to delete %v %q for Machine %q in namespace %q" ,
462
528
obj .GroupVersionKind (), obj .GetName (), m .Name , m .Namespace )
463
529
}
464
530
}
465
531
466
532
// Return true if there are no more external objects.
467
- return len ( objects ) == 0 , nil
533
+ return obj , nil
468
534
}
469
535
470
536
func (r * MachineReconciler ) shouldAdopt (m * clusterv1.Machine ) bool {
0 commit comments