Skip to content

Commit

Permalink
Merge pull request #30167 from tamiros/f-route53resolver-ipv6-supp-30075
Browse files Browse the repository at this point in the history
feat: added IPv6 support to Route53 Resolver Endpoint and Forward rule
  • Loading branch information
nam054 authored Oct 9, 2024
2 parents fc125af + a6070ab commit 6c7dd89
Show file tree
Hide file tree
Showing 8 changed files with 495 additions and 34 deletions.
4 changes: 4 additions & 0 deletions .changelog/30167.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
```release-note:enhancement
resource/aws_route53_resolver_endpoint: Add `resolver_endpoint_type` argument
resource/aws_route53_resolver_rule: Add `ipv6` optional argument to the `target_ip` object
```
13 changes: 13 additions & 0 deletions internal/service/route53resolver/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ func resourceEndpoint() *schema.Resource {
Computed: true,
ValidateFunc: validation.IsIPAddress,
},
"ipv6": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsIPv6Address,
},
"ip_id": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -448,6 +454,9 @@ func expandEndpointIPAddressUpdate(vIpAddress interface{}) *awstypes.IpAddressUp
if vIp, ok := mIpAddress["ip"].(string); ok && vIp != "" {
ipAddressUpdate.Ip = aws.String(vIp)
}
if vIpv6, ok := mIpAddress["ipv6"].(string); ok && vIpv6 != "" {
ipAddressUpdate.Ipv6 = aws.String(vIpv6)
}
if vIpId, ok := mIpAddress["ip_id"].(string); ok && vIpId != "" {
ipAddressUpdate.IpId = aws.String(vIpId)
}
Expand All @@ -469,6 +478,9 @@ func expandEndpointIPAddresses(vIpAddresses *schema.Set) []awstypes.IpAddressReq
if vIp, ok := mIpAddress["ip"].(string); ok && vIp != "" {
ipAddressRequest.Ip = aws.String(vIp)
}
if vIpv6, ok := mIpAddress["ipv6"].(string); ok && vIpv6 != "" {
ipAddressRequest.Ipv6 = aws.String(vIpv6)
}

