@@ -49,6 +49,7 @@ import (
49
49
"sigs.k8s.io/cluster-api/util/conditions"
50
50
v1beta1conditions "sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1"
51
51
"sigs.k8s.io/cluster-api/util/finalizers"
52
+ "sigs.k8s.io/cluster-api/util/labels/format"
52
53
"sigs.k8s.io/cluster-api/util/patch"
53
54
"sigs.k8s.io/cluster-api/util/paused"
54
55
"sigs.k8s.io/cluster-api/util/predicates"
@@ -62,10 +63,8 @@ import (
62
63
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io;bootstrap.cluster.x-k8s.io,resources=*,verbs=get;list;watch;create;update;patch;delete
63
64
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status;machinepools/finalizers,verbs=get;list;watch;create;update;patch;delete
64
65
65
- var (
66
- // machinePoolKind contains the schema.GroupVersionKind for the MachinePool type.
67
- machinePoolKind = clusterv1 .GroupVersion .WithKind ("MachinePool" )
68
- )
66
+ // machinePoolKind contains the schema.GroupVersionKind for the MachinePool type.
67
+ var machinePoolKind = clusterv1 .GroupVersion .WithKind ("MachinePool" )
69
68
70
69
const (
71
70
// MachinePoolControllerName defines the controller used when creating clients.
@@ -89,21 +88,6 @@ type MachinePoolReconciler struct {
89
88
predicateLog * logr.Logger
90
89
}
91
90
92
- // scope holds the different objects that are read and used during the reconcile.
93
- type scope struct {
94
- // cluster is the Cluster object the Machine belongs to.
95
- // It is set at the beginning of the reconcile function.
96
- cluster * clusterv1.Cluster
97
-
98
- // machinePool is the MachinePool object. It is set at the beginning
99
- // of the reconcile function.
100
- machinePool * clusterv1.MachinePool
101
-
102
- // nodeRefMapResult is a map of providerIDs to Nodes that are associated with the Cluster.
103
- // It is set after reconcileInfrastructure is called.
104
- nodeRefMap map [string ]* corev1.Node
105
- }
106
-
107
91
func (r * MachinePoolReconciler ) SetupWithManager (ctx context.Context , mgr ctrl.Manager , options controller.Options ) error {
108
92
if r .Client == nil || r .APIReader == nil || r .ClusterCache == nil {
109
93
return errors .New ("Client, APIReader and ClusterCache must not be nil" )
@@ -189,7 +173,17 @@ func (r *MachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request)
189
173
return ctrl.Result {}, err
190
174
}
191
175
176
+ // Handle normal reconciliation loop.
177
+ scope := & scope {
178
+ cluster : cluster ,
179
+ machinePool : mp ,
180
+ }
181
+
192
182
defer func () {
183
+ if err := r .updateStatus (ctx , scope ); err != nil {
184
+ reterr = kerrors .NewAggregate ([]error {reterr , err })
185
+ }
186
+
193
187
r .reconcilePhase (mp )
194
188
// TODO(jpang): add support for metrics.
195
189
@@ -223,79 +217,69 @@ func (r *MachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request)
223
217
}
224
218
}()
225
219
226
- // Reconcile labels.
227
- if mp .Labels == nil {
228
- mp .Labels = make (map [string ]string )
220
+ alwaysReconcile := []machinePoolReconcileFunc {
221
+ wrapErrMachinePoolReconcileFunc (r .reconcileSetOwnerAndLabels , "failed to set MachinePool owner and labels" ),
229
222
}
230
- mp .Labels [clusterv1 .ClusterNameLabel ] = mp .Spec .ClusterName
231
223
232
224
// Handle deletion reconciliation loop.
233
225
if ! mp .DeletionTimestamp .IsZero () {
234
- return ctrl.Result {}, r .reconcileDelete (ctx , cluster , mp )
226
+ reconcileDelete := append (
227
+ alwaysReconcile ,
228
+ wrapErrMachinePoolReconcileFunc (r .reconcileDelete , "failed to reconcile delete" ),
229
+ )
230
+ return doReconcile (ctx , scope , reconcileDelete )
235
231
}
236
232
237
- // Handle normal reconciliation loop.
238
- scope := & scope {
239
- cluster : cluster ,
240
- machinePool : mp ,
241
- }
242
- return r .reconcile (ctx , scope )
233
+ reconcileNormal := append (alwaysReconcile ,
234
+ wrapErrMachinePoolReconcileFunc (r .reconcileBootstrap , "failed to reconcile bootstrap config" ),
235
+ wrapErrMachinePoolReconcileFunc (r .reconcileInfrastructure , "failed to reconcile infrastructure" ),
236
+ wrapErrMachinePoolReconcileFunc (r .getMachinesForMachinePool , "failed to get Machines for MachinePool" ),
237
+ wrapErrMachinePoolReconcileFunc (r .reconcileNodeRefs , "failed to reconcile nodeRefs" ),
238
+ wrapErrMachinePoolReconcileFunc (r .setMachinesUptoDate , "failed to set machines up to date" ),
239
+ )
240
+
241
+ return doReconcile (ctx , scope , reconcileNormal )
243
242
}
244
243
245
- func (r * MachinePoolReconciler ) reconcile (ctx context.Context , s * scope ) (ctrl.Result , error ) {
246
- // Ensure the MachinePool is owned by the Cluster it belongs to.
244
+ func (r * MachinePoolReconciler ) reconcileSetOwnerAndLabels (_ context.Context , s * scope ) (ctrl.Result , error ) {
247
245
cluster := s .cluster
248
246
mp := s .machinePool
247
+
248
+ if mp .Labels == nil {
249
+ mp .Labels = make (map [string ]string )
250
+ }
251
+ mp .Labels [clusterv1 .ClusterNameLabel ] = mp .Spec .ClusterName
252
+
249
253
mp .SetOwnerReferences (util .EnsureOwnerRef (mp .GetOwnerReferences (), metav1.OwnerReference {
250
254
APIVersion : clusterv1 .GroupVersion .String (),
251
255
Kind : "Cluster" ,
252
256
Name : cluster .Name ,
253
257
UID : cluster .UID ,
254
258
}))
255
259
256
- phases := []func (context.Context , * scope ) (ctrl.Result , error ){
257
- r .reconcileBootstrap ,
258
- r .reconcileInfrastructure ,
259
- r .reconcileNodeRefs ,
260
- }
261
-
262
- res := ctrl.Result {}
263
- errs := []error {}
264
- for _ , phase := range phases {
265
- // Call the inner reconciliation methods.
266
- phaseResult , err := phase (ctx , s )
267
- if err != nil {
268
- errs = append (errs , err )
269
- }
270
- if len (errs ) > 0 {
271
- continue
272
- }
273
-
274
- res = util .LowestNonZeroResult (res , phaseResult )
275
- }
276
- return res , kerrors .NewAggregate (errs )
260
+ return ctrl.Result {}, nil
277
261
}
278
262
279
263
// reconcileDelete delete machinePool related resources.
280
- func (r * MachinePoolReconciler ) reconcileDelete (ctx context.Context , cluster * clusterv1. Cluster , machinePool * clusterv1. MachinePool ) error {
281
- if ok , err := r .reconcileDeleteExternal (ctx , machinePool ); ! ok || err != nil {
264
+ func (r * MachinePoolReconciler ) reconcileDelete (ctx context.Context , s * scope ) (ctrl. Result , error ) {
265
+ if ok , err := r .reconcileDeleteExternal (ctx , s . machinePool ); ! ok || err != nil {
282
266
// Return early and don't remove the finalizer if we got an error or
283
267
// the external reconciliation deletion isn't ready.
284
- return err
268
+ return ctrl. Result {}, fmt . Errorf ( "failed deleting external references: %s" , err )
285
269
}
286
270
287
271
// check nodes delete timeout passed.
288
- if ! r .isMachinePoolNodeDeleteTimeoutPassed (machinePool ) {
289
- if err := r .reconcileDeleteNodes (ctx , cluster , machinePool ); err != nil {
272
+ if ! r .isMachinePoolNodeDeleteTimeoutPassed (s . machinePool ) {
273
+ if err := r .reconcileDeleteNodes (ctx , s . cluster , s . machinePool ); err != nil {
290
274
// Return early and don't remove the finalizer if we got an error.
291
- return err
275
+ return ctrl. Result {}, fmt . Errorf ( "failed deleting nodes: %w" , err )
292
276
}
293
277
} else {
294
278
ctrl .LoggerFrom (ctx ).Info ("NodeDeleteTimeout passed, skipping Nodes deletion" )
295
279
}
296
280
297
- controllerutil .RemoveFinalizer (machinePool , clusterv1 .MachinePoolFinalizer )
298
- return nil
281
+ controllerutil .RemoveFinalizer (s . machinePool , clusterv1 .MachinePoolFinalizer )
282
+ return ctrl. Result {}, nil
299
283
}
300
284
301
285
// reconcileDeleteNodes delete the cluster nodes.
@@ -430,3 +414,110 @@ func (r *MachinePoolReconciler) nodeToMachinePool(ctx context.Context, o client.
430
414
431
415
return nil
432
416
}
417
+
418
+ func (r * MachinePoolReconciler ) getMachinesForMachinePool (ctx context.Context , s * scope ) (ctrl.Result , error ) {
419
+ infraMachineSelector := metav1.LabelSelector {
420
+ MatchLabels : map [string ]string {
421
+ clusterv1 .MachinePoolNameLabel : format .MustFormatValue (s .machinePool .Name ),
422
+ clusterv1 .ClusterNameLabel : s .machinePool .Spec .ClusterName ,
423
+ },
424
+ }
425
+
426
+ allMachines := & clusterv1.MachineList {}
427
+ if err := r .Client .List (ctx ,
428
+ allMachines ,
429
+ client .InNamespace (s .machinePool .Namespace ),
430
+ client .MatchingLabels (infraMachineSelector .MatchLabels )); err != nil {
431
+ return ctrl.Result {}, err
432
+ }
433
+
434
+ filteredMachines := make ([]* clusterv1.Machine , 0 , len (allMachines .Items ))
435
+ for idx := range allMachines .Items {
436
+ machine := & allMachines .Items [idx ]
437
+ if shouldExcludeMachine (s .machinePool , machine ) {
438
+ continue
439
+ }
440
+ filteredMachines = append (filteredMachines , machine )
441
+ }
442
+
443
+ s .machines = filteredMachines
444
+
445
+ return ctrl.Result {}, nil
446
+ }
447
+
448
+ func (r * MachinePoolReconciler ) setMachinesUptoDate (ctx context.Context , s * scope ) (ctrl.Result , error ) {
449
+ var errs []error
450
+ for _ , machine := range s .machines {
451
+ patchHelper , err := patch .NewHelper (machine , r .Client )
452
+ if err != nil {
453
+ errs = append (errs , err )
454
+ continue
455
+ }
456
+
457
+ upToDateCondition := & metav1.Condition {
458
+ Type : clusterv1 .MachineUpToDateCondition ,
459
+ }
460
+
461
+ if machine .DeletionTimestamp .IsZero () {
462
+ upToDateCondition .Status = metav1 .ConditionTrue
463
+ upToDateCondition .Reason = clusterv1 .MachineUpToDateReason
464
+ } else {
465
+ upToDateCondition .Status = metav1 .ConditionFalse
466
+ upToDateCondition .Reason = clusterv1 .MachineNotUpToDateReason
467
+ upToDateCondition .Message = "Machine is being deleted"
468
+ }
469
+ conditions .Set (machine , * upToDateCondition )
470
+
471
+ if err := patchHelper .Patch (ctx , machine , patch.WithOwnedConditions {Conditions : []string {
472
+ clusterv1 .MachineUpToDateCondition ,
473
+ }}); err != nil {
474
+ errs = append (errs , err )
475
+ continue
476
+ }
477
+ }
478
+
479
+ if len (errs ) > 0 {
480
+ return ctrl.Result {}, kerrors .NewAggregate (errs )
481
+ }
482
+
483
+ return ctrl.Result {}, nil
484
+ }
485
+
486
+ type machinePoolReconcileFunc func (ctx context.Context , s * scope ) (ctrl.Result , error )
487
+
488
+ func wrapErrMachinePoolReconcileFunc (f machinePoolReconcileFunc , msg string ) machinePoolReconcileFunc {
489
+ return func (ctx context.Context , s * scope ) (ctrl.Result , error ) {
490
+ res , err := f (ctx , s )
491
+ return res , errors .Wrap (err , msg )
492
+ }
493
+ }
494
+
495
+ func doReconcile (ctx context.Context , s * scope , phases []machinePoolReconcileFunc ) (ctrl.Result , kerrors.Aggregate ) {
496
+ res := ctrl.Result {}
497
+ errs := []error {}
498
+ for _ , phase := range phases {
499
+ // Call the inner reconciliation methods.
500
+ phaseResult , err := phase (ctx , s )
501
+ if err != nil {
502
+ errs = append (errs , err )
503
+ }
504
+ if len (errs ) > 0 {
505
+ continue
506
+ }
507
+ res = util .LowestNonZeroResult (res , phaseResult )
508
+ }
509
+
510
+ if len (errs ) > 0 {
511
+ return ctrl.Result {}, kerrors .NewAggregate (errs )
512
+ }
513
+
514
+ return res , nil
515
+ }
516
+
517
+ func shouldExcludeMachine (machinePool * clusterv1.MachinePool , machine * clusterv1.Machine ) bool {
518
+ if metav1 .GetControllerOf (machine ) != nil && ! metav1 .IsControlledBy (machine , machinePool ) {
519
+ return true
520
+ }
521
+
522
+ return false
523
+ }
0 commit comments