Skip to content

Commit ef89515

Browse files
committed
[feat aga] Implement endpoint loader with DNS resolution
1 parent 9f38c16 commit ef89515

13 files changed

+2181
-16
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ require (
104104
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
105105
github.com/hashicorp/errwrap v1.1.0 // indirect
106106
github.com/hashicorp/go-multierror v1.1.1 // indirect
107+
github.com/hashicorp/golang-lru v1.0.2 // indirect
107108
github.com/huandu/xstrings v1.5.0 // indirect
108109
github.com/imkira/go-interpol v1.1.0 // indirect
109110
github.com/inconshreveable/mousetrap v1.1.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
228228
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
229229
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
230230
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
231+
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
232+
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
231233
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
232234
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
233235
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package aga
2+
3+
import (
4+
"context"
5+
"fmt"
6+
awssdk "github.com/aws/aws-sdk-go-v2/aws"
7+
"sync"
8+
"time"
9+
10+
elbv2sdk "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
11+
"github.com/hashicorp/golang-lru"
12+
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
13+
)
14+
15+
const (
16+
// AWS Global Accelerator has a quota of 420 endpoints per AWS account (can be increased)
17+
// Using 420 provides headroom while efficiently caching DNS-to-ARN resolutions
18+
LRU_CACHE_SIZE = 420
19+
)
20+
21+
// DNSToLoadBalancerResolver resolves load balancer DNS names to ARNs
22+
type DNSToLoadBalancerResolver struct {
23+
elbv2Client services.ELBV2
24+
cache *lru.Cache
25+
cacheMutex sync.RWMutex
26+
ttl time.Duration
27+
}
28+
29+
type cacheEntry struct {
30+
arn string
31+
expireAt time.Time
32+
}
33+
34+
// NewDNSToLoadBalancerResolver creates a new DNSToLoadBalancerResolver
35+
func NewDNSToLoadBalancerResolver(elbv2Client services.ELBV2) (*DNSToLoadBalancerResolver, error) {
36+
cache, err := lru.New(LRU_CACHE_SIZE)
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
return &DNSToLoadBalancerResolver{
42+
elbv2Client: elbv2Client,
43+
cache: cache,
44+
ttl: 5 * time.Minute, // Default TTL of 5 minutes
45+
}, nil
46+
}
47+
48+
// ResolveDNSToLoadBalancerARN resolves a load balancer DNS name to an ARN
49+
func (r *DNSToLoadBalancerResolver) ResolveDNSToLoadBalancerARN(ctx context.Context, dnsName string) (string, error) {
50+
if dnsName == "" {
51+
return "", fmt.Errorf("empty DNS name")
52+
}
53+
54+
// Check cache first
55+
r.cacheMutex.RLock()
56+
if value, found := r.cache.Get(dnsName); found {
57+
entry := value.(cacheEntry)
58+
// Check if the cache entry is still valid
59+
if time.Now().Before(entry.expireAt) {
60+
r.cacheMutex.RUnlock()
61+
return entry.arn, nil
62+
}
63+
// Entry has expired, remove from cache
64+
r.cache.Remove(dnsName)
65+
}
66+
r.cacheMutex.RUnlock()
67+
68+
req := &elbv2sdk.DescribeLoadBalancersInput{}
69+
lbs, err := r.elbv2Client.DescribeLoadBalancersAsList(ctx, req)
70+
if err != nil {
71+
return "", fmt.Errorf("failed to describe load balancers: %w", err)
72+
}
73+
if len(lbs) == 0 {
74+
return "", fmt.Errorf("no load balancers found")
75+
}
76+
arn := ""
77+
for _, lb := range lbs {
78+
if awssdk.ToString(lb.DNSName) == dnsName {
79+
arn = awssdk.ToString(lb.LoadBalancerArn)
80+
break
81+
}
82+
}
83+
if arn == "" {
84+
return "", fmt.Errorf("no load balancer found for dns %s", dnsName)
85+
}
86+
87+
// Cache the result
88+
r.cacheMutex.Lock()
89+
r.cache.Add(dnsName, cacheEntry{
90+
arn: arn,
91+
expireAt: time.Now().Add(r.ttl),
92+
})
93+
r.cacheMutex.Unlock()
94+
95+
return arn, nil
96+
}
97+
98+
// Ensure DNSToLoadBalancerResolver implements DNSLoadBalancerResolverInterface
99+
var _ DNSLoadBalancerResolverInterface = (*DNSToLoadBalancerResolver)(nil)

0 commit comments

Comments
 (0)