ipAddressRequests = append(ipAddressRequests, ipAddressRequest)
}
Expand All @@ -486,6 +498,7 @@ func flattenEndpointIPAddresses(ipAddresses []awstypes.IpAddressResponse) []inte
for _, ipAddress := range ipAddresses {
mIpAddress := map[string]interface{}{
names.AttrSubnetID: aws.ToString(ipAddress.SubnetId),
"ipv6": aws.ToString(ipAddress.Ipv6),
"ip": aws.ToString(ipAddress.Ip),
"ip_id": aws.ToString(ipAddress.IpId),
}
Expand Down
7 changes: 6 additions & 1 deletion internal/service/route53resolver/endpoint_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,12 @@ func dataSourceEndpointRead(ctx context.Context, d *schema.ResourceData, meta in
var ips []*string

for _, v := range ipAddresses {
ips = append(ips, v.Ip)
if v.Ip != nil {
ips = append(ips, v.Ip)
}
if v.Ipv6 != nil {
ips = append(ips, v.Ipv6)
}
}

d.Set(names.AttrIPAddresses, aws.ToStringSlice(ips))
Expand Down
127 changes: 120 additions & 7 deletions internal/service/route53resolver/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,46 @@ func TestAccRoute53ResolverEndpoint_basic(t *testing.T) {
testAccCheckEndpointExists(ctx, resourceName, &ep),
resource.TestCheckResourceAttrSet(resourceName, names.AttrARN),
resource.TestCheckResourceAttr(resourceName, "direction", "INBOUND"),
resource.TestCheckResourceAttr(resourceName, "resolver_endpoint_type", "IPV4"),
resource.TestCheckResourceAttrPair(resourceName, "host_vpc_id", vpcResourceName, names.AttrID),
resource.TestCheckResourceAttr(resourceName, "ip_address.#", acctest.Ct3),
resource.TestCheckResourceAttr(resourceName, names.AttrName, ""),
resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", acctest.Ct2),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccRoute53ResolverEndpoint_basic_ipv6(t *testing.T) {
ctx := acctest.Context(t)
var ep awstypes.ResolverEndpoint
resourceName := "aws_route53_resolver_endpoint.test"
vpcResourceName := "aws_vpc.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.Route53ResolverServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckEndpointDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccEndpointConfig_basic_ipv6(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckEndpointExists(ctx, resourceName, &ep),
resource.TestCheckResourceAttrSet(resourceName, names.AttrARN),
resource.TestCheckResourceAttr(resourceName, "direction", "INBOUND"),
resource.TestCheckResourceAttr(resourceName, "resolver_endpoint_type", "IPV6"),
resource.TestCheckResourceAttrPair(resourceName, "host_vpc_id", vpcResourceName, names.AttrID),
resource.TestCheckResourceAttr(resourceName, "ip_address.#", acctest.Ct3),
resource.TestCheckResourceAttr(resourceName, names.AttrName, ""),
resource.TestCheckResourceAttr(resourceName, "protocols.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "resolver_endpoint_type", "IPV4"),
resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", acctest.Ct2),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0),
),
Expand Down Expand Up @@ -147,6 +182,7 @@ func TestAccRoute53ResolverEndpoint_updateOutbound(t *testing.T) {
testAccCheckEndpointExists(ctx, resourceName, &ep),
resource.TestCheckResourceAttr(resourceName, "direction", "OUTBOUND"),
resource.TestCheckResourceAttr(resourceName, "ip_address.#", acctest.Ct2),
resource.TestCheckResourceAttr(resourceName, "resolver_endpoint_type", "IPV4"),
resource.TestCheckResourceAttr(resourceName, names.AttrName, initialName),
resource.TestCheckResourceAttr(resourceName, "protocols.#", acctest.Ct1),
),
Expand All @@ -156,6 +192,7 @@ func TestAccRoute53ResolverEndpoint_updateOutbound(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
testAccCheckEndpointExists(ctx, resourceName, &ep),
resource.TestCheckResourceAttr(resourceName, "direction", "OUTBOUND"),
resource.TestCheckResourceAttr(resourceName, "resolver_endpoint_type", "IPV4"),
resource.TestCheckResourceAttr(resourceName, "ip_address.#", acctest.Ct3),
resource.TestCheckResourceAttr(resourceName, names.AttrName, updatedName),
resource.TestCheckResourceAttr(resourceName, "protocols.#", acctest.Ct2),
Expand Down Expand Up @@ -265,9 +302,10 @@ func testAccPreCheck(ctx context.Context, t *testing.T) {
func testAccEndpointConfig_base(rName string) string {
return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
cidr_block = "10.0.0.0/16"
assign_generated_ipv6_cidr_block = true
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = %[1]q
Expand Down Expand Up @@ -299,11 +337,78 @@ resource "aws_security_group" "test" {
`, rName))
}

func testAccEndpointConfig_base_ipv6(rName string) string {
return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
assign_generated_ipv6_cidr_block = true
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = %[1]q
}
}
resource "aws_subnet" "test" {
count = 3
vpc_id = aws_vpc.test.id
availability_zone = data.aws_availability_zones.available.names[count.index]
ipv6_cidr_block = cidrsubnet(aws_vpc.test.ipv6_cidr_block, 8, count.index)
assign_ipv6_address_on_creation = true
ipv6_native = true
enable_resource_name_dns_aaaa_record_on_launch = true
tags = {
Name = %[1]q
}
}
resource "aws_security_group" "test" {
count = 2
vpc_id = aws_vpc.test.id
name = "%[1]s-${count.index}"
tags = {
Name = %[1]q
}
}
`, rName))
}

func testAccEndpointConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccEndpointConfig_base(rName), `
resource "aws_route53_resolver_endpoint" "test" {
direction = "INBOUND"
resolver_endpoint_type = "IPV4"
security_group_ids = aws_security_group.test[*].id
ip_address {
subnet_id = aws_subnet.test[0].id
}
ip_address {
subnet_id = aws_subnet.test[1].id
}
ip_address {
subnet_id = aws_subnet.test[2].id
}
}
`)
}

func testAccEndpointConfig_basic_ipv6(rName string) string {
return acctest.ConfigCompose(testAccEndpointConfig_base_ipv6(rName), `
resource "aws_route53_resolver_endpoint" "test" {
direction = "INBOUND"
resolver_endpoint_type = "IPV6"
security_group_ids = aws_security_group.test[*].id
ip_address {
Expand All @@ -326,6 +431,8 @@ func testAccEndpointConfig_tags1(rName, tagKey1, tagValue1 string) string {
resource "aws_route53_resolver_endpoint" "test" {
direction = "INBOUND"
resolver_endpoint_type = "IPV4"
security_group_ids = aws_security_group.test[*].id
ip_address {
Expand All @@ -352,6 +459,8 @@ func testAccEndpointConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 s
resource "aws_route53_resolver_endpoint" "test" {
direction = "INBOUND"
resolver_endpoint_type = "IPV4"
security_group_ids = aws_security_group.test[*].id
ip_address {
Expand All @@ -377,8 +486,10 @@ resource "aws_route53_resolver_endpoint" "test" {
func testAccEndpointConfig_outbound(rName, name string) string {
return acctest.ConfigCompose(testAccEndpointConfig_base(rName), fmt.Sprintf(`
resource "aws_route53_resolver_endpoint" "test" {
direction = "OUTBOUND"
name = %[1]q
direction = "OUTBOUND"
resolver_endpoint_type = "IPV4"
name = %[1]q
security_group_ids = aws_security_group.test[*].id
Expand All @@ -400,6 +511,8 @@ resource "aws_route53_resolver_endpoint" "test" {
direction = "OUTBOUND"
name = %[1]q
resolver_endpoint_type = "IPV4"
security_group_ids = aws_security_group.test[*].id
ip_address {
Expand Down
13 changes: 11 additions & 2 deletions internal/service/route53resolver/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ func resourceRule() *schema.Resource {
Schema: map[string]*schema.Schema{
"ip": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.IsIPAddress,
Optional: true,
ValidateFunc: validation.IsIPv4Address,
},
"ipv6": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.IsIPv6Address,
},
names.AttrPort: {
Type: schema.TypeInt,
Expand Down Expand Up @@ -377,6 +382,9 @@ func expandRuleTargetIPs(vTargetIps *schema.Set) []awstypes.TargetAddress {
if vIp, ok := mTargetIp["ip"].(string); ok && vIp != "" {
targetAddress.Ip = aws.String(vIp)
}
if vIpv6, ok := mTargetIp["ipv6"].(string); ok && vIpv6 != "" {
targetAddress.Ipv6 = aws.String(vIpv6)
}
if vPort, ok := mTargetIp[names.AttrPort].(int); ok {
targetAddress.Port = aws.Int32(int32(vPort))
}
Expand All @@ -400,6 +408,7 @@ func flattenRuleTargetIPs(targetAddresses []awstypes.TargetAddress) []interface{
for _, targetAddress := range targetAddresses {
mTargetIp := map[string]interface{}{
"ip": aws.ToString(targetAddress.Ip),
"ipv6": aws.ToString(targetAddress.Ipv6),
names.AttrPort: int(aws.ToInt32(targetAddress.Port)),
names.AttrProtocol: targetAddress.Protocol,
}
Expand Down
Loading

0 comments on commit 6c7dd89

Please sign in to comment.