@@ -36,109 +36,90 @@ func NewDefaultAZIDTranslator(ec2Client services.EC2, logger logr.Logger) *defau
3636
3737var _ AZIDTranslator = & defaultAZIDTranslator {}
3838
39- // zoneCacheKey scopes a cached zone lookup to a single account.
40- // Availability zone names are only meaningful within an account, so entries for different accounts
41- // must never be shared. scope is empty for the cluster's own account and the assumed role ARN
42- // otherwise.
43- type zoneCacheKey struct {
44- scope string
45- lookup string
39+ // zoneMapping holds every availability zone of a single account, indexed by name and by ID.
40+ type zoneMapping struct {
41+ idByName map [string ]string
42+ nameByID map [string ]string
4643}
4744
4845type defaultAZIDTranslator struct {
4946 ec2Client services.EC2
5047
48+ // zoneCache maps an account scope to its zoneMapping. Availability zone names are only
49+ // meaningful within an account, so entries for different accounts must never be shared. The
50+ // scope is empty for the cluster's own account and the assumed role ARN otherwise.
5151 zoneCache * cache.Expiring
5252 zoneCacheMutex sync.RWMutex
5353
5454 logger logr.Logger
5555}
5656
5757func (t * defaultAZIDTranslator ) TranslateAZName (ctx context.Context , assumeRoleArn string , externalId string , srcZoneName string ) (* string , error ) {
58- zoneID , err := t .resolveZoneID (ctx , srcZoneName )
58+ srcZones , err := t .fetchZoneMapping (ctx , t . ec2Client , "" )
5959 if err != nil {
6060 return nil , err
6161 }
62- if zoneID == nil {
62+ zoneID , exists := srcZones .idByName [srcZoneName ]
63+ if ! exists {
64+ t .logger .Info ("unable to resolve availability zone ID" , "zoneName" , srcZoneName )
6365 return nil , nil
6466 }
6567
6668 assumedRoleEC2 , err := t .ec2Client .AssumeRole (ctx , assumeRoleArn , externalId )
6769 if err != nil {
6870 return nil , err
6971 }
70- return t .resolveZoneName (ctx , assumedRoleEC2 , assumeRoleArn , * zoneID )
71- }
72-
73- // resolveZoneID resolves a zone name to its zone ID within the cluster's own account.
74- func (t * defaultAZIDTranslator ) resolveZoneID (ctx context.Context , zoneName string ) (* string , error ) {
75- cacheKey := zoneCacheKey {lookup : zoneName }
76- if cachedZoneID , exists := t .fetchZoneFromCache (cacheKey ); exists {
77- return & cachedZoneID , nil
78- }
79-
80- resp , err := t .ec2Client .DescribeAvailabilityZonesWithContext (ctx , & ec2sdk.DescribeAvailabilityZonesInput {
81- ZoneNames : []string {zoneName },
82- })
72+ dstZones , err := t .fetchZoneMapping (ctx , assumedRoleEC2 , assumeRoleArn )
8373 if err != nil {
8474 return nil , err
8575 }
86- for _ , azInfo := range resp .AvailabilityZones {
87- if awssdk .ToString (azInfo .ZoneName ) != zoneName {
88- continue
89- }
90- zoneID := awssdk .ToString (azInfo .ZoneId )
91- if zoneID == "" {
92- continue
93- }
94- t .saveZoneToCache (cacheKey , zoneID )
95- return & zoneID , nil
76+ zoneName , exists := dstZones .nameByID [zoneID ]
77+ if ! exists {
78+ t .logger .Info ("unable to resolve availability zone name" , "zoneID" , zoneID , "scope" , assumeRoleArn )
79+ return nil , nil
9680 }
97- t .logger .Info ("unable to resolve availability zone ID" , "zoneName" , zoneName )
98- return nil , nil
81+ return & zoneName , nil
9982}
10083
101- // resolveZoneName resolves a zone ID to the zone name used by the account reachable via ec2Client.
102- func (t * defaultAZIDTranslator ) resolveZoneName (ctx context.Context , ec2Client services.EC2 , scope string , zoneID string ) (* string , error ) {
103- cacheKey := zoneCacheKey {scope : scope , lookup : zoneID }
104- if cachedZoneName , exists := t .fetchZoneFromCache (cacheKey ); exists {
105- return & cachedZoneName , nil
84+ // fetchZoneMapping returns the availability zones visible to ec2Client, cached under scope.
85+ // The zones of an account are fetched in a single unfiltered call so that a zone missing from the
86+ // mapping is known to be unresolvable without issuing another call for it.
87+ func (t * defaultAZIDTranslator ) fetchZoneMapping (ctx context.Context , ec2Client services.EC2 , scope string ) (* zoneMapping , error ) {
88+ if cachedMapping , exists := t .fetchZoneMappingFromCache (scope ); exists {
89+ return cachedMapping , nil
10690 }
10791
108- resp , err := ec2Client .DescribeAvailabilityZonesWithContext (ctx , & ec2sdk.DescribeAvailabilityZonesInput {
109- ZoneIds : []string {zoneID },
110- })
92+ resp , err := ec2Client .DescribeAvailabilityZonesWithContext (ctx , & ec2sdk.DescribeAvailabilityZonesInput {})
11193 if err != nil {
11294 return nil , err
11395 }
96+
97+ mapping := & zoneMapping {
98+ idByName : make (map [string ]string , len (resp .AvailabilityZones )),
99+ nameByID : make (map [string ]string , len (resp .AvailabilityZones )),
100+ }
114101 for _ , azInfo := range resp .AvailabilityZones {
115- if awssdk .ToString (azInfo .ZoneId ) != zoneID {
116- continue
117- }
118102 zoneName := awssdk .ToString (azInfo .ZoneName )
119- if zoneName == "" {
103+ zoneID := awssdk .ToString (azInfo .ZoneId )
104+ if zoneName == "" || zoneID == "" {
120105 continue
121106 }
122- t . saveZoneToCache ( cacheKey , zoneName )
123- return & zoneName , nil
107+ mapping . idByName [ zoneName ] = zoneID
108+ mapping . nameByID [ zoneID ] = zoneName
124109 }
125- t .logger .Info ("unable to resolve availability zone name" , "zoneID" , zoneID , "scope" , scope )
126- return nil , nil
110+
111+ t .zoneCacheMutex .Lock ()
112+ defer t .zoneCacheMutex .Unlock ()
113+ t .zoneCache .Set (scope , mapping , defaultAZIDTranslationCacheTTL )
114+ return mapping , nil
127115}
128116
129- func (t * defaultAZIDTranslator ) fetchZoneFromCache ( key zoneCacheKey ) (string , bool ) {
117+ func (t * defaultAZIDTranslator ) fetchZoneMappingFromCache ( scope string ) (* zoneMapping , bool ) {
130118 t .zoneCacheMutex .RLock ()
131119 defer t .zoneCacheMutex .RUnlock ()
132120
133- if rawCacheItem , exists := t .zoneCache .Get (key ); exists {
134- return rawCacheItem .(string ), true
121+ if rawCacheItem , exists := t .zoneCache .Get (scope ); exists {
122+ return rawCacheItem .(* zoneMapping ), true
135123 }
136- return "" , false
137- }
138-
139- func (t * defaultAZIDTranslator ) saveZoneToCache (key zoneCacheKey , value string ) {
140- t .zoneCacheMutex .Lock ()
141- defer t .zoneCacheMutex .Unlock ()
142-
143- t .zoneCache .Set (key , value , defaultAZIDTranslationCacheTTL )
124+ return nil , false
144125}
0 commit comments