Skip to content

Commit 5b550db

Browse files
Bajzathddoktoric
authored andcommitted
CB-23235 Disable delete protection of ELBs before delete
1 parent bbb8fb7 commit 5b550db

2 files changed

Lines changed: 50 additions & 11 deletions

File tree

aws/aws.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -568,9 +568,14 @@ func deleteNativeStack(ec2Client ec2Client, elbClient elbClient, cloudWatchClien
568568
go func(loadBalancerArn string) {
569569
defer wg.Done()
570570

571-
err := deleteLoadBalancer(elbClient, stack.ID, loadBalancerArn, region)
571+
elbExists, err := disableElbDeleteProtection(elbClient, stack.ID, loadBalancerArn, region)
572572
if err != nil {
573573
errChan <- err
574+
} else if elbExists {
575+
err := deleteLoadBalancer(elbClient, stack.ID, loadBalancerArn, region)
576+
if err != nil {
577+
errChan <- err
578+
}
574579
}
575580
}(lb)
576581
}
@@ -643,15 +648,23 @@ func deleteCfStack(cfClient cfClient, rdsClient rdsClient, ec2Client ec2Client,
643648
case "AWS::RDS::DBInstance":
644649
if *stackResource.ResourceStatus != cloudformation.ResourceStatusDeleteComplete {
645650
var dbExists bool
646-
dbExists, resourceErr = disableDeleteProtection(rdsClient, stack.Name, *stackResource.PhysicalResourceId, region)
651+
dbExists, resourceErr = disableDbDeleteProtection(rdsClient, stack.Name, *stackResource.PhysicalResourceId, region)
647652
if !dbExists {
648653
retainResources = append(retainResources, stackResource.LogicalResourceId)
649654
}
650655
}
651656
case "AWS::EC2::VPC":
652657
resourceErr = deleteVpcWithDependencies(ec2Client, stack.Name, *stackResource.PhysicalResourceId, region)
653658
case "AWS::ElasticLoadBalancingV2::LoadBalancer":
654-
resourceErr = deleteLoadBalancer(elbClient, stack.Name, *stackResource.PhysicalResourceId, region)
659+
if *stackResource.ResourceStatus != cloudformation.ResourceStatusDeleteComplete {
660+
var elbExists bool
661+
elbExists, resourceErr = disableElbDeleteProtection(elbClient, stack.Name, *stackResource.PhysicalResourceId, region)
662+
if !elbExists {
663+
retainResources = append(retainResources, stackResource.LogicalResourceId)
664+
} else if resourceErr == nil {
665+
resourceErr = deleteLoadBalancer(elbClient, stack.Name, *stackResource.PhysicalResourceId, region)
666+
}
667+
}
655668
}
656669

