Skip to content

Commit f1f8f38

Browse files
authored
Merge pull request #10694 from sbueringer/pr-fixup-finalizers
🌱 Preserve finalizers during MS/Machine reconciliation
2 parents 8500666 + 049a781 commit f1f8f38

File tree

6 files changed

+81
-16
lines changed

6 files changed

+81
-16
lines changed

internal/controllers/machinedeployment/machinedeployment_sync.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"k8s.io/apimachinery/pkg/types"
3030
kerrors "k8s.io/apimachinery/pkg/util/errors"
3131
apirand "k8s.io/apimachinery/pkg/util/rand"
32-
"k8s.io/apimachinery/pkg/util/sets"
3332
"k8s.io/apimachinery/pkg/util/wait"
3433
"k8s.io/klog/v2"
3534
"k8s.io/utils/ptr"
@@ -241,11 +240,6 @@ func (r *Reconciler) computeDesiredMachineSet(ctx context.Context, deployment *c
241240
name, randomSuffix = computeNewMachineSetName(deployment.Name + "-")
242241
uniqueIdentifierLabelValue = fmt.Sprintf("%d-%s", templateHash, randomSuffix)
243242

244-
// Add foregroundDeletion finalizer to MachineSet if the MachineDeployment has it.
245-
if sets.New[string](deployment.Finalizers...).Has(metav1.FinalizerDeleteDependents) {
246-
finalizers = []string{metav1.FinalizerDeleteDependents}
247-
}
248-
249243
replicas, err = mdutil.NewMSNewReplicas(deployment, oldMSs, 0)
250244
if err != nil {
251245
return nil, errors.Wrap(err, "failed to compute desired MachineSet")
@@ -268,15 +262,8 @@ func (r *Reconciler) computeDesiredMachineSet(ctx context.Context, deployment *c
268262
name = existingMS.Name
269263
uid = existingMS.UID
270264

271-
// Keep foregroundDeletion finalizer if the existingMS has it.
272-
// Note: This case is a little different from the create case. In the update case we preserve
273-
// the finalizer on the MachineSet if it already exists. Because of SSA we should not build
274-
// the finalizer information from the MachineDeployment when updating a MachineSet because that could lead
275-
// to dropping the finalizer from the MachineSet if it is dropped from the MachineDeployment.
276-
// We should not drop the finalizer on the MachineSet if the finalizer is dropped from the MachineDeployment.
277-
if sets.New[string](existingMS.Finalizers...).Has(metav1.FinalizerDeleteDependents) {
278-
finalizers = []string{metav1.FinalizerDeleteDependents}
279-
}
265+
// Preserve all existing finalizers (including foregroundDeletion finalizer).
266+
finalizers = existingMS.Finalizers
280267

281268
replicas = *existingMS.Spec.Replicas
282269

internal/controllers/machinedeployment/machinedeployment_sync_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,8 @@ func TestComputeDesiredMachineSet(t *testing.T) {
642642
"ms-label-1": "ms-value-1",
643643
}
644644
existingMS.Annotations = nil
645+
// Pre-existing finalizer should be preserved.
646+
existingMS.Finalizers = []string{"pre-existing-finalizer"}
645647
existingMS.Spec.Template.Labels = map[string]string{
646648
clusterv1.MachineDeploymentUniqueLabel: uniqueID,
647649
"ms-label-2": "ms-value-2",
@@ -657,6 +659,9 @@ func TestComputeDesiredMachineSet(t *testing.T) {
657659
expectedMS.UID = existingMSUID
658660
expectedMS.Name = deployment.Name + "-" + uniqueID
659661
expectedMS.Labels[clusterv1.MachineDeploymentUniqueLabel] = uniqueID
662+
// Pre-existing finalizer should be preserved.
663+
expectedMS.Finalizers = []string{"pre-existing-finalizer"}
664+
660665
expectedMS.Spec.Template.Labels[clusterv1.MachineDeploymentUniqueLabel] = uniqueID
661666

662667
g := NewWithT(t)
@@ -676,6 +681,8 @@ func TestComputeDesiredMachineSet(t *testing.T) {
676681
"ms-label-1": "ms-value-1",
677682
}
678683
existingMS.Annotations = nil
684+
// Pre-existing finalizer should be preserved.
685+
existingMS.Finalizers = []string{"pre-existing-finalizer"}
679686
existingMS.Spec.Template.Labels = map[string]string{
680687
clusterv1.MachineDeploymentUniqueLabel: uniqueID,
681688
"ms-label-2": "ms-value-2",
@@ -698,6 +705,8 @@ func TestComputeDesiredMachineSet(t *testing.T) {
698705
expectedMS.UID = existingMSUID
699706
expectedMS.Name = deployment.Name + "-" + uniqueID
700707
expectedMS.Labels[clusterv1.MachineDeploymentUniqueLabel] = uniqueID
708+
// Pre-existing finalizer should be preserved.
709+
expectedMS.Finalizers = []string{"pre-existing-finalizer"}
701710
expectedMS.Spec.Template.Labels[clusterv1.MachineDeploymentUniqueLabel] = uniqueID
702711

703712
g := NewWithT(t)
@@ -765,6 +774,9 @@ func assertMachineSet(g *WithT, actualMS *clusterv1.MachineSet, expectedMS *clus
765774
// Check Namespace
766775
g.Expect(actualMS.Namespace).Should(Equal(expectedMS.Namespace))
767776

777+
// Check finalizers
778+
g.Expect(actualMS.Finalizers).Should(Equal(expectedMS.Finalizers))
779+
768780
// Check Replicas
769781
g.Expect(actualMS.Spec.Replicas).ShouldNot(BeNil())
770782
g.Expect(actualMS.Spec.Replicas).Should(HaveValue(Equal(*expectedMS.Spec.Replicas)))

internal/controllers/machineset/machineset_controller.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3030
"k8s.io/apimachinery/pkg/labels"
3131
kerrors "k8s.io/apimachinery/pkg/util/errors"
32+
"k8s.io/apimachinery/pkg/util/sets"
3233
"k8s.io/apimachinery/pkg/util/wait"
3334
"k8s.io/apiserver/pkg/storage/names"
3435
"k8s.io/client-go/tools/record"
@@ -636,10 +637,18 @@ func (r *Reconciler) computeDesiredMachine(machineSet *clusterv1.MachineSet, exi
636637
if existingMachine != nil {
637638
desiredMachine.SetName(existingMachine.Name)
638639
desiredMachine.SetUID(existingMachine.UID)
640+
641+
// Preserve all existing finalizers (including foregroundDeletion finalizer).
642+
finalizers := existingMachine.Finalizers
643+
// Ensure MachineFinalizer is set.
644+
if !sets.New[string](finalizers...).Has(clusterv1.MachineFinalizer) {
645+
finalizers = append(finalizers, clusterv1.MachineFinalizer)
646+
}
647+
desiredMachine.Finalizers = finalizers
648+
639649
desiredMachine.Spec.Bootstrap.ConfigRef = existingMachine.Spec.Bootstrap.ConfigRef
640650
desiredMachine.Spec.InfrastructureRef = existingMachine.Spec.InfrastructureRef
641651
}
642-
643652
// Set the in-place mutable fields.
644653
// When we create a new Machine we will just create the Machine with those fields.
645654
// When we update an existing Machine will we update the fields on the existing Machine (in-place mutate).

internal/controllers/machineset/machineset_controller_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,8 @@ func TestComputeDesiredMachine(t *testing.T) {
16081608
existingMachine.UID = "abc-123-existing-machine-1"
16091609
existingMachine.Labels = nil
16101610
existingMachine.Annotations = nil
1611+
// Pre-existing finalizer should be preserved.
1612+
existingMachine.Finalizers = []string{"pre-existing-finalizer"}
16111613
existingMachine.Spec.InfrastructureRef = corev1.ObjectReference{
16121614
Kind: "GenericInfrastructureMachine",
16131615
Name: "infra-machine-1",
@@ -1625,6 +1627,8 @@ func TestComputeDesiredMachine(t *testing.T) {
16251627
expectedUpdatedMachine := skeletonMachine.DeepCopy()
16261628
expectedUpdatedMachine.Name = existingMachine.Name
16271629
expectedUpdatedMachine.UID = existingMachine.UID
1630+
// Pre-existing finalizer should be preserved.
1631+
expectedUpdatedMachine.Finalizers = []string{"pre-existing-finalizer", clusterv1.MachineFinalizer}
16281632
expectedUpdatedMachine.Spec.InfrastructureRef = *existingMachine.Spec.InfrastructureRef.DeepCopy()
16291633
expectedUpdatedMachine.Spec.Bootstrap.ConfigRef = existingMachine.Spec.Bootstrap.ConfigRef.DeepCopy()
16301634

test/e2e/md_scale.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
. "github.com/onsi/ginkgo/v2"
2626
. "github.com/onsi/gomega"
2727
corev1 "k8s.io/api/core/v1"
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2829
"k8s.io/utils/ptr"
2930

3031
"sigs.k8s.io/cluster-api/test/framework"
@@ -123,6 +124,17 @@ func MachineDeploymentScaleSpec(ctx context.Context, inputGetter func() MachineD
123124
Replicas: 1,
124125
WaitForMachineDeployments: input.E2EConfig.GetIntervals(specName, "wait-worker-nodes"),
125126
})
127+
128+
By("Deleting the MachineDeployment with foreground deletion")
129+
foreground := metav1.DeletePropagationForeground
130+
framework.DeleteAndWaitMachineDeployment(ctx, framework.DeleteAndWaitMachineDeploymentInput{
131+
ClusterProxy: input.BootstrapClusterProxy,
132+
Cluster: clusterResources.Cluster,
133+
MachineDeployment: clusterResources.MachineDeployments[0],
134+
WaitForMachineDeployments: input.E2EConfig.GetIntervals(specName, "wait-worker-nodes"),
135+
DeletePropagationPolicy: &foreground,
136+
})
137+
126138
By("PASSED!")
127139
})
128140

test/framework/machinedeployment_helpers.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
. "github.com/onsi/ginkgo/v2"
2626
. "github.com/onsi/gomega"
2727
"github.com/pkg/errors"
28+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2829
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3031
"k8s.io/apimachinery/pkg/util/sets"
@@ -448,6 +449,46 @@ func machineDeploymentOptions(deployment clusterv1.MachineDeployment) []client.L
448449
}
449450
}
450451

452+
// DeleteAndWaitMachineDeploymentInput is the input for DeleteAndWaitMachineDeployment.
453+
type DeleteAndWaitMachineDeploymentInput struct {
454+
ClusterProxy ClusterProxy
455+
Cluster *clusterv1.Cluster
456+
MachineDeployment *clusterv1.MachineDeployment
457+
WaitForMachineDeployments []interface{}
458+
DeletePropagationPolicy *metav1.DeletionPropagation
459+
}
460+
461+
// DeleteAndWaitMachineDeployment deletes MachineDeployment and waits until it is gone.
462+
func DeleteAndWaitMachineDeployment(ctx context.Context, input DeleteAndWaitMachineDeploymentInput) {
463+
Expect(ctx).NotTo(BeNil(), "ctx is required for DeleteAndWaitMachineDeployment")
464+
Expect(input.ClusterProxy).ToNot(BeNil(), "Invalid argument. input.ClusterProxy can't be nil when calling DeleteAndWaitMachineDeployment")
465+
Expect(input.Cluster).ToNot(BeNil(), "Invalid argument. input.Cluster can't be nil when calling DeleteAndWaitMachineDeployment")
466+
Expect(input.MachineDeployment).ToNot(BeNil(), "Invalid argument. input.MachineDeployment can't be nil when calling DeleteAndWaitMachineDeployment")
467+
468+
log.Logf("Deleting MachineDeployment %s", klog.KObj(input.MachineDeployment))
469+
Expect(input.ClusterProxy.GetClient().Delete(ctx, input.MachineDeployment, &client.DeleteOptions{PropagationPolicy: input.DeletePropagationPolicy})).To(Succeed())
470+
471+
log.Logf("Waiting for MD to be deleted")
472+
Eventually(func(g Gomega) {
473+
selectorMap, err := metav1.LabelSelectorAsMap(&input.MachineDeployment.Spec.Selector)
474+
g.Expect(err).ToNot(HaveOccurred())
475+
476+
machines := &clusterv1.MachineList{}
477+
err = input.ClusterProxy.GetClient().List(ctx, machines, client.InNamespace(input.Cluster.Namespace), client.MatchingLabels(selectorMap))
478+
g.Expect(err).ToNot(HaveOccurred())
479+
g.Expect(machines.Items).To(BeEmpty())
480+
481+
ms := &clusterv1.MachineSetList{}
482+
err = input.ClusterProxy.GetClient().List(ctx, ms, client.InNamespace(input.Cluster.Namespace), client.MatchingLabels(selectorMap))
483+
g.Expect(err).ToNot(HaveOccurred())
484+
g.Expect(ms.Items).To(BeEmpty())
485+
486+
md := &clusterv1.MachineDeployment{}
487+
err = input.ClusterProxy.GetClient().Get(ctx, client.ObjectKeyFromObject(input.MachineDeployment), md)
488+
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
489+
}, input.WaitForMachineDeployments...).Should(Succeed(), "Timed out waiting for Machine Deployment deletion")
490+
}
491+
451492
// ScaleAndWaitMachineDeploymentInput is the input for ScaleAndWaitMachineDeployment.
452493
type ScaleAndWaitMachineDeploymentInput struct {
453494
ClusterProxy ClusterProxy

0 commit comments

Comments
 (0)