@@ -33,6 +33,7 @@ import (
33
33
"sigs.k8s.io/controller-runtime/pkg/builder"
34
34
"sigs.k8s.io/controller-runtime/pkg/client"
35
35
"sigs.k8s.io/controller-runtime/pkg/controller"
36
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
36
37
"sigs.k8s.io/controller-runtime/pkg/handler"
37
38
38
39
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -42,6 +43,7 @@ import (
42
43
"sigs.k8s.io/cluster-api/util/annotations"
43
44
"sigs.k8s.io/cluster-api/util/conditions"
44
45
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
46
+ clog "sigs.k8s.io/cluster-api/util/log"
45
47
"sigs.k8s.io/cluster-api/util/patch"
46
48
"sigs.k8s.io/cluster-api/util/predicates"
47
49
)
@@ -158,9 +160,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Re
158
160
}
159
161
}()
160
162
161
- // Ignore deleted MachineDeployments, this can happen when foregroundDeletion
162
- // is enabled
163
+ // Handle deletion reconciliation loop.
163
164
if ! deployment .DeletionTimestamp .IsZero () {
165
+ return ctrl.Result {}, r .reconcileDelete (ctx , deployment )
166
+ }
167
+
168
+ // Add finalizer first if not set to avoid the race condition between init and delete.
169
+ // Note: Finalizers in general can only be added when the deletionTimestamp is not set.
170
+ if ! controllerutil .ContainsFinalizer (deployment , clusterv1 .MachineDeploymentFinalizer ) {
171
+ controllerutil .AddFinalizer (deployment , clusterv1 .MachineDeploymentFinalizer )
164
172
return ctrl.Result {}, nil
165
173
}
166
174
@@ -225,7 +233,7 @@ func (r *Reconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster,
225
233
}
226
234
}
227
235
228
- msList , err := r .getMachineSetsForDeployment (ctx , md )
236
+ msList , err := r .getAndAdoptMachineSetsForDeployment (ctx , md )
229
237
if err != nil {
230
238
return err
231
239
}
@@ -286,8 +294,36 @@ func (r *Reconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster,
286
294
return errors .Errorf ("unexpected deployment strategy type: %s" , md .Spec .Strategy .Type )
287
295
}
288
296
289
- // getMachineSetsForDeployment returns a list of MachineSets associated with a MachineDeployment.
290
- func (r * Reconciler ) getMachineSetsForDeployment (ctx context.Context , md * clusterv1.MachineDeployment ) ([]* clusterv1.MachineSet , error ) {
297
+ func (r * Reconciler ) reconcileDelete (ctx context.Context , md * clusterv1.MachineDeployment ) error {
298
+ log := ctrl .LoggerFrom (ctx )
299
+ msList , err := r .getAndAdoptMachineSetsForDeployment (ctx , md )
300
+ if err != nil {
301
+ return err
302
+ }
303
+
304
+ // If all the descendant machinesets are deleted, then remove the machinedeployment's finalizer.
305
+ if len (msList ) == 0 {
306
+ controllerutil .RemoveFinalizer (md , clusterv1 .MachineDeploymentFinalizer )
307
+ return nil
308
+ }
309
+
310
+ log .Info ("Waiting for MachineSets to be deleted" , "MachineSets" , clog .ObjNamesString (msList ))
311
+
312
+ // else delete owned machinesets.
313
+ for _ , ms := range msList {
314
+ if ms .DeletionTimestamp .IsZero () {
315
+ log .Info ("Deleting MachineSet" , "MachineSet" , klog .KObj (ms ))
316
+ if err := r .Client .Delete (ctx , ms ); err != nil && ! apierrors .IsNotFound (err ) {
317
+ return errors .Wrapf (err , "failed to delete MachineSet %s" , klog .KObj (ms ))
318
+ }
319
+ }
320
+ }
321
+
322
+ return nil
323
+ }
324
+
325
+ // getAndAdoptMachineSetsForDeployment returns a list of MachineSets associated with a MachineDeployment.
326
+ func (r * Reconciler ) getAndAdoptMachineSetsForDeployment (ctx context.Context , md * clusterv1.MachineDeployment ) ([]* clusterv1.MachineSet , error ) {
291
327
log := ctrl .LoggerFrom (ctx )
292
328
293
329
// List all MachineSets to find those we own but that no longer match our selector.
@@ -299,7 +335,8 @@ func (r *Reconciler) getMachineSetsForDeployment(ctx context.Context, md *cluste
299
335
filtered := make ([]* clusterv1.MachineSet , 0 , len (machineSets .Items ))
300
336
for idx := range machineSets .Items {
301
337
ms := & machineSets .Items [idx ]
302
- log .WithValues ("MachineSet" , klog .KObj (ms ))
338
+ log := log .WithValues ("MachineSet" , klog .KObj (ms ))
339
+ ctx := ctrl .LoggerInto (ctx , log )
303
340
selector , err := metav1 .LabelSelectorAsSelector (& md .Spec .Selector )
304
341
if err != nil {
305
342
log .Error (err , "Skipping MachineSet, failed to get label selector from spec selector" )
0 commit comments