Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions pkg/networking/subnet_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ func (r *defaultSubnetsResolver) ResolveViaNameOrIDSlice(ctx context.Context, su
}

// listSubnetsByNameOrIDs lists subnets within vpc matching given ID or name.
// The returned subnets will be in the same order as the input subnetNameOrIDs slice.
func (r *defaultSubnetsResolver) listSubnetsByNameOrIDs(ctx context.Context, subnetNameOrIDs []string) ([]ec2types.Subnet, error) {
var subnetIDs []string
var subnetNames []string
Expand All @@ -250,21 +251,57 @@ func (r *defaultSubnetsResolver) listSubnetsByNameOrIDs(ctx context.Context, sub
subnetNames = append(subnetNames, nameOrID)
}
}
var resolvedSubnets []ec2types.Subnet

subnetByID := make(map[string]ec2types.Subnet)
subnetByName := make(map[string]ec2types.Subnet)

if len(subnetIDs) > 0 {
subnets, err := r.listSubnetsByIDs(ctx, subnetIDs)
if err != nil {
return nil, err
}
resolvedSubnets = append(resolvedSubnets, subnets...)
for _, subnet := range subnets {
subnetByID[awssdk.ToString(subnet.SubnetId)] = subnet
}
}
if len(subnetNames) > 0 {
subnets, err := r.listSubnetsByNames(ctx, subnetNames)
if err != nil {
return nil, err
}
resolvedSubnets = append(resolvedSubnets, subnets...)
for _, subnet := range subnets {
// Extract the Name tag value for mapping
var subnetName string
for _, tag := range subnet.Tags {
if awssdk.ToString(tag.Key) == "Name" {
subnetName = awssdk.ToString(tag.Value)
break
}
}
if subnetName != "" {
subnetByName[subnetName] = subnet
}
}
}

// Reconstruct the subnet list in the original requested order
resolvedSubnets := make([]ec2types.Subnet, 0, len(subnetNameOrIDs))
for _, nameOrID := range subnetNameOrIDs {
if strings.HasPrefix(nameOrID, "subnet-") {
if subnet, ok := subnetByID[nameOrID]; ok {
resolvedSubnets = append(resolvedSubnets, subnet)
} else {
return nil, fmt.Errorf("subnet ID not found: %s", nameOrID)
}
} else {
if subnet, ok := subnetByName[nameOrID]; ok {
resolvedSubnets = append(resolvedSubnets, subnet)
} else {
return nil, fmt.Errorf("subnet with Name tag not found: %s", nameOrID)
}
}
}

return resolvedSubnets, nil
}

Expand Down
135 changes: 135 additions & 0 deletions pkg/networking/subnet_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2246,13 +2246,25 @@ func Test_defaultSubnetsResolver_ResolveViaNameOrIDSlice(t *testing.T) {
AvailabilityZoneId: awssdk.String("usw2-az1"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-1"),
},
},
},
{
SubnetId: awssdk.String("subnet-2"),
AvailabilityZone: awssdk.String("us-west-2b"),
AvailabilityZoneId: awssdk.String("usw2-az2"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-2"),
},
},
},
},
},
Expand Down Expand Up @@ -2292,13 +2304,25 @@ func Test_defaultSubnetsResolver_ResolveViaNameOrIDSlice(t *testing.T) {
AvailabilityZoneId: awssdk.String("usw2-az1"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-1"),
},
},
},
{
SubnetId: awssdk.String("subnet-2"),
AvailabilityZone: awssdk.String("us-west-2b"),
AvailabilityZoneId: awssdk.String("usw2-az2"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-2"),
},
},
},
},
},
Expand Down Expand Up @@ -2343,6 +2367,12 @@ func Test_defaultSubnetsResolver_ResolveViaNameOrIDSlice(t *testing.T) {
AvailabilityZoneId: awssdk.String("usw2-az2"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-2"),
},
},
},
},
},
Expand Down Expand Up @@ -2376,6 +2406,111 @@ func Test_defaultSubnetsResolver_ResolveViaNameOrIDSlice(t *testing.T) {
},
},
want: []ec2types.Subnet{
{
SubnetId: awssdk.String("subnet-1"),
AvailabilityZone: awssdk.String("us-west-2a"),
AvailabilityZoneId: awssdk.String("usw2-az1"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
},
{
SubnetId: awssdk.String("subnet-2"),
AvailabilityZone: awssdk.String("us-west-2b"),
AvailabilityZoneId: awssdk.String("usw2-az2"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
Tags: []ec2types.Tag{
{
Key: awssdk.String("Name"),
Value: awssdk.String("name-2"),
},
},
},
},
},
{
name: "order is preserved when AWS returns subnets in different order",
fields: fields{
clusterTagCheckEnabled: true,
albSingleSubnetEnabled: false,
discoveryByReachabilityEnabled: true,
describeSubnetsAsListCalls: []describeSubnetsAsListCall{
{
input: &ec2sdk.DescribeSubnetsInput{
SubnetIds: []string{"subnet-3", "subnet-1", "subnet-2"},
},
// AWS returns in different order than requested
output: []ec2types.Subnet{
{
SubnetId: awssdk.String("subnet-1"),
AvailabilityZone: awssdk.String("us-west-2a"),
AvailabilityZoneId: awssdk.String("usw2-az1"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
},
{
SubnetId: awssdk.String("subnet-2"),
AvailabilityZone: awssdk.String("us-west-2b"),
AvailabilityZoneId: awssdk.String("usw2-az2"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
},
{
SubnetId: awssdk.String("subnet-3"),
AvailabilityZone: awssdk.String("us-west-2c"),
AvailabilityZoneId: awssdk.String("usw2-az3"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
},
},
},
},
fetchAZInfosCalls: []fetchAZInfosCall{
{
availabilityZoneIDs: []string{"usw2-az3"},
azInfoByAZID: map[string]ec2types.AvailabilityZone{
"usw2-az3": {
ZoneId: awssdk.String("usw2-az3"),
ZoneType: awssdk.String("availability-zone"),
},
},
},
{
availabilityZoneIDs: []string{"usw2-az1"},
azInfoByAZID: map[string]ec2types.AvailabilityZone{
"usw2-az1": {
ZoneId: awssdk.String("usw2-az1"),
ZoneType: awssdk.String("availability-zone"),
},
},
},
{
availabilityZoneIDs: []string{"usw2-az2"},
azInfoByAZID: map[string]ec2types.AvailabilityZone{
"usw2-az2": {
ZoneId: awssdk.String("usw2-az2"),
ZoneType: awssdk.String("availability-zone"),
},
},
},
},
},
args: args{
nameOrIDs: []string{"subnet-3", "subnet-1", "subnet-2"},
opts: []SubnetsResolveOption{
WithSubnetsResolveLBType(elbv2model.LoadBalancerTypeApplication),
WithSubnetsResolveLBScheme(elbv2model.LoadBalancerSchemeInternetFacing),
},
},
// Expected result must be in the requested order, not AWS's order
want: []ec2types.Subnet{
{
SubnetId: awssdk.String("subnet-3"),
AvailabilityZone: awssdk.String("us-west-2c"),
AvailabilityZoneId: awssdk.String("usw2-az3"),
AvailableIpAddressCount: awssdk.Int32(8),
VpcId: awssdk.String("vpc-dummy"),
},
{
SubnetId: awssdk.String("subnet-1"),
AvailabilityZone: awssdk.String("us-west-2a"),
Expand Down