Skip to content

Commit ba9ccd9

Browse files
authored
fix: cleanup AWS CloudFormation stack in Test environment (kubernetes-sigs#4059)
* Cleanup AWS CloudFormation stack in Test environment * add security group name to the output
1 parent 69c97b0 commit ba9ccd9

File tree

4 files changed

+29
-10
lines changed

4 files changed

+29
-10
lines changed

cmd/clusterawsadm/cloudformation/service/service.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewService(i cloudformationiface.CloudFormationAPI) *Service {
4949
}
5050

5151
// ReconcileBootstrapStack creates or updates bootstrap CloudFormation.
52-
func (s *Service) ReconcileBootstrapStack(stackName string, t go_cfn.Template, tags map[string]string) error {
52+
func (s *Service) ReconcileBootstrapStack(stackName string, t go_cfn.Template, tags map[string]string, deleteOnFailure bool) error {
5353
yaml, err := t.YAML()
5454
processedYaml := string(yaml)
5555
if err != nil {
@@ -64,7 +64,7 @@ func (s *Service) ReconcileBootstrapStack(stackName string, t go_cfn.Template, t
6464
})
6565
}
6666
//nolint:nestif
67-
if err := s.createStack(stackName, processedYaml, stackTags); err != nil {
67+
if err := s.createStack(stackName, processedYaml, stackTags, deleteOnFailure); err != nil {
6868
if code, _ := awserrors.Code(errors.Cause(err)); code == "AlreadyExistsException" {
6969
klog.Infof("AWS Cloudformation stack %q already exists, updating", klog.KRef("", stackName))
7070
updateErr := s.updateStack(stackName, processedYaml, stackTags)
@@ -82,13 +82,16 @@ func (s *Service) ReconcileBootstrapStack(stackName string, t go_cfn.Template, t
8282
return nil
8383
}
8484

85-
func (s *Service) createStack(stackName, yaml string, tags []*cfn.Tag) error {
85+
func (s *Service) createStack(stackName, yaml string, tags []*cfn.Tag, deleteOnFailure bool) error {
8686
input := &cfn.CreateStackInput{
8787
Capabilities: aws.StringSlice([]string{cfn.CapabilityCapabilityIam, cfn.CapabilityCapabilityNamedIam}),
8888
TemplateBody: aws.String(yaml),
8989
StackName: aws.String(stackName),
9090
Tags: tags,
9191
}
92+
if deleteOnFailure {
93+
input.OnFailure = aws.String(cfn.OnFailureDelete)
94+
}
9295
klog.V(2).Infof("creating AWS CloudFormation stack %q", stackName)
9396
if _, err := s.CFN.CreateStack(input); err != nil {
9497
return errors.Wrap(err, "failed to create AWS CloudFormation stack")

cmd/clusterawsadm/cmd/bootstrap/iam/cloudformation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func createCloudFormationStackCmd() *cobra.Command {
109109

110110
cfnSvc := cloudformation.NewService(cfn.New(sess))
111111

112-
err = cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *t.RenderCloudFormation(), t.Spec.StackTags)
112+
err = cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *t.RenderCloudFormation(), t.Spec.StackTags, false)
113113
if err != nil {
114114
fmt.Printf("Error: %v\n", err)
115115
return err

pkg/cloud/services/securitygroup/securitygroups.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,8 @@ func (s *Service) deleteSecurityGroup(sg *infrav1.SecurityGroup, typ string) err
305305
}
306306

307307
if _, err := s.EC2Client.DeleteSecurityGroup(input); awserrors.IsIgnorableSecurityGroupError(err) != nil {
308-
record.Warnf(s.scope.InfraCluster(), "FailedDeleteSecurityGroup", "Failed to delete %s SecurityGroup %q: %v", typ, sg.ID, err)
309-
return errors.Wrapf(err, "failed to delete security group %q", sg.ID)
308+
record.Warnf(s.scope.InfraCluster(), "FailedDeleteSecurityGroup", "Failed to delete %s SecurityGroup %q with name %q: %v", typ, sg.ID, sg.Name, err)
309+
return errors.Wrapf(err, "failed to delete security group %q with name %q", sg.ID, sg.Name)
310310
}
311311

312312
record.Eventf(s.scope.InfraCluster(), "SuccessfulDeleteSecurityGroup", "Deleted %s SecurityGroup %q", typ, sg.ID)

test/e2e/shared/aws.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,19 +410,24 @@ func createCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Temp
410410
cfnSvc := cloudformation.NewService(CFN)
411411

412412
Eventually(func() bool {
413-
err := cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *renderCustomCloudFormation(t), tags)
413+
err := cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *renderCustomCloudFormation(t), tags, true)
414414
output, err1 := CFN.DescribeStackEvents(&cfn.DescribeStackEventsInput{StackName: aws.String(t.Spec.StackName), NextToken: aws.String("1")})
415+
By("========= Stack Event Output Begin =========")
415416
for _, event := range output.StackEvents {
416417
By(fmt.Sprintf("Event details for %s : Resource: %s, Status: %s, Reason: %s", aws.StringValue(event.LogicalResourceId), aws.StringValue(event.ResourceType), aws.StringValue(event.ResourceStatus), aws.StringValue(event.ResourceStatusReason)))
417418
}
419+
By("========= Stack Event Output End =========")
418420
return err == nil && err1 == nil
419421
}, 2*time.Minute).Should(Equal(true))
422+
420423
stack, err := CFN.DescribeStacks(&cfn.DescribeStacksInput{StackName: aws.String(t.Spec.StackName)})
421424
if err == nil && len(stack.Stacks) > 0 {
422425
deleteMultitenancyRoles(prov)
423426
if aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackFailed ||
424427
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackComplete ||
425-
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackInProgress {
428+
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackInProgress ||
429+
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusCreateFailed ||
430+
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusDeleteFailed {
426431
// If cloudformation stack creation fails due to resources that already exist, stack stays in rollback status and must be manually deleted.
427432
// Delete resources that failed because they already exists.
428433
deleteResourcesInCloudFormation(prov, t)
@@ -445,17 +450,23 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra
445450
iamSvc := iam.New(prov)
446451
temp := *renderCustomCloudFormation(t)
447452
for _, val := range temp.Resources {
453+
By(fmt.Sprintf("deleting the following resource: %s", val.AWSCloudFormationType()))
448454
tayp := val.AWSCloudFormationType()
449455
if tayp == configservice.ResourceTypeAwsIamRole {
450456
role := val.(*cfn_iam.Role)
457+
By(fmt.Sprintf("cleanup for role with name '%s'", role.RoleName))
451458
Eventually(func(gomega Gomega) bool {
452459
_, err := iamSvc.DeleteRole(&iam.DeleteRoleInput{RoleName: aws.String(role.RoleName)})
453460
return awserrors.IsNotFound(err) || err == nil
454461
}, 5*time.Minute, 5*time.Second).Should(BeTrue())
455462
}
456463
if val.AWSCloudFormationType() == "AWS::IAM::InstanceProfile" {
457464
profile := val.(*cfn_iam.InstanceProfile)
458-
_, _ = iamSvc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{InstanceProfileName: aws.String(profile.InstanceProfileName)})
465+
By(fmt.Sprintf("cleanup for profile with name '%s'", profile.InstanceProfileName))
466+
Eventually(func(gomega Gomega) bool {
467+
_, err := iamSvc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{InstanceProfileName: aws.String(profile.InstanceProfileName)})
468+
return awserrors.IsNotFound(err) || err == nil
469+
}, 5*time.Minute, 5*time.Second).Should(BeTrue())
459470
}
460471
if val.AWSCloudFormationType() == "AWS::IAM::ManagedPolicy" {
461472
policy := val.(*cfn_iam.ManagedPolicy)
@@ -464,7 +475,12 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra
464475
if len(policies.Policies) > 0 {
465476
for _, p := range policies.Policies {
466477
if aws.StringValue(p.PolicyName) == policy.ManagedPolicyName {
467-
_, _ = iamSvc.DeletePolicy(&iam.DeletePolicyInput{PolicyArn: p.Arn})
478+
By(fmt.Sprintf("cleanup for policy '%s'", p.String()))
479+
Eventually(func(gomega Gomega) bool {
480+
_, err := iamSvc.DeletePolicy(&iam.DeletePolicyInput{PolicyArn: p.Arn})
481+
return awserrors.IsNotFound(err) || err == nil
482+
}, 5*time.Minute, 5*time.Second).Should(BeTrue())
483+
// TODO: why is there a break here? Don't we want to clean up everything?
468484
break
469485
}
470486
}

0 commit comments

Comments
 (0)