Skip to content

Commit d8d7056

Browse files
authored
Merge pull request #12528 from richardcase/mp_v1beta2_replicas
✨ feat: set new replica fields for machine pools
2 parents 4e37a51 + 7bf5a92 commit d8d7056

File tree

5 files changed

+322
-82
lines changed

5 files changed

+322
-82
lines changed

exp/internal/controllers/machinepool_controller.go

Lines changed: 152 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949
"sigs.k8s.io/cluster-api/util/conditions"
5050
v1beta1conditions "sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1"
5151
"sigs.k8s.io/cluster-api/util/finalizers"
52+
"sigs.k8s.io/cluster-api/util/labels/format"
5253
"sigs.k8s.io/cluster-api/util/patch"
5354
"sigs.k8s.io/cluster-api/util/paused"
5455
"sigs.k8s.io/cluster-api/util/predicates"
@@ -62,10 +63,8 @@ import (
6263
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io;bootstrap.cluster.x-k8s.io,resources=*,verbs=get;list;watch;create;update;patch;delete
6364
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status;machinepools/finalizers,verbs=get;list;watch;create;update;patch;delete
6465

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")
6968

7069
const (
7170
// MachinePoolControllerName defines the controller used when creating clients.
@@ -89,21 +88,6 @@ type MachinePoolReconciler struct {
8988
predicateLog *logr.Logger
9089
}
9190

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-
10791
func (r *MachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
10892
if r.Client == nil || r.APIReader == nil || r.ClusterCache == nil {
10993
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)
189173
return ctrl.Result{}, err
190174
}
191175

176+
// Handle normal reconciliation loop.
177+
scope := &scope{
178+
cluster: cluster,
179+
machinePool: mp,
180+
}
181+
192182
defer func() {
183+
if err := r.updateStatus(ctx, scope); err != nil {
184+
reterr = kerrors.NewAggregate([]error{reterr, err})
185+
}
186+
193187
r.reconcilePhase(mp)
194188
// TODO(jpang): add support for metrics.
195189

@@ -223,79 +217,69 @@ func (r *MachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request)
223217
}
224218
}()
225219

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"),
229222
}
230-
mp.Labels[clusterv1.ClusterNameLabel] = mp.Spec.ClusterName
231223

232224
// Handle deletion reconciliation loop.
233225
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)
235231
}
236232

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)
243242
}
244243

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) {
247245
cluster := s.cluster
248246
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+
249253
mp.SetOwnerReferences(util.EnsureOwnerRef(mp.GetOwnerReferences(), metav1.OwnerReference{
250254
APIVersion: clusterv1.GroupVersion.String(),
251255
Kind: "Cluster",
252256
Name: cluster.Name,
253257
UID: cluster.UID,
254258
}))
255259

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
277261
}
278262

279263
// 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 {
282266
// Return early and don't remove the finalizer if we got an error or
283267
// the external reconciliation deletion isn't ready.
284-
return err
268+
return ctrl.Result{}, fmt.Errorf("failed deleting external references: %s", err)
285269
}
286270

287271
// 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 {
290274
// 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)
292276
}
293277
} else {
294278
ctrl.LoggerFrom(ctx).Info("NodeDeleteTimeout passed, skipping Nodes deletion")
295279
}
296280

297-
controllerutil.RemoveFinalizer(machinePool, clusterv1.MachinePoolFinalizer)
298-
return nil
281+
controllerutil.RemoveFinalizer(s.machinePool, clusterv1.MachinePoolFinalizer)
282+
return ctrl.Result{}, nil
299283
}
300284

301285
// reconcileDeleteNodes delete the cluster nodes.
@@ -430,3 +414,110 @@ func (r *MachinePoolReconciler) nodeToMachinePool(ctx context.Context, o client.
430414

431415
return nil
432416
}
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+
}

exp/internal/controllers/machinepool_controller_phases.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s *
276276
return ctrl.Result{}, err
277277
}
278278
infraConfig := infraReconcileResult.Result
279+
s.infraMachinePool = infraConfig
279280

280281
if !infraConfig.GetDeletionTimestamp().IsZero() {
281282
return ctrl.Result{}, nil

0 commit comments

Comments
 (0)