Skip to content

Commit ed98c60

Browse files
authored
Merge pull request #5761 from AndiDog/machine-pool-machine-deletion
🐛 Only try to delete AWSMachine bootstrap data for non-machine pool machines
2 parents f6c53bb + 89f1eab commit ed98c60

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

controllers/awsmachine_controller.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,11 @@ func (r *AWSMachineReconciler) reconcileDelete(ctx context.Context, machineScope
306306

307307
ec2Service := r.getEC2Service(ec2Scope)
308308

309-
if err := r.deleteBootstrapData(ctx, machineScope, clusterScope, objectStoreScope); err != nil {
310-
machineScope.Error(err, "unable to delete machine")
311-
return ctrl.Result{}, err
309+
if !machineScope.IsMachinePoolMachine() {
310+
if err := r.deleteBootstrapData(ctx, machineScope, clusterScope, objectStoreScope); err != nil {
311+
machineScope.Error(err, "unable to delete AWSMachine bootstrap data")
312+
return ctrl.Result{}, err
313+
}
312314
}
313315

314316
instance, err := r.findInstance(machineScope, ec2Service)

controllers/awsmachine_controller_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"sigs.k8s.io/controller-runtime/pkg/client"
3737

3838
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
39+
expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
3940
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud"
4041
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
4142
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
@@ -428,6 +429,105 @@ func TestAWSMachineReconcilerIntegrationTests(t *testing.T) {
428429
})
429430
g.Expect(ms.AWSMachine.Finalizers).ShouldNot(ContainElement(infrav1.MachineFinalizer))
430431
})
432+
t.Run("Should successfully continue AWSMachinePool machine deletion if spec.cloudInit=={}", func(t *testing.T) {
433+
g := NewWithT(t)
434+
mockCtrl = gomock.NewController(t)
435+
ec2Mock := mocks.NewMockEC2API(mockCtrl)
436+
437+
// Simulate terminated instance
438+
ec2Mock.EXPECT().DescribeInstances(context.TODO(), gomock.Eq(&ec2.DescribeInstancesInput{
439+
InstanceIds: []string{"myMachine"},
440+
})).Return(&ec2.DescribeInstancesOutput{
441+
Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{Placement: &ec2types.Placement{AvailabilityZone: aws.String("us-east-1a")}, InstanceId: aws.String("i-mymachine"), State: &ec2types.InstanceState{Name: ec2types.InstanceStateNameTerminated, Code: aws.Int32(48)}}}}},
442+
}, nil)
443+
444+
ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("integ-test-%s", util.RandomString(5)))
445+
g.Expect(err).To(BeNil())
446+
447+
setup(t, g)
448+
awsMachine := &infrav1.AWSMachine{
449+
ObjectMeta: metav1.ObjectMeta{
450+
Namespace: ns.Name,
451+
GenerateName: "mypool-",
452+
Labels: map[string]string{
453+
clusterv1.MachinePoolNameLabel: "mypool",
454+
clusterv1.ClusterNameLabel: "test-cluster",
455+
},
456+
OwnerReferences: []metav1.OwnerReference{
457+
{
458+
APIVersion: expinfrav1.GroupVersion.String(),
459+
Kind: "AWSMachinePool",
460+
Name: "mypool",
461+
BlockOwnerDeletion: ptr.To(true),
462+
UID: "6d1e6238-045d-4297-8c7e-73df7a5cc998",
463+
},
464+
},
465+
},
466+
Spec: infrav1.AWSMachineSpec{
467+
ProviderID: aws.String(providerID),
468+
InstanceID: aws.String("i-mymachine"),
469+
AMI: infrav1.AMIReference{
470+
ID: aws.String("ami-alsodoesntmatter"),
471+
},
472+
InstanceType: "foo",
473+
PublicIP: aws.Bool(false),
474+
SSHKeyName: aws.String("foo"),
475+
InstanceMetadataOptions: &infrav1.InstanceMetadataOptions{
476+
// ...
477+
},
478+
IAMInstanceProfile: "foo",
479+
AdditionalSecurityGroups: nil,
480+
Subnet: &infrav1.AWSResourceReference{ID: aws.String("sub-doesntmatter")},
481+
RootVolume: &infrav1.Volume{
482+
Size: 8,
483+
// ...
484+
},
485+
NonRootVolumes: nil,
486+
NetworkInterfaces: []string{"eni-foobar"},
487+
CloudInit: infrav1.CloudInit{},
488+
SpotMarketOptions: nil,
489+
Tenancy: "host",
490+
},
491+
}
492+
createAWSMachine(g, awsMachine)
493+
494+
defer teardown(g)
495+
defer t.Cleanup(func() {
496+
g.Expect(testEnv.Cleanup(ctx, awsMachine, ns)).To(Succeed())
497+
})
498+
499+
cs, err := getClusterScope(infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{Name: "test"}})
500+
g.Expect(err).To(BeNil())
501+
cs.Cluster = &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}}
502+
ms, err := getMachineScope(cs, awsMachine)
503+
g.Expect(err).To(BeNil())
504+
505+
// This case happened in a live object. It didn't get defaulted and actually was
506+
// a machine pool AWSMachine managed via Ignition. The AWSMachine controller must
507+
// not try to use this field or delete bootstrap data, as the object is managed
508+
// by the AWSMachinePool controller.
509+
ms.AWSMachine.Spec.CloudInit.SecureSecretsBackend = ""
510+
now := metav1.Now()
511+
ms.AWSMachine.DeletionTimestamp = &now
512+
ms.AWSMachine.Status.InstanceState = &infrav1.InstanceStateTerminated
513+
514+
// Machine pool controlled Machine/AWSMachine
515+
if ms.Machine.Labels == nil {
516+
ms.Machine.Labels = map[string]string{}
517+
}
518+
ms.Machine.Labels[clusterv1.MachinePoolNameLabel] = ms.AWSMachine.Labels[clusterv1.MachinePoolNameLabel]
519+
ms.Machine.Labels[clusterv1.ClusterNameLabel] = ms.AWSMachine.Labels[clusterv1.ClusterNameLabel]
520+
521+
ec2Svc := ec2Service.NewService(cs)
522+
ec2Svc.EC2Client = ec2Mock
523+
reconciler.ec2ServiceFactory = func(scope scope.EC2Scope) services.EC2Interface {
524+
return ec2Svc
525+
}
526+
527+
_, err = reconciler.reconcileDelete(context.TODO(), ms, cs, cs, cs, cs)
528+
g.Expect(err).To(BeNil())
529+
g.Expect(ms.AWSMachine.Finalizers).ShouldNot(ContainElement(infrav1.MachineFinalizer))
530+
})
431531
}
432532

433533
func getMachineScope(cs *scope.ClusterScope, awsMachine *infrav1.AWSMachine) (*scope.MachineScope, error) {

0 commit comments

Comments
 (0)