Skip to content

Commit 269388c

Browse files
committed
use ELBv2 tag operation to filter TargetGroups, same solution #1387
1 parent 4ba8b59 commit 269388c

File tree

7 files changed

+977
-47
lines changed

7 files changed

+977
-47
lines changed

internal/alb/tg/targetgroup_group.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ func (controller *defaultGroupController) GC(ctx context.Context, tgGroup Target
9393
for _, tg := range tgGroup.TGByBackend {
9494
usedServiceTGARNs.Insert(tg.Arn)
9595
}
96-
arns, err := controller.cloud.GetResourcesByFilters(tagFilters, aws.ResourceTypeEnumELBTargetGroup)
96+
97+
targetGroups, err := controller.cloud.GetTargetGroupsByTagFilters(ctx, tagFilters)
98+
arns := make([]string, 0, len(targetGroups))
99+
for _, tg := range targetGroups {
100+
arns = append(arns, aws.StringValue(tg.TargetGroupArn))
101+
}
97102
if err != nil {
98103
return fmt.Errorf("failed to get targetGroups due to %v", err)
99104
}

internal/alb/tg/targetgroup_group_test.go

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@ type TGReconcileCall struct {
2525
Err error
2626
}
2727

28-
type GetResourcesByFiltersCall struct {
28+
type GetTargetGroupsByTagFiltersCall struct {
2929
TagFilters map[string][]string
30-
ResourceType string
31-
Arns []string
30+
TargetGroups []*elbv2.TargetGroup
3231
Err error
3332
}
3433

@@ -536,11 +535,11 @@ func TestDefaultGroupController_Reconcile(t *testing.T) {
536535

537536
func TestDefaultGroupController_GC(t *testing.T) {
538537
for _, tc := range []struct {
539-
Name string
540-
TGGroup TargetGroupGroup
541-
GetResourcesByFiltersCall *GetResourcesByFiltersCall
542-
DeleteTargetGroupByArnCalls []DeleteTargetGroupByArnCall
543-
ExpectedError error
538+
Name string
539+
TGGroup TargetGroupGroup
540+
GetTargetGroupsByTagFiltersCall *GetTargetGroupsByTagFiltersCall
541+
DeleteTargetGroupByArnCalls []DeleteTargetGroupByArnCall
542+
ExpectedError error
544543
}{
545544
{
546545
Name: "GC succeeds",
@@ -553,10 +552,13 @@ func TestDefaultGroupController_GC(t *testing.T) {
553552
},
554553
selector: map[string]string{"key1": "value1", "key2": "value2"},
555554
},
556-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
557-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
558-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
559-
Arns: []string{"arn1", "arn2", "arn3"},
555+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
556+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
557+
TargetGroups: []*elbv2.TargetGroup{
558+
{TargetGroupArn: aws.String("arn1")},
559+
{TargetGroupArn: aws.String("arn2")},
560+
{TargetGroupArn: aws.String("arn3")},
561+
},
560562
},
561563
DeleteTargetGroupByArnCalls: []DeleteTargetGroupByArnCall{
562564
{
@@ -579,10 +581,13 @@ func TestDefaultGroupController_GC(t *testing.T) {
579581
externalTGARNs: []string{"arn3"},
580582
selector: map[string]string{"key1": "value1", "key2": "value2"},
581583
},
582-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
583-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
584-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
585-
Arns: []string{"arn1", "arn2", "arn3"},
584+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
585+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
586+
TargetGroups: []*elbv2.TargetGroup{
587+
{TargetGroupArn: aws.String("arn1")},
588+
{TargetGroupArn: aws.String("arn2")},
589+
{TargetGroupArn: aws.String("arn3")},
590+
},
586591
},
587592
DeleteTargetGroupByArnCalls: []DeleteTargetGroupByArnCall{
588593
{
@@ -601,10 +606,9 @@ func TestDefaultGroupController_GC(t *testing.T) {
601606
},
602607
selector: map[string]string{"key1": "value1", "key2": "value2"},
603608
},
604-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
605-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
606-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
607-
Err: errors.New("GetResourcesByFiltersCall"),
609+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
610+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
611+
Err: errors.New("GetResourcesByFiltersCall"),
608612
},
609613
ExpectedError: errors.New("failed to get targetGroups due to GetResourcesByFiltersCall"),
610614
},
@@ -619,10 +623,13 @@ func TestDefaultGroupController_GC(t *testing.T) {
619623
},
620624
selector: map[string]string{"key1": "value1", "key2": "value2"},
621625
},
622-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
623-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
624-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
625-
Arns: []string{"arn1", "arn2", "arn3"},
626+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
627+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
628+
TargetGroups: []*elbv2.TargetGroup{
629+
{TargetGroupArn: aws.String("arn1")},
630+
{TargetGroupArn: aws.String("arn2")},
631+
{TargetGroupArn: aws.String("arn3")},
632+
},
626633
},
627634
DeleteTargetGroupByArnCalls: []DeleteTargetGroupByArnCall{
628635
{
@@ -635,8 +642,8 @@ func TestDefaultGroupController_GC(t *testing.T) {
635642
} {
636643
ctx := context.Background()
637644
cloud := &mocks.CloudAPI{}
638-
if tc.GetResourcesByFiltersCall != nil {
639-
cloud.On("GetResourcesByFilters", tc.GetResourcesByFiltersCall.TagFilters, tc.GetResourcesByFiltersCall.ResourceType).Return(tc.GetResourcesByFiltersCall.Arns, tc.GetResourcesByFiltersCall.Err)
645+
if tc.GetTargetGroupsByTagFiltersCall != nil {
646+
cloud.On("GetTargetGroupsByTagFilters", ctx, tc.GetTargetGroupsByTagFiltersCall.TagFilters).Return(tc.GetTargetGroupsByTagFiltersCall.TargetGroups, tc.GetTargetGroupsByTagFiltersCall.Err)
640647
}
641648
for _, call := range tc.DeleteTargetGroupByArnCalls {
642649
cloud.On("DeleteTargetGroupByArn", ctx, call.Arn).Return(call.Err)
@@ -663,12 +670,12 @@ func TestDefaultGroupController_GC(t *testing.T) {
663670

664671
func TestDefaultGroupController_Delete(t *testing.T) {
665672
for _, tc := range []struct {
666-
Name string
667-
IngressKey types.NamespacedName
668-
TagTGGroupCall *TagTGGroupCall
669-
GetResourcesByFiltersCall *GetResourcesByFiltersCall
670-
DeleteTargetGroupByArnCalls []DeleteTargetGroupByArnCall
671-
ExpectedError error
673+
Name string
674+
IngressKey types.NamespacedName
675+
TagTGGroupCall *TagTGGroupCall
676+
GetTargetGroupsByTagFiltersCall *GetTargetGroupsByTagFiltersCall
677+
DeleteTargetGroupByArnCalls []DeleteTargetGroupByArnCall
678+
ExpectedError error
672679
}{
673680
{
674681
Name: "DELETE succeeds",
@@ -681,10 +688,13 @@ func TestDefaultGroupController_Delete(t *testing.T) {
681688
IngressName: "ingress",
682689
Tags: map[string]string{"key1": "value1", "key2": "value2"},
683690
},
684-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
685-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
686-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
687-
Arns: []string{"arn1", "arn2", "arn3"},
691+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
692+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
693+
TargetGroups: []*elbv2.TargetGroup{
694+
{TargetGroupArn: aws.String("arn1")},
695+
{TargetGroupArn: aws.String("arn2")},
696+
{TargetGroupArn: aws.String("arn3")},
697+
},
688698
},
689699
DeleteTargetGroupByArnCalls: []DeleteTargetGroupByArnCall{
690700
{
@@ -709,10 +719,9 @@ func TestDefaultGroupController_Delete(t *testing.T) {
709719
IngressName: "ingress",
710720
Tags: map[string]string{"key1": "value1", "key2": "value2"},
711721
},
712-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
713-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
714-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
715-
Err: errors.New("GetResourcesByFiltersCall"),
722+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
723+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
724+
Err: errors.New("GetResourcesByFiltersCall"),
716725
},
717726
ExpectedError: errors.New("failed to get targetGroups due to GetResourcesByFiltersCall"),
718727
},
@@ -727,10 +736,13 @@ func TestDefaultGroupController_Delete(t *testing.T) {
727736
IngressName: "ingress",
728737
Tags: map[string]string{"key1": "value1", "key2": "value2"},
729738
},
730-
GetResourcesByFiltersCall: &GetResourcesByFiltersCall{
731-
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
732-
ResourceType: aws.ResourceTypeEnumELBTargetGroup,
733-
Arns: []string{"arn1", "arn2", "arn3"},
739+
GetTargetGroupsByTagFiltersCall: &GetTargetGroupsByTagFiltersCall{
740+
TagFilters: map[string][]string{"key1": {"value1"}, "key2": {"value2"}},
741+
TargetGroups: []*elbv2.TargetGroup{
742+
{TargetGroupArn: aws.String("arn1")},
743+
{TargetGroupArn: aws.String("arn2")},
744+
{TargetGroupArn: aws.String("arn3")},
745+
},
734746
},
735747
DeleteTargetGroupByArnCalls: []DeleteTargetGroupByArnCall{
736748
{
@@ -743,8 +755,8 @@ func TestDefaultGroupController_Delete(t *testing.T) {
743755
} {
744756
ctx := context.Background()
745757
cloud := &mocks.CloudAPI{}
746-
if tc.GetResourcesByFiltersCall != nil {
747-
cloud.On("GetResourcesByFilters", tc.GetResourcesByFiltersCall.TagFilters, tc.GetResourcesByFiltersCall.ResourceType).Return(tc.GetResourcesByFiltersCall.Arns, tc.GetResourcesByFiltersCall.Err)
758+
if tc.GetTargetGroupsByTagFiltersCall != nil {
759+
cloud.On("GetTargetGroupsByTagFilters", ctx, tc.GetTargetGroupsByTagFiltersCall.TagFilters).Return(tc.GetTargetGroupsByTagFiltersCall.TargetGroups, tc.GetTargetGroupsByTagFiltersCall.Err)
748760
}
749761
for _, call := range tc.DeleteTargetGroupByArnCalls {
750762
cloud.On("DeleteTargetGroupByArn", ctx, call.Arn).Return(call.Err)

internal/aws/elbv2.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"github.com/aws/aws-sdk-go/aws/awserr"
99
"github.com/aws/aws-sdk-go/aws/request"
1010
"github.com/aws/aws-sdk-go/service/elbv2"
11+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/internal/utils"
12+
util "github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/types"
1113
)
1214

1315
type ELBV2API interface {
@@ -36,6 +38,9 @@ type ELBV2API interface {
3638
// GetTargetGroupByName retrieve TargetGroup instance by name
3739
GetTargetGroupByName(context.Context, string) (*elbv2.TargetGroup, error)
3840

41+
// GetTargetGroupsByTagFilters retrieve TargetGroups instance by tags
42+
GetTargetGroupsByTagFilters(ctx context.Context, tagFilters map[string][]string) ([]*elbv2.TargetGroup, error)
43+
3944
// DeleteTargetGroupByArn deletes TargetGroup instance by arn
4045
DeleteTargetGroupByArn(context.Context, string) error
4146

@@ -291,6 +296,35 @@ func (c *Cloud) GetTargetGroupByName(ctx context.Context, name string) (*elbv2.T
291296
return targetGroups[0], nil
292297
}
293298

299+
// GetTargetGroupsByTagFilters retrieve TargetGroups instance by tags
300+
func (c *Cloud) GetTargetGroupsByTagFilters(ctx context.Context, tagFilters map[string][]string) ([]*elbv2.TargetGroup, error) {
301+
req := &elbv2.DescribeTargetGroupsInput{}
302+
tgs, err := c.describeTargetGroupsHelper(req)
303+
if err != nil {
304+
return nil, err
305+
}
306+
307+
tgARNs := make([]string, 0, len(tgs))
308+
tgByARN := make(map[string]*elbv2.TargetGroup, len(tgs))
309+
for _, tg := range tgs {
310+
tgARN := aws.StringValue(tg.TargetGroupArn)
311+
tgARNs = append(tgARNs, tgARN)
312+
tgByARN[tgARN] = tg
313+
}
314+
tagsByARN, err := c.describeResourceTags(ctx, tgARNs)
315+
if err != nil {
316+
return nil, err
317+
}
318+
319+
var matchedTGs []*elbv2.TargetGroup
320+
for _, arn := range tgARNs {
321+
if util.Matches(tagsByARN[arn], tagFilters) {
322+
matchedTGs = append(matchedTGs, tgByARN[arn])
323+
}
324+
}
325+
return matchedTGs, nil
326+
}
327+
294328
// DeleteTargetGroupByArn deletes TargetGroup instance by arn
295329
func (c *Cloud) DeleteTargetGroupByArn(ctx context.Context, arn string) error {
296330
_, err := c.elbv2.DeleteTargetGroupWithContext(ctx, &elbv2.DeleteTargetGroupInput{
@@ -322,3 +356,33 @@ func (c *Cloud) describeTargetGroupsHelper(input *elbv2.DescribeTargetGroupsInpu
322356
})
323357
return result, err
324358
}
359+
360+
const (
361+
// ELBV2 API supports up to 20 resource per DescribeTags API call.
362+
defaultDescribeTagsChunkSize = 20
363+
)
364+
365+
// describeResourceTags describes tags for elbv2 resources.
366+
// returns tags indexed by resource ARN.
367+
func (c *Cloud) describeResourceTags(ctx context.Context, arns []string) (map[string]map[string]string, error) {
368+
tagsByARN := make(map[string]map[string]string, len(arns))
369+
arnsChunks := utils.SplitStringSlice(arns, defaultDescribeTagsChunkSize)
370+
for _, arnsChunk := range arnsChunks {
371+
req := &elbv2.DescribeTagsInput{
372+
ResourceArns: aws.StringSlice(arnsChunk),
373+
}
374+
375+
resp, err := c.elbv2.DescribeTagsWithContext(ctx, req)
376+
if err != nil {
377+
return nil, err
378+
}
379+
for _, tagDescription := range resp.TagDescriptions {
380+
tags := make(map[string]string, len(tagDescription.Tags))
381+
for _, sdkTag := range tagDescription.Tags {
382+
tags[aws.StringValue(sdkTag.Key)] = aws.StringValue(sdkTag.Value)
383+
}
384+
tagsByARN[aws.StringValue(tagDescription.ResourceArn)] = tags
385+
}
386+
}
387+
return tagsByARN, nil
388+
}

0 commit comments

Comments
 (0)