Skip to content

Commit 33c5b6d

Browse files
committed
fix: non control plane node deletion when the cluster has no control plane machines
1 parent 2a7d61d commit 33c5b6d

File tree

3 files changed

+118
-68
lines changed

3 files changed

+118
-68
lines changed

internal/controllers/machine/machine_controller.go

+16-13
Original file line numberDiff line numberDiff line change
@@ -784,21 +784,24 @@ func (r *Reconciler) isDeleteNodeAllowed(ctx context.Context, cluster *clusterv1
784784
}
785785
}
786786

787-
// Get all of the active machines that belong to this cluster.
788-
machines, err := collections.GetFilteredMachinesForCluster(ctx, r.Client, cluster, collections.ActiveMachines)
789-
if err != nil {
790-
return err
791-
}
787+
if util.IsControlPlaneMachine(machine) {
788+
// Get all the machines that belong to this cluster.
789+
machines, err := collections.GetFilteredMachinesForCluster(ctx, r.Client, cluster)
790+
if err != nil {
791+
return err
792+
}
792793

793-
// Whether or not it is okay to delete the NodeRef depends on the
794-
// number of remaining control plane members and whether or not this
795-
// machine is one of them.
796-
numControlPlaneMachines := len(machines.Filter(collections.ControlPlaneMachines(cluster.Name)))
797-
if numControlPlaneMachines == 0 {
798-
// Do not delete the NodeRef if there are no remaining members of
799-
// the control plane.
800-
return errNoControlPlaneNodes
794+
// Whether or not it is okay to delete the NodeRef depends on the
795+
// number of remaining control plane members and whether or not this
796+
// machine is one of them.
797+
numOfControlPlaneMachines := len(machines.Filter(collections.ControlPlaneMachines(cluster.Name)))
798+
if numOfControlPlaneMachines == 1 {
799+
// Do not delete the NodeRef as this is the last remaining member of
800+
// the control plane.
801+
return errLastControlPlaneNode
802+
}
801803
}
804+
802805
// Otherwise it is okay to delete the NodeRef.
803806
return nil
804807
}

internal/controllers/machine/machine_controller_test.go

