Skip to content

Commit 492822d

Browse files
authored
Merge pull request #4076 from Skarlso/always-clean-roles-and-resources
chore(ref): always clean roles and resources on cf stack failure
2 parents 66491f6 + dade397 commit 492822d

File tree

3 files changed

+12
-26
lines changed

3 files changed

+12
-26
lines changed

cmd/clusterawsadm/cloudformation/service/service.go

Lines changed: 5 additions & 8 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, deleteOnFailure bool) error {
52+
func (s *Service) ReconcileBootstrapStack(stackName string, t go_cfn.Template, tags map[string]string) 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, deleteOnFailure); err != nil {
67+
if err := s.createStack(stackName, processedYaml, stackTags); 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)
@@ -97,29 +97,26 @@ func (s *Service) ReconcileBootstrapNoUpdate(stackName string, t go_cfn.Template
9797
})
9898
}
9999
//nolint:nestif
100-
if err := s.createStack(stackName, processedYaml, stackTags, true); err != nil {
100+
if err := s.createStack(stackName, processedYaml, stackTags); err != nil {
101101
if code, _ := awserrors.Code(errors.Cause(err)); code == "AlreadyExistsException" {
102102
desInput := &cfn.DescribeStacksInput{StackName: aws.String(stackName)}
103103
if err := s.CFN.WaitUntilStackCreateComplete(desInput); err != nil {
104104
return errors.Wrap(err, "failed to wait for AWS CloudFormation stack to be CreateComplete")
105105
}
106106
return nil
107107
}
108-
return err
108+
return fmt.Errorf("failed to create CF stack: %w", err)
109109
}
110110
return nil
111111
}
112112

113-
func (s *Service) createStack(stackName, yaml string, tags []*cfn.Tag, deleteOnFailure bool) error {
113+
func (s *Service) createStack(stackName, yaml string, tags []*cfn.Tag) error {
114114
input := &cfn.CreateStackInput{
115115
Capabilities: aws.StringSlice([]string{cfn.CapabilityCapabilityIam, cfn.CapabilityCapabilityNamedIam}),
116116
TemplateBody: aws.String(yaml),
117117
StackName: aws.String(stackName),
118118
Tags: tags,
119119
}
120-
if deleteOnFailure {
121-
input.OnFailure = aws.String(cfn.OnFailureDelete)
122-
}
123120
klog.V(2).Infof("creating AWS CloudFormation stack %q", stackName)
124121
if _, err := s.CFN.CreateStack(input); err != nil {
125122
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, false)
112+
err = cfnSvc.ReconcileBootstrapStack(t.Spec.StackName, *t.RenderCloudFormation(), t.Spec.StackTags)
113113
if err != nil {
114114
fmt.Printf("Error: %v\n", err)
115115
return err

test/e2e/shared/aws.go

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -410,30 +410,19 @@ func createCloudFormationStack(prov client.ConfigProvider, t *cfn_bootstrap.Temp
410410
// CloudFormation stack will clean up on a failure, we don't need an Eventually here.
411411
// The `create` already does a WaitUntilStackCreateComplete.
412412
cfnSvc := cloudformation.NewService(cfnClient)
413-
err := cfnSvc.ReconcileBootstrapNoUpdate(t.Spec.StackName, *renderCustomCloudFormation(t), tags)
414-
if err != nil {
413+
if err := cfnSvc.ReconcileBootstrapNoUpdate(t.Spec.StackName, *renderCustomCloudFormation(t), tags); err != nil {
415414
By(fmt.Sprintf("Error reconciling Cloud formation stack %v", err))
416415
spewCloudFormationResources(cfnClient, t)
417416

418-
stack, derr := cfnClient.DescribeStacks(&cfn.DescribeStacksInput{StackName: aws.String(t.Spec.StackName)})
419-
if derr == nil && len(stack.Stacks) > 0 {
420-
if aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackFailed ||
421-
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackComplete ||
422-
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusRollbackInProgress ||
423-
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusCreateFailed ||
424-
aws.StringValue(stack.Stacks[0].StackStatus) == cfn.StackStatusDeleteFailed {
425-
// If cloudformation stack creation fails due to resources that already exist, stack stays in rollback status and must be manually deleted.
426-
// Delete resources that failed because they already exists.
427-
By("Starting cleanup process as the stack failed to create")
428-
deleteMultitenancyRoles(prov)
429-
deleteResourcesInCloudFormation(prov, t)
430-
}
431-
}
417+
// always clean up on a failure because we could leak these resources and the next cloud formation create would
418+
// fail with the same problem.
419+
deleteMultitenancyRoles(prov)
420+
deleteResourcesInCloudFormation(prov, t)
432421
return err
433422
}
434423

435424
spewCloudFormationResources(cfnClient, t)
436-
return err
425+
return nil
437426
}
438427

439428
func spewCloudFormationResources(cfnClient *cfn.CloudFormation, t *cfn_bootstrap.Template) {

0 commit comments

Comments
 (0)