@@ -2,6 +2,10 @@ package elbv2
2
2
3
3
import (
4
4
"context"
5
+ "sync"
6
+ "time"
7
+
8
+ "k8s.io/apimachinery/pkg/util/cache"
5
9
6
10
awssdk "github.com/aws/aws-sdk-go/aws"
7
11
elbv2sdk "github.com/aws/aws-sdk-go/service/elbv2"
@@ -18,6 +22,8 @@ import (
18
22
const (
19
23
// ELBV2 API supports up to 20 resource per DescribeTags API call.
20
24
defaultDescribeTagsChunkSize = 20
25
+ // cache ttl for tags on ELB resources.
26
+ defaultResourceTagsCacheTTL = 20 * time .Minute
21
27
)
22
28
23
29
// LoadBalancer with it's tags.
@@ -103,6 +109,8 @@ func NewDefaultTaggingManager(elbv2Client services.ELBV2, vpcID string, featureG
103
109
featureGates : featureGates ,
104
110
logger : logger ,
105
111
describeTagsChunkSize : defaultDescribeTagsChunkSize ,
112
+ resourceTagsCache : cache .NewExpiring (),
113
+ resourceTagsCacheTTL : defaultResourceTagsCacheTTL ,
106
114
rgt : rgt ,
107
115
}
108
116
}
@@ -117,7 +125,11 @@ type defaultTaggingManager struct {
117
125
featureGates config.FeatureGates
118
126
logger logr.Logger
119
127
describeTagsChunkSize int
120
- rgt services.RGT
128
+ // cache for tags on ELB resources.
129
+ resourceTagsCache * cache.Expiring
130
+ resourceTagsCacheTTL time.Duration
131
+ resourceTagsCacheMutex sync.RWMutex
132
+ rgt services.RGT
121
133
}
122
134
123
135
func (m * defaultTaggingManager ) ReconcileTags (ctx context.Context , arn string , desiredTags map [string ]string , opts ... ReconcileTagsOption ) error {
@@ -128,7 +140,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
128
140
reconcileOpts .ApplyOptions (opts )
129
141
currentTags := reconcileOpts .CurrentTags
130
142
if currentTags == nil {
131
- tagsByARN , err := m .describeResourceTagsNative (ctx , []string {arn })
143
+ tagsByARN , err := m .describeResourceTags (ctx , []string {arn })
132
144
if err != nil {
133
145
return err
134
146
}
@@ -153,6 +165,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
153
165
if _ , err := m .elbv2Client .AddTagsWithContext (ctx , req ); err != nil {
154
166
return err
155
167
}
168
+ m .invalidateResourceTagsCache (arn )
156
169
m .logger .Info ("added resource tags" ,
157
170
"arn" , arn )
158
171
}
@@ -170,6 +183,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
170
183
if _ , err := m .elbv2Client .RemoveTagsWithContext (ctx , req ); err != nil {
171
184
return err
172
185
}
186
+ m .invalidateResourceTagsCache (arn )
173
187
m .logger .Info ("removed resource tags" ,
174
188
"arn" , arn )
175
189
}
@@ -193,7 +207,7 @@ func (m *defaultTaggingManager) ListListeners(ctx context.Context, lbARN string)
193
207
}
194
208
var tagsByARN map [string ]map [string ]string
195
209
if m .featureGates .Enabled (config .ListenerRulesTagging ) {
196
- tagsByARN , err = m .describeResourceTagsNative (ctx , lsARNs )
210
+ tagsByARN , err = m .describeResourceTags (ctx , lsARNs )
197
211
if err != nil {
198
212
return nil , err
199
213
}
@@ -226,7 +240,7 @@ func (m *defaultTaggingManager) ListListenerRules(ctx context.Context, lsARN str
226
240
}
227
241
var tagsByARN map [string ]map [string ]string
228
242
if m .featureGates .Enabled (config .ListenerRulesTagging ) {
229
- tagsByARN , err = m .describeResourceTagsNative (ctx , lrARNs )
243
+ tagsByARN , err = m .describeResourceTags (ctx , lrARNs )
230
244
if err != nil {
231
245
return nil , err
232
246
}
@@ -242,6 +256,7 @@ func (m *defaultTaggingManager) ListListenerRules(ctx context.Context, lsARN str
242
256
return sdkLRs , err
243
257
}
244
258
259
+ // TODO: we can refactor this by store provisioned LB's ARN as annotations on Ingress/Service, thus avoid this heavy lookup calls when RGT is not available.
245
260
func (m * defaultTaggingManager ) ListLoadBalancers (ctx context.Context , tagFilters ... tracking.TagFilter ) ([]LoadBalancerWithTags , error ) {
246
261
if m .featureGates .Enabled (config .EnableRGTAPI ) {
247
262
return m .listLoadBalancersRGT (ctx , tagFilters )
@@ -254,7 +269,6 @@ func (m *defaultTaggingManager) ListTargetGroups(ctx context.Context, tagFilters
254
269
return m .listTargetGroupsRGT (ctx , tagFilters )
255
270
}
256
271
return m .listTargetGroupsNative (ctx , tagFilters )
257
-
258
272
}
259
273
260
274
func (m * defaultTaggingManager ) listLoadBalancersRGT (ctx context.Context , tagFilters []tracking.TagFilter ) ([]LoadBalancerWithTags , error ) {
@@ -311,7 +325,7 @@ func (m *defaultTaggingManager) listLoadBalancersNative(ctx context.Context, tag
311
325
lbARNsWithinVPC = append (lbARNsWithinVPC , lbARN )
312
326
lbByARNWithinVPC [lbARN ] = lb
313
327
}
314
- tagsByARN , err := m .describeResourceTagsNative (ctx , lbARNsWithinVPC )
328
+ tagsByARN , err := m .describeResourceTags (ctx , lbARNsWithinVPC )
315
329
if err != nil {
316
330
return nil , err
317
331
}
@@ -391,7 +405,7 @@ func (m *defaultTaggingManager) listTargetGroupsNative(ctx context.Context, tagF
391
405
tgARNsWithinVPC = append (tgARNsWithinVPC , tgARN )
392
406
tgByARNWithinVPC [tgARN ] = tg
393
407
}
394
- tagsByARN , err := m .describeResourceTagsNative (ctx , tgARNsWithinVPC )
408
+ tagsByARN , err := m .describeResourceTags (ctx , tgARNsWithinVPC )
395
409
if err != nil {
396
410
return nil , err
397
411
}
@@ -416,9 +430,34 @@ func (m *defaultTaggingManager) listTargetGroupsNative(ctx context.Context, tagF
416
430
return matchedTGs , nil
417
431
}
418
432
419
- // describeResourceTagsNative describes tags for elbv2 resources.
433
+ func (m * defaultTaggingManager ) describeResourceTags (ctx context.Context , arns []string ) (map [string ]map [string ]string , error ) {
434
+ m .resourceTagsCacheMutex .Lock ()
435
+ defer m .resourceTagsCacheMutex .Unlock ()
436
+
437
+ tagsByARN := make (map [string ]map [string ]string , len (arns ))
438
+ var arnsWithoutTagsCache []string
439
+ for _ , arn := range arns {
440
+ if rawTagsCacheItem , exists := m .resourceTagsCache .Get (arn ); exists {
441
+ tagsCacheItem := rawTagsCacheItem .(map [string ]string )
442
+ tagsByARN [arn ] = tagsCacheItem
443
+ } else {
444
+ arnsWithoutTagsCache = append (arnsWithoutTagsCache , arn )
445
+ }
446
+ }
447
+ tagsByARNFromAWS , err := m .describeResourceTagsFromAWS (ctx , arnsWithoutTagsCache )
448
+ if err != nil {
449
+ return nil , err
450
+ }
451
+ for arn , tags := range tagsByARNFromAWS {
452
+ m .resourceTagsCache .Set (arn , tags , m .resourceTagsCacheTTL )
453
+ tagsByARN [arn ] = tags
454
+ }
455
+ return tagsByARN , nil
456
+ }
457
+
458
+ // describeResourceTagsFromAWS describes tags for elbv2 resources.
420
459
// returns tags indexed by resource ARN.
421
- func (m * defaultTaggingManager ) describeResourceTagsNative (ctx context.Context , arns []string ) (map [string ]map [string ]string , error ) {
460
+ func (m * defaultTaggingManager ) describeResourceTagsFromAWS (ctx context.Context , arns []string ) (map [string ]map [string ]string , error ) {
422
461
tagsByARN := make (map [string ]map [string ]string , len (arns ))
423
462
arnsChunks := algorithm .ChunkStrings (arns , m .describeTagsChunkSize )
424
463
for _ , arnsChunk := range arnsChunks {
@@ -436,6 +475,13 @@ func (m *defaultTaggingManager) describeResourceTagsNative(ctx context.Context,
436
475
return tagsByARN , nil
437
476
}
438
477
478
+ func (m * defaultTaggingManager ) invalidateResourceTagsCache (arn string ) {
479
+ m .resourceTagsCacheMutex .Lock ()
480
+ defer m .resourceTagsCacheMutex .Unlock ()
481
+
482
+ m .resourceTagsCache .Delete (arn )
483
+ }
484
+
439
485
// convert tags into AWS SDK tag presentation.
440
486
func convertTagsToSDKTags (tags map [string ]string ) []* elbv2sdk.Tag {
441
487
if len (tags ) == 0 {
0 commit comments