Skip to content
Permalink
Browse files

Merge pull request #1688 from vincepri/md-ms-match-labels

Auto-select on cluster-name label in MachineDeployment and MachineSet
  • Loading branch information...
k8s-ci-robot committed Nov 8, 2019
2 parents 685e7dc + 36cf145 commit 86c86080fc55577960c83d68f24df385e8e1b476
@@ -19,7 +19,6 @@ package controllers
import (
"context"
"fmt"
"reflect"

"github.com/go-logr/logr"
"github.com/pkg/errors"
@@ -109,49 +108,26 @@ func (r *MachineDeploymentReconciler) Reconcile(req ctrl.Request) (ctrl.Result,

func (r *MachineDeploymentReconciler) reconcile(ctx context.Context, d *clusterv1.MachineDeployment) (ctrl.Result, error) {
logger := r.Log.WithValues("machinedeployment", d.Name, "namespace", d.Namespace)
logger.V(4).Info("Reconcile MachineDeployment")

// Reconcile defaults.
clusterv1.PopulateDefaultsMachineDeployment(d)

// Test for an empty LabelSelector and short circuit if that is the case
// TODO: When we have validation webhooks, we should likely reject on an empty LabelSelector
everything := metav1.LabelSelector{}
if reflect.DeepEqual(d.Spec.Selector, &everything) {
if d.Status.ObservedGeneration < d.Generation {
patch := client.MergeFrom(d.DeepCopy())
d.Status.ObservedGeneration = d.Generation
if err := r.Client.Status().Patch(ctx, d, patch); err != nil {
logger.Error(err, "Failed to patch status")
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}

// Make sure that label selector can match the template's labels.
// TODO(vincepri): Move to a validation (admission) webhook when supported.
selector, err := metav1.LabelSelectorAsSelector(&d.Spec.Selector)
if err != nil {
return ctrl.Result{}, errors.Wrapf(err, "failed to parse MachineDeployment %q label selector", d.Name)
}

if !selector.Matches(labels.Set(d.Spec.Template.Labels)) {
return ctrl.Result{}, errors.Errorf("failed validation on MachineDeployment %q label selector, cannot match Machine template labels", d.Name)
}

// Copy label selector to its status counterpart in string format.
// This is necessary for CRDs including scale subresources.
d.Status.Selector = selector.String()

// Reconcile and retrieve the Cluster object.
if d.Labels == nil {
d.Labels = make(map[string]string)
}
d.Labels[clusterv1.ClusterLabelName] = d.Spec.ClusterName

// Add MachineDeploymentLabelName label to machines
// Make sure selector and template to be in the same cluster.
d.Spec.Selector.MatchLabels[clusterv1.ClusterLabelName] = d.Spec.ClusterName
d.Spec.Template.Labels[clusterv1.ClusterLabelName] = d.Spec.ClusterName

// Add label and selector based on the MachineDeployment's name.
d.Spec.Selector.MatchLabels[clusterv1.MachineDeploymentLabelName] = d.Name
d.Spec.Template.Labels[clusterv1.MachineDeploymentLabelName] = d.Name

// Check for Cluster ownership.
cluster, err := util.GetClusterByName(ctx, r.Client, d.ObjectMeta.Namespace, d.Spec.ClusterName)
if err != nil {
return ctrl.Result{}, err
@@ -172,6 +148,17 @@ func (r *MachineDeploymentReconciler) reconcile(ctx context.Context, d *clusterv
}
}

// Make sure that label selector can match the template's labels.
// TODO(vincepri): Move to a validation (admission) webhook when supported.
selector, err := metav1.LabelSelectorAsSelector(&d.Spec.Selector)
if err != nil {
return ctrl.Result{}, errors.Wrapf(err, "failed to parse MachineDeployment %q label selector", d.Name)
}

if !selector.Matches(labels.Set(d.Spec.Template.Labels)) {
return ctrl.Result{}, errors.Errorf("failed validation on MachineDeployment %q label selector, cannot match Machine template labels", d.Name)
}

msList, err := r.getMachineSetsForDeployment(d)
if err != nil {
return ctrl.Result{}, err
@@ -327,6 +327,9 @@ var _ = Describe("MachineDeployment Reconciler", func() {

return len(machineSets.Items)
}, timeout*5).Should(BeEquivalentTo(0))

// Validate that the controller set the cluster name label in selector.
Expect(deployment.Status.Selector).To(ContainSubstring(testCluster.Name))
})
})

@@ -362,9 +362,13 @@ func calculateStatus(allMSs []*clusterv1.MachineSet, newMS *clusterv1.MachineSet
unavailableReplicas = 0
}

// Calculate the label selector. We check the error in the MD reconcile function, ignore here.
selector, _ := metav1.LabelSelectorAsSelector(&deployment.Spec.Selector) //nolint

status := clusterv1.MachineDeploymentStatus{
// TODO: Ensure that if we start retrying status updates, we won't pick up a new Generation value.
ObservedGeneration: deployment.Generation,
Selector: selector.String(),
Replicas: mdutil.GetActualReplicaCountForMachineSets(allMSs),
UpdatedReplicas: mdutil.GetActualReplicaCountForMachineSets([]*clusterv1.MachineSet{newMS}),
ReadyReplicas: mdutil.GetReadyReplicaCountForMachineSets(allMSs),
@@ -121,9 +121,46 @@ func (r *MachineSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error)

func (r *MachineSetReconciler) reconcile(ctx context.Context, machineSet *clusterv1.MachineSet) (ctrl.Result, error) {
logger := r.Log.WithValues("machineset", machineSet.Name, "namespace", machineSet.Namespace)

logger.V(4).Info("Reconcile MachineSet")

// Reconcile and retrieve the Cluster object.
if machineSet.Labels == nil {
machineSet.Labels = make(map[string]string)
}
machineSet.Labels[clusterv1.ClusterLabelName] = machineSet.Spec.ClusterName

cluster, err := util.GetClusterByName(ctx, r.Client, machineSet.ObjectMeta.Namespace, machineSet.Spec.ClusterName)
if err != nil {
return ctrl.Result{}, err
}

if r.shouldAdopt(machineSet) {
patch := client.MergeFrom(machineSet.DeepCopy())
machineSet.OwnerReferences = util.EnsureOwnerRef(machineSet.OwnerReferences, metav1.OwnerReference{
APIVersion: clusterv1.GroupVersion.String(),
Kind: "Cluster",
Name: cluster.Name,
UID: cluster.UID,
})
// Patch using a deep copy to avoid overwriting any unexpected Status changes from the returned result
if err := r.Client.Patch(ctx, machineSet.DeepCopy(), patch); err != nil {
return ctrl.Result{}, errors.Wrapf(
err,
"failed to add OwnerReference to MachineSet %s/%s",
machineSet.Namespace,
machineSet.Name,
)
}
}

// Make sure selector and template to be in the same cluster.
machineSet.Spec.Selector.MatchLabels[clusterv1.ClusterLabelName] = machineSet.Spec.ClusterName
machineSet.Spec.Template.Labels[clusterv1.ClusterLabelName] = machineSet.Spec.ClusterName

// Add label and selector based on the MachineSet's name.
machineSet.Spec.Selector.MatchLabels[clusterv1.MachineSetLabelName] = machineSet.Name
machineSet.Spec.Template.Labels[clusterv1.MachineSetLabelName] = machineSet.Name

// Make sure that label selector can match template's labels.
// TODO(vincepri): Move to a validation (admission) webhook when supported.
selector, err := metav1.LabelSelectorAsSelector(&machineSet.Spec.Selector)
@@ -155,36 +192,6 @@ func (r *MachineSetReconciler) reconcile(ctx context.Context, machineSet *cluste
return ctrl.Result{}, errors.Wrap(err, "failed to list machines")
}

// Reconcile and retrieve the Cluster object.
if machineSet.Labels == nil {
machineSet.Labels = make(map[string]string)
}
machineSet.Labels[clusterv1.ClusterLabelName] = machineSet.Spec.ClusterName

cluster, err := util.GetClusterByName(ctx, r.Client, machineSet.ObjectMeta.Namespace, machineSet.Spec.ClusterName)
if err != nil {
return ctrl.Result{}, err
}

if r.shouldAdopt(machineSet) {
patch := client.MergeFrom(machineSet.DeepCopy())
machineSet.OwnerReferences = util.EnsureOwnerRef(machineSet.OwnerReferences, metav1.OwnerReference{
APIVersion: clusterv1.GroupVersion.String(),
Kind: "Cluster",
Name: cluster.Name,
UID: cluster.UID,
})
// Patch using a deep copy to avoid overwriting any unexpected Status changes from the returned result
if err := r.Client.Patch(ctx, machineSet.DeepCopy(), patch); err != nil {
return ctrl.Result{}, errors.Wrapf(
err,
"failed to add OwnerReference to MachineSet %s/%s",
machineSet.Namespace,
machineSet.Name,
)
}
}

// Filter out irrelevant machines (deleting/mismatch labels) and claim orphaned machines.
filteredMachines := make([]*clusterv1.Machine, 0, len(allMachines.Items))
for idx := range allMachines.Items {
@@ -395,7 +402,6 @@ func (r *MachineSetReconciler) getNewMachine(machineSet *clusterv1.MachineSet) *
if machine.Labels == nil {
machine.Labels = make(map[string]string)
}
machine.Labels[clusterv1.MachineSetLabelName] = machineSet.Name
return machine
}

@@ -201,6 +201,9 @@ var _ = Describe("MachineSet Reconciler", func() {
}
return instance.Status.AvailableReplicas
}, timeout).Should(BeEquivalentTo(replicas))

// Validate that the controller set the cluster name label in selector.
Expect(instance.Status.Selector).To(ContainSubstring(testCluster.Name))
})
})

0 comments on commit 86c8608

Please sign in to comment.
You can’t perform that action at this time.