+101-55
Original file line numberDiff line numberDiff line change
@@ -2529,9 +2529,53 @@ func nodeNameIndex(o client.Object) []string {
25292529
func TestIsDeleteNodeAllowed(t *testing.T) {
25302530
deletionts := metav1.Now()
25312531

2532+
cp1 := &clusterv1.Machine{
2533+
ObjectMeta: metav1.ObjectMeta{
2534+
Name: "cp1",
2535+
Namespace: metav1.NamespaceDefault,
2536+
Labels: map[string]string{
2537+
clusterv1.ClusterNameLabel: "test-cluster",
2538+
clusterv1.MachineControlPlaneLabel: "",
2539+
},
2540+
Finalizers: []string{clusterv1.MachineFinalizer},
2541+
},
2542+
Spec: clusterv1.MachineSpec{
2543+
ClusterName: "test-cluster",
2544+
InfrastructureRef: corev1.ObjectReference{},
2545+
Bootstrap: clusterv1.Bootstrap{DataSecretName: ptr.To("data")},
2546+
},
2547+
Status: clusterv1.MachineStatus{
2548+
NodeRef: &corev1.ObjectReference{
2549+
Name: "test1",
2550+
},
2551+
},
2552+
}
2553+
cp2 := &clusterv1.Machine{
2554+
ObjectMeta: metav1.ObjectMeta{
2555+
Name: "cp2",
2556+
Namespace: metav1.NamespaceDefault,
2557+
Labels: map[string]string{
2558+
clusterv1.ClusterNameLabel: "test-cluster",
2559+
clusterv1.MachineControlPlaneLabel: "",
2560+
},
2561+
Finalizers: []string{clusterv1.MachineFinalizer},
2562+
},
2563+
Spec: clusterv1.MachineSpec{
2564+
ClusterName: "test-cluster",
2565+
InfrastructureRef: corev1.ObjectReference{},
2566+
Bootstrap: clusterv1.Bootstrap{DataSecretName: ptr.To("data")},
2567+
},
2568+
Status: clusterv1.MachineStatus{
2569+
NodeRef: &corev1.ObjectReference{
2570+
Name: "test2",
2571+
},
2572+
},
2573+
}
2574+
25322575
testCases := []struct {
25332576
name string
25342577
cluster *clusterv1.Cluster
2578+
extraMachines []*clusterv1.Machine
25352579
machine *clusterv1.Machine
25362580
expectedError error
25372581
}{
@@ -2559,10 +2603,13 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
25592603
},
25602604
Status: clusterv1.MachineStatus{},
25612605
},
2606+
extraMachines: nil,
25622607
expectedError: errNilNodeRef,
25632608
},
25642609
{
2565-
name: "no control plane members",
2610+
// This situation can happen when the control plane is not implemented via Cluster API,
2611+
// so for Cluster API the control plane machine members count is zero in this case.
2612+
name: "no control plane members, deleting a worker",
25662613
cluster: &clusterv1.Cluster{
25672614
ObjectMeta: metav1.ObjectMeta{
25682615
Name: "test-cluster",
@@ -2576,7 +2623,8 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
25762623
Labels: map[string]string{
25772624
clusterv1.ClusterNameLabel: "test-cluster",
25782625
},
2579-
Finalizers: []string{clusterv1.MachineFinalizer},
2626+
Finalizers: []string{clusterv1.MachineFinalizer},
2627+
DeletionTimestamp: &metav1.Time{Time: time.Now().UTC()},
25802628
},
25812629
Spec: clusterv1.MachineSpec{
25822630
ClusterName: "test-cluster",
@@ -2589,10 +2637,11 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
25892637
},
25902638
},
25912639
},
2592-
expectedError: errNoControlPlaneNodes,
2640+
extraMachines: nil,
2641+
expectedError: nil,
25932642
},
25942643
{
2595-
name: "is last control plane member",
2644+
name: "is last control plane member, trying to delete it",
25962645
cluster: &clusterv1.Cluster{
25972646
ObjectMeta: metav1.ObjectMeta{
25982647
Name: "test-cluster",
@@ -2621,7 +2670,40 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
26212670
},
26222671
},
26232672
},
2624-
expectedError: errNoControlPlaneNodes,
2673+
extraMachines: nil,
2674+
expectedError: errLastControlPlaneNode,
2675+
},
2676+
{
2677+
name: "only one control plane member, trying to delete a worker",
2678+
cluster: &clusterv1.Cluster{
2679+
ObjectMeta: metav1.ObjectMeta{
2680+
Name: "test-cluster",
2681+
Namespace: metav1.NamespaceDefault,
2682+
},
2683+
},
2684+
machine: &clusterv1.Machine{
2685+
ObjectMeta: metav1.ObjectMeta{
2686+
Name: "created",
2687+
Namespace: metav1.NamespaceDefault,
2688+
Labels: map[string]string{
2689+
clusterv1.ClusterNameLabel: "test-cluster",
2690+
},
2691+
Finalizers: []string{clusterv1.MachineFinalizer},
2692+
DeletionTimestamp: &metav1.Time{Time: time.Now().UTC()},
2693+
},
2694+
Spec: clusterv1.MachineSpec{
2695+
ClusterName: "test-cluster",
2696+
InfrastructureRef: corev1.ObjectReference{},
2697+
Bootstrap: clusterv1.Bootstrap{DataSecretName: ptr.To("data")},
2698+
},
2699+
Status: clusterv1.MachineStatus{
2700+
NodeRef: &corev1.ObjectReference{
2701+
Name: "test",
2702+
},
2703+
},
2704+
},
2705+
extraMachines: nil,
2706+
expectedError: nil,
26252707
},
26262708
{
26272709
name: "has nodeRef and control plane is healthy",
@@ -2651,6 +2733,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
26512733
},
26522734
},
26532735
},
2736+
extraMachines: []*clusterv1.Machine{cp1, cp2},
26542737
expectedError: nil,
26552738
},
26562739
{
@@ -2664,6 +2747,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
26642747
},
26652748
},
26662749
machine: &clusterv1.Machine{},
2750+
extraMachines: nil,
26672751
expectedError: errClusterIsBeingDeleted,
26682752
},
26692753
{
@@ -2702,6 +2786,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
27022786
},
27032787
},
27042788
},
2789+
extraMachines: []*clusterv1.Machine{cp1, cp2},
27052790
expectedError: nil,
27062791
},
27072792
{
@@ -2740,6 +2825,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
27402825
},
27412826
},
27422827
},
2828+
extraMachines: nil,
27432829
expectedError: errControlPlaneIsBeingDeleted,
27442830
},
27452831
{
@@ -2778,6 +2864,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
27782864
},
27792865
},
27802866
},
2867+
extraMachines: nil,
27812868
expectedError: errControlPlaneIsBeingDeleted,
27822869
},
27832870
}
@@ -2822,61 +2909,19 @@ func TestIsDeleteNodeAllowed(t *testing.T) {
28222909
t.Run(tc.name, func(t *testing.T) {
28232910
g := NewWithT(t)
28242911

2825-
m1 := &clusterv1.Machine{
2826-
ObjectMeta: metav1.ObjectMeta{
2827-
Name: "cp1",
2828-
Namespace: metav1.NamespaceDefault,
2829-
Labels: map[string]string{
2830-
clusterv1.ClusterNameLabel: "test-cluster",
2831-
},
2832-
Finalizers: []string{clusterv1.MachineFinalizer},
2833-
},
2834-
Spec: clusterv1.MachineSpec{
2835-
ClusterName: "test-cluster",
2836-
InfrastructureRef: corev1.ObjectReference{},
2837-
Bootstrap: clusterv1.Bootstrap{DataSecretName: ptr.To("data")},
2838-
},
2839-
Status: clusterv1.MachineStatus{
2840-
NodeRef: &corev1.ObjectReference{
2841-
Name: "test1",
2842-
},
2843-
},
2844-
}
2845-
m2 := &clusterv1.Machine{
2846-
ObjectMeta: metav1.ObjectMeta{
2847-
Name: "cp2",
2848-
Namespace: metav1.NamespaceDefault,
2849-
Labels: map[string]string{
2850-
clusterv1.ClusterNameLabel: "test-cluster",
2851-
},
2852-
Finalizers: []string{clusterv1.MachineFinalizer},
2853-
},
2854-
Spec: clusterv1.MachineSpec{
2855-
ClusterName: "test-cluster",
2856-
InfrastructureRef: corev1.ObjectReference{},
2857-
Bootstrap: clusterv1.Bootstrap{DataSecretName: ptr.To("data")},
2858-
},
2859-
Status: clusterv1.MachineStatus{
2860-
NodeRef: &corev1.ObjectReference{
2861-
Name: "test2",
2862-
},
2863-
},
2864-
}
2865-
// For isDeleteNodeAllowed to be true we assume a healthy control plane.
2866-
if tc.expectedError == nil {
2867-
m1.Labels[clusterv1.MachineControlPlaneLabel] = ""
2868-
m2.Labels[clusterv1.MachineControlPlaneLabel] = ""
2869-
}
2870-
2871-
c := fake.NewClientBuilder().WithObjects(
2912+
objects := []client.Object{
28722913
tc.cluster,
28732914
tc.machine,
2874-
m1,
2875-
m2,
28762915
emp,
28772916
mcpBeingDeleted,
28782917
empBeingDeleted,
2879-
).Build()
2918+
}
2919+
2920+
for _, e := range tc.extraMachines {
2921+
objects = append(objects, e)
2922+
}
2923+
2924+
c := fake.NewClientBuilder().WithObjects(objects...).Build()
28802925
mr := &Reconciler{
28812926
Client: c,
28822927
}
@@ -3197,6 +3242,7 @@ func TestNodeDeletion(t *testing.T) {
31973242
Namespace: metav1.NamespaceDefault,
31983243
Labels: map[string]string{
31993244
clusterv1.MachineControlPlaneLabel: "",
3245+
clusterv1.ClusterNameLabel: "test-cluster",
32003246
},
32013247
Annotations: map[string]string{
32023248
"machine.cluster.x-k8s.io/exclude-node-draining": "",

util/collections/machine_filters.go

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func ControlPlaneMachines(clusterName string) func(machine *clusterv1.Machine) b
118118
if machine == nil {
119119
return false
120120
}
121+
121122
return selector.Matches(labels.Set(machine.Labels))
122123
}
123124
}

0 commit comments

Comments
 (0)