diff --git a/.changelog/17295.txt b/.changelog/17295.txt new file mode 100644 index 000000000000..1aa7f7f378dc --- /dev/null +++ b/.changelog/17295.txt @@ -0,0 +1,3 @@ +```release-notes:enhancement +data-source/aws_route: Add `destination_prefix_list_id` attribute +``` diff --git a/aws/data_source_aws_route.go b/aws/data_source_aws_route.go index 0a3afb6225c1..c05f601dc6e0 100644 --- a/aws/data_source_aws_route.go +++ b/aws/data_source_aws_route.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" @@ -34,6 +35,12 @@ func dataSourceAwsRoute() *schema.Resource { Computed: true, }, + "destination_prefix_list_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + // // Targets. // @@ -104,7 +111,7 @@ func dataSourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { continue } - if r.DestinationPrefixListId != nil { + if r.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(r.GatewayId), "vpce-") { // Skipping because VPC endpoint routes are handled separately // See aws_vpc_endpoint continue @@ -118,6 +125,10 @@ func dataSourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { continue } + if v, ok := d.GetOk("destination_prefix_list_id"); ok && aws.StringValue(r.DestinationPrefixListId) != v.(string) { + continue + } + if v, ok := d.GetOk("carrier_gateway_id"); ok && aws.StringValue(r.CarrierGatewayId) != v.(string) { continue } @@ -171,11 +182,14 @@ func dataSourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { d.SetId(tfec2.RouteCreateID(routeTableID, destination)) } else if destination := aws.StringValue(route.DestinationIpv6CidrBlock); destination != "" { d.SetId(tfec2.RouteCreateID(routeTableID, destination)) + } else if destination := aws.StringValue(route.DestinationPrefixListId); destination != "" { + d.SetId(tfec2.RouteCreateID(routeTableID, destination)) } d.Set("carrier_gateway_id", route.CarrierGatewayId) d.Set("destination_cidr_block", route.DestinationCidrBlock) d.Set("destination_ipv6_cidr_block", route.DestinationIpv6CidrBlock) + d.Set("destination_prefix_list_id", route.DestinationPrefixListId) d.Set("egress_only_gateway_id", route.EgressOnlyInternetGatewayId) d.Set("gateway_id", route.GatewayId) d.Set("instance_id", route.InstanceId) diff --git a/aws/data_source_aws_route_test.go b/aws/data_source_aws_route_test.go index 6a6228378db0..05d71a62de93 100644 --- a/aws/data_source_aws_route_test.go +++ b/aws/data_source_aws_route_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/service/ec2" @@ -138,6 +139,58 @@ func TestAccAWSRouteDataSource_CarrierGatewayID(t *testing.T) { }) } +func TestAccAWSRouteDataSource_DestinationPrefixListId(t *testing.T) { + dataSourceName := "data.aws_route.test" + resourceName := "aws_route.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckEc2ManagedPrefixList(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRouteDataSourceConfigPrefixListNatGateway(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "destination_prefix_list_id", dataSourceName, "destination_prefix_list_id"), + resource.TestCheckResourceAttrPair(resourceName, "nat_gateway_id", dataSourceName, "nat_gateway_id"), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", dataSourceName, "route_table_id"), + ), + }, + }, + }) +} + +func TestAccAWSRouteDataSource_GatewayVpcEndpoint(t *testing.T) { + var routeTable ec2.RouteTable + var vpce ec2.VpcEndpoint + rtResourceName := "aws_route_table.test" + vpceResourceName := "aws_vpc_endpoint.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRouteDataSourceConfigGatewayVpcEndpointNoDataSource(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists(rtResourceName, &routeTable), + testAccCheckVpcEndpointExists(vpceResourceName, &vpce), + testAccCheckAWSRouteTableWaitForVpcEndpointRoute(&routeTable, &vpce), + ), + }, + { + Config: testAccAWSRouteDataSourceConfigGatewayVpcEndpointWithDataSource(rName), + ExpectError: regexp.MustCompile(`No routes matching supplied arguments found in Route Table`), + }, + }, + }) +} + func testAccDataSourceAwsRouteConfigBasic(rName string) string { return composeConfig( testAccLatestAmazonLinuxHvmEbsAmiConfig(), @@ -414,3 +467,120 @@ data "aws_route" "test" { } `, rName) } + +func testAccAWSRouteDataSourceConfigPrefixListNatGateway(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + cidr_block = "10.1.1.0/24" + vpc_id = aws_vpc.test.id + + map_public_ip_on_launch = true + + tags = { + Name = %[1]q + } +} + +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_eip" "test" { + vpc = true + + tags = { + Name = %[1]q + } +} + +resource "aws_nat_gateway" "test" { + allocation_id = aws_eip.test.id + subnet_id = aws_subnet.test.id + + tags = { + Name = %[1]q + } + + depends_on = [aws_internet_gateway.test] +} + +resource "aws_ec2_managed_prefix_list" "test" { + address_family = "IPv4" + max_entries = 1 + name = %[1]q +} + +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_route" "test" { + route_table_id = aws_route_table.test.id + destination_prefix_list_id = aws_ec2_managed_prefix_list.test.id + nat_gateway_id = aws_nat_gateway.test.id +} + +data "aws_route" "test" { + route_table_id = aws_route.test.route_table_id + destination_prefix_list_id = aws_route.test.destination_prefix_list_id + nat_gateway_id = aws_route.test.nat_gateway_id +} +`, rName) +} + +func testAccAWSRouteDataSourceConfigGatewayVpcEndpointNoDataSource(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + tags = { + Name = %[1]q + } +} + +data "aws_region" "current" {} + +resource "aws_vpc_endpoint" "test" { + vpc_id = aws_vpc.test.id + service_name = "com.amazonaws.${data.aws_region.current.name}.s3" + route_table_ids = [aws_route_table.test.id] +} + +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} +`, rName) +} + +func testAccAWSRouteDataSourceConfigGatewayVpcEndpointWithDataSource(rName string) string { + return composeConfig(testAccAWSRouteDataSourceConfigGatewayVpcEndpointNoDataSource(rName), ` +data "aws_prefix_list" "test" { + name = aws_vpc_endpoint.test.service_name +} + +data "aws_route" "test" { + route_table_id = aws_route_table.test.id + destination_prefix_list_id = data.aws_prefix_list.test.id +} + `) +} diff --git a/aws/resource_aws_default_route_table_test.go b/aws/resource_aws_default_route_table_test.go index 054960468abe..3d50ba216b45 100644 --- a/aws/resource_aws_default_route_table_test.go +++ b/aws/resource_aws_default_route_table_test.go @@ -260,7 +260,7 @@ func TestAccAWSDefaultRouteTable_IPv4_To_VpcEndpoint(t *testing.T) { destinationCidr := "0.0.0.0/0" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckElbv2GatewayLoadBalancer(t) }, ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID, "elasticloadbalancing"), Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index 00ea7daeaac1..0ed93bf05dd5 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -559,7 +559,7 @@ func TestAccAWSRouteTable_IPv4_To_VpcEndpoint(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckElbv2GatewayLoadBalancer(t) }, - ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID, "elasticloadbalancing"), Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ diff --git a/aws/resource_aws_route_test.go b/aws/resource_aws_route_test.go index bb7e29e55de9..2c48c46ef88a 100644 --- a/aws/resource_aws_route_test.go +++ b/aws/resource_aws_route_test.go @@ -1397,7 +1397,7 @@ func TestAccAWSRoute_IPv4_To_VpcEndpoint(t *testing.T) { destinationCidr := "172.16.1.0/24" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckElbv2GatewayLoadBalancer(t) }, ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID, "elasticloadbalancing"), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRouteDestroy, diff --git a/website/docs/d/route.html.markdown b/website/docs/d/route.html.markdown index bb2293c2c3a8..38d0c4fdb3f5 100644 --- a/website/docs/d/route.html.markdown +++ b/website/docs/d/route.html.markdown @@ -46,6 +46,7 @@ The following arguments are optional: * `carrier_gateway_id` - (Optional) EC2 Carrier Gateway ID of the Route belonging to the Route Table. * `destination_cidr_block` - (Optional) CIDR block of the Route belonging to the Route Table. * `destination_ipv6_cidr_block` - (Optional) IPv6 CIDR block of the Route belonging to the Route Table. +* `destination_prefix_list_id` - (Optional) The ID of a [managed prefix list](ec2_managed_prefix_list.html) destination of the Route belonging to the Route Table. * `egress_only_gateway_id` - (Optional) Egress Only Gateway ID of the Route belonging to the Route Table. * `gateway_id` - (Optional) Gateway ID of the Route belonging to the Route Table. * `instance_id` - (Optional) Instance ID of the Route belonging to the Route Table.