in aws/aws.go [4583:4767]
func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error {
if isLBExternal(service.Annotations) {
return nil
}
loadBalancerName := c.GetLoadBalancerName(ctx, clusterName, service)
if isNLB(service.Annotations) {
lb, err := c.describeLoadBalancerv2(loadBalancerName)
if err != nil {
return err
}
if lb == nil {
klog.Info("Load balancer already deleted: ", loadBalancerName)
return nil
}
// Delete the LoadBalancer and target groups
//
// Deleting a target group while associated with a load balancer will
// fail. We delete the loadbalancer first. This does leave the
// possibility of zombie target groups if DeleteLoadBalancer() fails
//
// * Get target groups for NLB
// * Delete Load Balancer
// * Delete target groups
// * Clean up SecurityGroupRules
{
targetGroups, err := c.elbv2.DescribeTargetGroups(
&elbv2.DescribeTargetGroupsInput{LoadBalancerArn: lb.LoadBalancerArn},
)
if err != nil {
return fmt.Errorf("error listing target groups before deleting load balancer: %q", err)
}
_, err = c.elbv2.DeleteLoadBalancer(
&elbv2.DeleteLoadBalancerInput{LoadBalancerArn: lb.LoadBalancerArn},
)
if err != nil {
return fmt.Errorf("error deleting load balancer %q: %v", loadBalancerName, err)
}
for _, group := range targetGroups.TargetGroups {
_, err := c.elbv2.DeleteTargetGroup(
&elbv2.DeleteTargetGroupInput{TargetGroupArn: group.TargetGroupArn},
)
if err != nil {
return fmt.Errorf("error deleting target groups after deleting load balancer: %q", err)
}
}
}
return c.updateInstanceSecurityGroupsForNLB(loadBalancerName, nil, nil, nil, nil)
}
lb, err := c.describeLoadBalancer(loadBalancerName)
if err != nil {
return err
}
if lb == nil {
klog.Info("Load balancer already deleted: ", loadBalancerName)
return nil
}
{
// De-authorize the load balancer security group from the instances security group
err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, nil, service.Annotations)
if err != nil {
klog.Errorf("Error deregistering load balancer from instance security groups: %q", err)
return err
}
}
{
// Delete the load balancer itself
request := &elb.DeleteLoadBalancerInput{}
request.LoadBalancerName = lb.LoadBalancerName
_, err = c.elb.DeleteLoadBalancer(request)
if err != nil {
// TODO: Check if error was because load balancer was concurrently deleted
klog.Errorf("Error deleting load balancer: %q", err)
return err
}
}
{
// Delete the security group(s) for the load balancer
// Note that this is annoying: the load balancer disappears from the API immediately, but it is still
// deleting in the background. We get a DependencyViolation until the load balancer has deleted itself
var loadBalancerSGs = aws.StringValueSlice(lb.SecurityGroups)
describeRequest := &ec2.DescribeSecurityGroupsInput{}
describeRequest.Filters = []*ec2.Filter{
newEc2Filter("group-id", loadBalancerSGs...),
}
response, err := c.ec2.DescribeSecurityGroups(describeRequest)
if err != nil {
return fmt.Errorf("error querying security groups for ELB: %q", err)
}
// Collect the security groups to delete
securityGroupIDs := map[string]struct{}{}
annotatedSgSet := map[string]bool{}
annotatedSgsList := getSGListFromAnnotation(service.Annotations[ServiceAnnotationLoadBalancerSecurityGroups])
annotatedExtraSgsList := getSGListFromAnnotation(service.Annotations[ServiceAnnotationLoadBalancerExtraSecurityGroups])
annotatedSgsList = append(annotatedSgsList, annotatedExtraSgsList...)
for _, sg := range annotatedSgsList {
annotatedSgSet[sg] = true
}
for _, sg := range response {
sgID := aws.StringValue(sg.GroupId)
if sgID == c.cfg.Global.ElbSecurityGroup {
//We don't want to delete a security group that was defined in the Cloud Configuration.
continue
}
if sgID == "" {
klog.Warningf("Ignoring empty security group in %s", service.Name)
continue
}
if !c.tagging.hasClusterTag(sg.Tags) {
klog.Warningf("Ignoring security group with no cluster tag in %s", service.Name)
continue
}
// This is an extra protection of deletion of non provisioned Security Group which is annotated with `service.beta.kubernetes.io/aws-load-balancer-security-groups`.
if _, ok := annotatedSgSet[sgID]; ok {
klog.Warningf("Ignoring security group with annotation `service.beta.kubernetes.io/aws-load-balancer-security-groups` or service.beta.kubernetes.io/aws-load-balancer-extra-security-groups in %s", service.Name)
continue
}
securityGroupIDs[sgID] = struct{}{}
}
// Loop through and try to delete them
timeoutAt := time.Now().Add(time.Second * 600)
for {
for securityGroupID := range securityGroupIDs {
request := &ec2.DeleteSecurityGroupInput{}
request.GroupId = &securityGroupID
_, err := c.ec2.DeleteSecurityGroup(request)
if err == nil {
delete(securityGroupIDs, securityGroupID)
} else {
ignore := false
if awsError, ok := err.(awserr.Error); ok {
if awsError.Code() == "DependencyViolation" {
klog.V(2).Infof("Ignoring DependencyViolation while deleting load-balancer security group (%s), assuming because LB is in process of deleting", securityGroupID)
ignore = true
}
}
if !ignore {
return fmt.Errorf("error while deleting load balancer security group (%s): %q", securityGroupID, err)
}
}
}
if len(securityGroupIDs) == 0 {
klog.V(2).Info("Deleted all security groups for load balancer: ", service.Name)
break
}
if time.Now().After(timeoutAt) {
ids := []string{}
for id := range securityGroupIDs {
ids = append(ids, id)
}
return fmt.Errorf("timed out deleting ELB: %s. Could not delete security groups %v", service.Name, strings.Join(ids, ","))
}
klog.V(2).Info("Waiting for load-balancer to delete so we can delete security groups: ", service.Name)
time.Sleep(10 * time.Second)
}
}
return nil
}