Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 Ensure infra and bootstrap objects are owned by Machines #7593

Merged
merged 1 commit into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions internal/controllers/machine/machine_controller_phases.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,11 @@ func (r *Reconciler) reconcileExternal(ctx context.Context, cluster *clusterv1.C
return external.ReconcileOutput{}, err
}

sbueringer marked this conversation as resolved.
Show resolved Hide resolved
// With the migration from v1alpha2 to v1alpha3, Machine controllers should be the owner for the
// infra Machines, hence remove any existing machineset controller owner reference
if controller := metav1.GetControllerOf(obj); controller != nil && controller.Kind == "MachineSet" {
gv, err := schema.ParseGroupVersion(controller.APIVersion)
if err != nil {
return external.ReconcileOutput{}, err
}
if gv.Group == clusterv1.GroupVersion.Group {
ownerRefs := util.RemoveOwnerRef(obj.GetOwnerReferences(), *controller)
obj.SetOwnerReferences(ownerRefs)
}
// removeOnCreateOwnerRefs removes MachineSet and control plane owners from the objects referred to by a Machine.
// These owner references are added initially because Machines don't exist when those objects are created.
// At this point the Machine exists and can be set as the controller reference.
if err := removeOnCreateOwnerRefs(cluster, m, obj); err != nil {
return external.ReconcileOutput{}, err
}

// Set external object ControllerReference to the Machine.
Expand Down Expand Up @@ -372,3 +366,33 @@ func (r *Reconciler) reconcileCertificateExpiry(ctx context.Context, _ *clusterv

return ctrl.Result{}, nil
}

// removeOnCreateOwnerRefs will remove any MachineSet or control plane owner references from passed objects.
func removeOnCreateOwnerRefs(cluster *clusterv1.Cluster, m *clusterv1.Machine, obj *unstructured.Unstructured) error {
cpGVK := getControlPlaneGVKForMachine(cluster, m)
for _, owner := range obj.GetOwnerReferences() {
ownerGV, err := schema.ParseGroupVersion(owner.APIVersion)
if err != nil {
return errors.Wrapf(err, "Could not remove ownerReference %v from object %s/%s", owner.String(), obj.GetKind(), obj.GetName())
}
if (ownerGV.Group == clusterv1.GroupVersion.Group && owner.Kind == "MachineSet") ||
(cpGVK != nil && ownerGV.Group == cpGVK.GroupVersion().Group && owner.Kind == cpGVK.Kind) {
ownerRefs := util.RemoveOwnerRef(obj.GetOwnerReferences(), owner)
obj.SetOwnerReferences(ownerRefs)
}
}
return nil
}

// getControlPlaneGVKForMachine returns the Kind of the control plane in the Cluster associated with the Machine.
// This function checks that the Machine is managed by a control plane, and then retrieves the Kind from the Cluster's
// .spec.controlPlaneRef.
func getControlPlaneGVKForMachine(cluster *clusterv1.Cluster, machine *clusterv1.Machine) *schema.GroupVersionKind {
if _, ok := machine.GetLabels()[clusterv1.MachineControlPlaneLabelName]; ok {
fabriziopandini marked this conversation as resolved.
Show resolved Hide resolved
if cluster.Spec.ControlPlaneRef != nil {
gvk := cluster.Spec.ControlPlaneRef.GroupVersionKind()
return &gvk
}
}
return nil
}
40 changes: 30 additions & 10 deletions internal/controllers/machineset/machineset_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,24 @@ func TestMachineSetReconciler(t *testing.T) {
g.Expect(im.GetAnnotations()).To(HaveKeyWithValue("annotation-1", "true"), "have annotations of MachineTemplate applied")
g.Expect(im.GetAnnotations()).To(HaveKeyWithValue("precedence", "MachineSet"), "the annotations from the MachineSpec template to overwrite the infrastructure template ones")
g.Expect(im.GetLabels()).To(HaveKeyWithValue("label-1", "true"), "have labels of MachineTemplate applied")
}
g.Eventually(func() bool {
killianmuldoon marked this conversation as resolved.
Show resolved Hide resolved
g.Expect(env.List(ctx, infraMachines, client.InNamespace(namespace.Name))).To(Succeed())
// The Machine reconciler should remove the ownerReference to the MachineSet on the InfrastructureMachine.
hasMSOwnerRef := false
for _, o := range im.GetOwnerReferences() {
if o.Kind == machineSetKind.Kind {
hasMSOwnerRef = true
hasMachineOwnerRef := false
for _, im := range infraMachines.Items {
for _, o := range im.GetOwnerReferences() {
if o.Kind == machineSetKind.Kind {
hasMSOwnerRef = true
}
if o.Kind == "Machine" {
hasMachineOwnerRef = true
}
}
}
g.Expect(hasMSOwnerRef).To(BeTrue(), "have ownerRef to MachineSet")
}
return !hasMSOwnerRef && hasMachineOwnerRef
}, timeout).Should(BeTrue(), "infraMachine should not have ownerRef to MachineSet")

t.Log("Creating a BootstrapConfig for each Machine")
bootstrapConfigs := &unstructured.UnstructuredList{}
Expand All @@ -251,14 +261,24 @@ func TestMachineSetReconciler(t *testing.T) {
g.Expect(im.GetAnnotations()).To(HaveKeyWithValue("annotation-1", "true"), "have annotations of MachineTemplate applied")
g.Expect(im.GetAnnotations()).To(HaveKeyWithValue("precedence", "MachineSet"), "the annotations from the MachineSpec template to overwrite the bootstrap config template ones")
g.Expect(im.GetLabels()).To(HaveKeyWithValue("label-1", "true"), "have labels of MachineTemplate applied")
}
g.Eventually(func() bool {
g.Expect(env.List(ctx, bootstrapConfigs, client.InNamespace(namespace.Name))).To(Succeed())
// The Machine reconciler should remove the ownerReference to the MachineSet on the Bootstrap object.
hasMSOwnerRef := false
for _, o := range im.GetOwnerReferences() {
if o.Kind == machineSetKind.Kind {
hasMSOwnerRef = true
hasMachineOwnerRef := false
for _, im := range bootstrapConfigs.Items {
for _, o := range im.GetOwnerReferences() {
if o.Kind == machineSetKind.Kind {
hasMSOwnerRef = true
}
if o.Kind == "Machine" {
hasMachineOwnerRef = true
}
}
}
g.Expect(hasMSOwnerRef).To(BeTrue(), "have ownerRef to MachineSet")
}
return !hasMSOwnerRef && hasMachineOwnerRef
}, timeout).Should(BeTrue(), "bootstrap should not have ownerRef to MachineSet")

// Set the infrastructure reference as ready.
for _, m := range machines.Items {
Expand Down