657670
if resourceErr != nil {
@@ -685,22 +698,20 @@ func deleteCfStack(cfClient cfClient, rdsClient rdsClient, ec2Client ec2Client,
685698
return nil
686699
}
687700

688-
func disableDeleteProtection(rdsClient rdsClient, stackName string, dbInstanceId string, region string) (bool, error) {
701+
func disableDbDeleteProtection(rdsClient rdsClient, stackName string, dbInstanceId string, region string) (dbExists bool, err error) {
689702
log.Infof("[AWS] Disabling DeletionProtection for DB instance: %s in stack: %s, region: %s", dbInstanceId, stackName, region)
690-
dbExists := true
691703

692-
_, err := rdsClient.ModifyDBInstance(&rds.ModifyDBInstanceInput{
704+
_, err = rdsClient.ModifyDBInstance(&rds.ModifyDBInstanceInput{
693705
DBInstanceIdentifier: &dbInstanceId,
694706
DeletionProtection: aws.Bool(false),
695707
})
696708
if err != nil {
697-
dbExists = false
709+
log.Errorf("[AWS] Failed to disable DeletionProtection on db instance: %s in stack: %s, err: %s", dbInstanceId, stackName, err)
698710
if strings.Contains(err.Error(), "DB instance not found") {
699-
return dbExists, nil
711+
return false, nil
700712
}
701-
log.Errorf("[AWS] Failed to disable DeletionProtection on db instance: %s in stack: %s, err: %s", dbInstanceId, stackName, err)
702713
}
703-
return dbExists, err
714+
return true, err
704715
}
705716

706717
/**
@@ -791,6 +802,25 @@ func deleteVpcWithDependencies(ec2Client ec2Client, stackName string, vpcId stri
791802
return nil
792803
}
793804

805+
func disableElbDeleteProtection(elbClient elbClient, stackName string, elbArn string, region string) (elbExists bool, err error) {
806+
log.Infof("[AWS] Disabling DeletionProtection for ELB: %s in stack: %s, region: %s", elbArn, stackName, region)
807+
808+
deletionProtection := &elb.LoadBalancerAttribute{}
809+
deletionProtection.SetKey("deletion_protection.enabled")
810+
deletionProtection.SetValue("false")
811+
_, err = elbClient.ModifyLoadBalancerAttributes(&elb.ModifyLoadBalancerAttributesInput{
812+
LoadBalancerArn: aws.String(elbArn),
813+
Attributes: []*elb.LoadBalancerAttribute{deletionProtection},
814+
})
815+
if err != nil {
816+
log.Errorf("[AWS] Failed to disable DeletionProtection on ELB: %s in stack: %s, err: %s", elbArn, stackName, err)
817+
if strings.Contains(err.Error(), "ELB not found") {
818+
return false, nil
819+
}
820+
}
821+
return true, err
822+
}
823+
794824
func deleteLoadBalancer(elbClient elbClient, stackName string, elbArn string, region string) error {
795825
log.Infof("[AWS] Deleting load balancer: %s in stack: %s, region: %s", elbArn, stackName, region)
796826

@@ -1008,6 +1038,7 @@ type elbClient interface {
10081038
DescribeLoadBalancers(input *elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error)
10091039
DescribeTags(input *elb.DescribeTagsInput) (*elb.DescribeTagsOutput, error)
10101040
DeleteLoadBalancer(input *elb.DeleteLoadBalancerInput) (*elb.DeleteLoadBalancerOutput, error)
1041+
ModifyLoadBalancerAttributes(input *elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error)
10111042
}
10121043

10131044
type cloudWatchClient interface {

aws/aws_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ func TestRemoveCfStack(t *testing.T) {
206206
assert.Equal(t, "DescribeSecurityGroups", <-operationChannel)
207207
assert.Equal(t, "DeleteSecurityGroup:custom-group-id", <-operationChannel)
208208
assert.Equal(t, "DeleteVpc", <-operationChannel)
209+
assert.Equal(t, "ModifyLoadBalancerAttributes:elb-arn", <-operationChannel)
209210
assert.Equal(t, "DeleteLoadBalancer:elb-arn", <-operationChannel)
210211
assert.Equal(t, "DeleteStack", <-operationChannel)
211212
assert.Equal(t, "WaitUntilStackDeleteComplete", <-operationChannel)
@@ -260,10 +261,12 @@ func TestRemoveNativeStack(t *testing.T) {
260261
asyncOperations = append(asyncOperations, op)
261262
}
262263

263-
assert.Equal(t, 6, len(asyncOperations))
264+
assert.Equal(t, 8, len(asyncOperations))
264265
assert.Contains(t, asyncOperations, "DeleteVolume:vol")
265266
assert.Contains(t, asyncOperations, "DeleteSecurityGroup:sg")
267+
assert.Contains(t, asyncOperations, "ModifyLoadBalancerAttributes:lb-1")
266268
assert.Contains(t, asyncOperations, "DeleteLoadBalancer:lb-1")
269+
assert.Contains(t, asyncOperations, "ModifyLoadBalancerAttributes:lb-2")
267270
assert.Contains(t, asyncOperations, "DeleteLoadBalancer:lb-2")
268271
assert.Contains(t, asyncOperations, "ReleaseAddress:ip")
269272
assert.Contains(t, asyncOperations, "DeleteAlarms:alarm")
@@ -640,6 +643,11 @@ func (t mockElbClient) DeleteLoadBalancer(input *elb.DeleteLoadBalancerInput) (*
640643
return nil, nil
641644
}
642645

646+
func (t mockElbClient) ModifyLoadBalancerAttributes(input *elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error) {
647+
t.operationChannel <- "ModifyLoadBalancerAttributes:" + *input.LoadBalancerArn
648+
return nil, nil
649+
}
650+
643651
type mockCwClient struct {
644652
operationChannel chan (string)
645653
}

0 commit comments

Comments
 (0)