Skip to content

Commit fda8e40

Browse files
authored
Merge pull request #857 from M00nF1sh/fix-sg
fix issue 838
2 parents f7b8011 + 299a7d3 commit fda8e40

File tree

4 files changed

+103
-61
lines changed

4 files changed

+103
-61
lines changed

internal/alb/sg/association.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func (c *associationController) ensureSGInstance(ctx context.Context, groupName
237237

238238
func (c *associationController) deleteSGInstance(ctx context.Context, instance *ec2.SecurityGroup) error {
239239
albctx.GetLogger(ctx).Infof("deleting securityGroup %v:%v", aws.StringValue(instance.GroupName), aws.StringValue(instance.Description))
240-
return c.cloud.DeleteSecurityGroupByID(aws.StringValue(instance.GroupId))
240+
return c.cloud.DeleteSecurityGroupByID(ctx, aws.StringValue(instance.GroupId))
241241
}
242242

243243
func (c *associationController) buildAssociationConfig(ctx context.Context, ingress *extensions.Ingress) (associationConfig, error) {

internal/alb/sg/instance_attachment.go

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"sync"
77

8+
"k8s.io/apimachinery/pkg/util/sets"
9+
810
"github.com/aws/aws-sdk-go/service/ec2"
911
"github.com/aws/aws-sdk-go/service/elbv2"
1012
"github.com/kubernetes-sigs/aws-alb-ingress-controller/internal/alb/tg"
@@ -37,38 +39,46 @@ func (controller *instanceAttachmentController) Reconcile(ctx context.Context, g
3739
if err != nil {
3840
return fmt.Errorf("failed to get cluster ENIs due to %v", err)
3941
}
42+
43+
// sgAttachedENIs is not always an subnet of instanceENIs :(, e.g. this CNI bug: https://github.com/aws/amazon-vpc-cni-k8s/issues/69
44+
sgAttachedENIs, err := controller.getSGAttachedENIs(ctx, groupID)
45+
if err != nil {
46+
return fmt.Errorf("failed to get ENIs attached to %s due to %v", groupID, err)
47+
}
48+
4049
supportingENIs := controller.findENIsSupportingTargets(instanceENIs, tgGroup)
4150
for _, enis := range instanceENIs {
4251
for _, eni := range enis {
43-
if _, ok := supportingENIs[aws.StringValue(eni.NetworkInterfaceId)]; ok {
44-
err := controller.ensureSGAttachedToENI(ctx, groupID, eni)
45-
if err != nil {
46-
return err
47-
}
48-
} else {
49-
err := controller.ensureSGDetachedFromENI(ctx, groupID, eni)
50-
if err != nil {
52+
if supportingENIs.Has(aws.StringValue(eni.NetworkInterfaceId)) {
53+
if err := controller.ensureSGAttachedToENI(ctx, groupID, eni); err != nil {
5154
return err
5255
}
5356
}
5457
}
5558
}
59+
60+
for _, eni := range sgAttachedENIs {
61+
if !supportingENIs.Has(aws.StringValue(eni.NetworkInterfaceId)) {
62+
if err := controller.ensureSGDetachedFromENI(ctx, groupID, eni); err != nil {
63+
return err
64+
}
65+
}
66+
}
67+
5668
return nil
5769
}
5870

5971
func (controller *instanceAttachmentController) Delete(ctx context.Context, groupID string) error {
6072
clusterInstanceENILock.Lock()
6173
defer clusterInstanceENILock.Unlock()
62-
instanceENIs, err := controller.getClusterInstanceENIs()
74+
75+
sgAttachedENIs, err := controller.getSGAttachedENIs(ctx, groupID)
6376
if err != nil {
64-
return fmt.Errorf("failed to get cluster enis due to %v", err)
77+
return fmt.Errorf("failed to get ENIs attached to %s due to %v", groupID, err)
6578
}
66-
for _, enis := range instanceENIs {
67-
for _, eni := range enis {
68-
err := controller.ensureSGDetachedFromENI(ctx, groupID, eni)
69-
if err != nil {
70-
return err
71-
}
79+
for _, eni := range sgAttachedENIs {
80+
if err := controller.ensureSGDetachedFromENI(ctx, groupID, eni); err != nil {
81+
return err
7282
}
7383
}
7484
return nil
@@ -92,7 +102,7 @@ func (controller *instanceAttachmentController) ensureSGAttachedToENI(ctx contex
92102
return err
93103
}
94104

95-
func (controller *instanceAttachmentController) ensureSGDetachedFromENI(ctx context.Context, sgID string, eni *ec2.InstanceNetworkInterface) error {
105+
func (controller *instanceAttachmentController) ensureSGDetachedFromENI(ctx context.Context, sgID string, eni *ec2.NetworkInterface) error {
96106
sgAttached := false
97107
desiredGroups := []string{}
98108
for _, group := range eni.Groups {
@@ -116,17 +126,15 @@ func (controller *instanceAttachmentController) ensureSGDetachedFromENI(ctx cont
116126
}
117127

118128
// findENIsSupportingTargets find the ID of ENIs that are used to supporting ingress traffic to targets
119-
func (controller *instanceAttachmentController) findENIsSupportingTargets(instanceENIs map[string][]*ec2.InstanceNetworkInterface, tgGroup tg.TargetGroupGroup) map[string]bool {
120-
result := make(map[string]bool)
129+
func (controller *instanceAttachmentController) findENIsSupportingTargets(instanceENIs map[string][]*ec2.InstanceNetworkInterface, tgGroup tg.TargetGroupGroup) sets.String {
130+
result := sets.NewString()
121131
for _, tg := range tgGroup.TGByBackend {
122132
if tg.TargetType == elbv2.TargetTypeEnumInstance {
123-
for _, eniID := range controller.findENIsSupportingTargetGroupOfTypeInstance(instanceENIs, tg) {
124-
result[eniID] = true
125-
}
133+
eniIDs := controller.findENIsSupportingTargetGroupOfTypeInstance(instanceENIs, tg)
134+
result.Insert(eniIDs...)
126135
} else {
127-
for _, eniID := range controller.findENIsSupportingTargetGroupOfTypeIP(instanceENIs, tg) {
128-
result[eniID] = true
129-
}
136+
eniIDs := controller.findENIsSupportingTargetGroupOfTypeIP(instanceENIs, tg)
137+
result.Insert(eniIDs...)
130138
}
131139
}
132140
return result
@@ -173,7 +181,7 @@ func (controller *instanceAttachmentController) findENIsSupportingTargetGroupOfT
173181
return result
174182
}
175183

176-
// getClusterInstanceENIs retrives all ENIs attached to instances indexed by instanceID
184+
// getClusterInstanceENIs retrieves all ENIs attached to instances indexed by instanceID
177185
func (controller *instanceAttachmentController) getClusterInstanceENIs() (map[string][]*ec2.InstanceNetworkInterface, error) {
178186
instanceIDs, err := controller.store.GetClusterInstanceIDs()
179187
if err != nil {
@@ -189,3 +197,15 @@ func (controller *instanceAttachmentController) getClusterInstanceENIs() (map[st
189197
}
190198
return result, nil
191199
}
200+
201+
// getSGAttachedENIs retrieves all ENIs attached with specified securityGroup.
202+
func (controller *instanceAttachmentController) getSGAttachedENIs(ctx context.Context, sgID string) ([]*ec2.NetworkInterface, error) {
203+
return controller.cloud.DescribeNetworkInterfaces(ctx, &ec2.DescribeNetworkInterfacesInput{
204+
Filters: []*ec2.Filter{
205+
{
206+
Name: aws.String("group-id"),
207+
Values: []*string{aws.String(sgID)},
208+
},
209+
},
210+
})
211+
}

internal/aws/ec2.go

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"time"
78

8-
"github.com/aws/aws-sdk-go/aws"
99
"github.com/aws/aws-sdk-go/aws/awserr"
10+
"k8s.io/apimachinery/pkg/util/wait"
11+
12+
"github.com/aws/aws-sdk-go/aws"
1013
"github.com/aws/aws-sdk-go/aws/request"
1114

1215
"github.com/aws/aws-sdk-go/service/ec2"
@@ -42,7 +45,10 @@ type EC2API interface {
4245
GetSecurityGroupsByName(context.Context, []string) ([]*ec2.SecurityGroup, error)
4346

4447
// DeleteSecurityGroupByID delete securityGroup by securityGroupID
45-
DeleteSecurityGroupByID(string) error
48+
DeleteSecurityGroupByID(context.Context, string) error
49+
50+
// DescribeNetworkInterfaces list network interfaces.
51+
DescribeNetworkInterfaces(context.Context, *ec2.DescribeNetworkInterfacesInput) ([]*ec2.NetworkInterface, error)
4652

4753
ModifyNetworkInterfaceAttributeWithContext(context.Context, *ec2.ModifyNetworkInterfaceAttributeInput) (*ec2.ModifyNetworkInterfaceAttributeOutput, error)
4854
CreateSecurityGroupWithContext(context.Context, *ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error)
@@ -78,6 +84,15 @@ func (c *Cloud) DeleteEC2TagsWithContext(ctx context.Context, i *ec2.DeleteTagsI
7884
return c.ec2.DeleteTagsWithContext(ctx, i)
7985
}
8086

87+
func (c *Cloud) DescribeNetworkInterfaces(ctx context.Context, input *ec2.DescribeNetworkInterfacesInput) ([]*ec2.NetworkInterface, error) {
88+
var result []*ec2.NetworkInterface
89+
err := c.ec2.DescribeNetworkInterfacesPagesWithContext(ctx, input, func(output *ec2.DescribeNetworkInterfacesOutput, _ bool) bool {
90+
result = append(result, output.NetworkInterfaces...)
91+
return true
92+
})
93+
return result, err
94+
}
95+
8196
func (c *Cloud) GetSubnetsByNameOrID(ctx context.Context, nameOrIDs []string) (subnets []*ec2.Subnet, err error) {
8297
var filters [][]*ec2.Filter
8398
var names []string
@@ -201,20 +216,22 @@ func (c *Cloud) GetSecurityGroupByName(groupName string) (*ec2.SecurityGroup, er
201216
return securityGroups[0], nil
202217
}
203218

204-
func (c *Cloud) DeleteSecurityGroupByID(groupID string) error {
219+
func (c *Cloud) DeleteSecurityGroupByID(ctx context.Context, groupID string) error {
205220
input := &ec2.DeleteSecurityGroupInput{
206221
GroupId: aws.String(groupID),
207222
}
208223

209-
retryOption := func(req *request.Request) {
210-
req.Retryer = &deleteSecurityGroupRetryer{
211-
req.Retryer,
224+
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
225+
defer cancel()
226+
return wait.PollImmediateUntil(2*time.Second, func() (done bool, err error) {
227+
if _, err := c.ec2.DeleteSecurityGroupWithContext(ctx, input); err != nil {
228+
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "DependencyViolation" {
229+
return false, nil
230+
}
231+
return false, err
212232
}
213-
}
214-
if _, err := c.ec2.DeleteSecurityGroupWithContext(aws.BackgroundContext(), input, retryOption); err != nil {
215-
return err
216-
}
217-
return nil
233+
return true, nil
234+
}, ctx.Done())
218235
}
219236

220237
// describeSecurityGroups is an helper to handle pagination for DescribeSecurityGroups API call
@@ -277,21 +294,3 @@ func (c *Cloud) IsNodeHealthy(instanceid string) (bool, error) {
277294

278295
return false, nil
279296
}
280-
281-
type deleteSecurityGroupRetryer struct {
282-
request.Retryer
283-
}
284-
285-
func (r *deleteSecurityGroupRetryer) ShouldRetry(req *request.Request) bool {
286-
if awsErr, ok := req.Error.(awserr.Error); ok {
287-
if awsErr.Code() == "DependencyViolation" {
288-
return true
289-
}
290-
}
291-
// Fallback to built in retry rules
292-
return r.Retryer.ShouldRetry(req)
293-
}
294-
295-
func (r *deleteSecurityGroupRetryer) MaxRetries() int {
296-
return 20
297-
}

mocks/CloudAPI.go

Lines changed: 28 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)