provider/aws: Add support for IPv6 in aws_route (#12639)

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSRoute_'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/03/12 18:56:59 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSRoute_ -timeout 120m
=== RUN   TestAccAWSRoute_basic
--- PASS: TestAccAWSRoute_basic (58.46s)
=== RUN   TestAccAWSRoute_ipv6Support
--- PASS: TestAccAWSRoute_ipv6Support (48.74s)
=== RUN   TestAccAWSRoute_changeCidr
--- PASS: TestAccAWSRoute_changeCidr (90.23s)
=== RUN   TestAccAWSRoute_noopdiff
--- PASS: TestAccAWSRoute_noopdiff (138.02s)
=== RUN   TestAccAWSRoute_doesNotCrashWithVPCEndpoint
--- PASS: TestAccAWSRoute_doesNotCrashWithVPCEndpoint (63.58s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	399.054s
```
This commit is contained in:
Paul Stack 2017-03-14 12:41:40 +02:00 committed by GitHub
parent ff7df7b997
commit 1c7ea5a8af
3 changed files with 207 additions and 44 deletions

View File

@ -16,7 +16,7 @@ import (
// How long to sleep if a limit-exceeded event happens // How long to sleep if a limit-exceeded event happens
var routeTargetValidationError = errors.New("Error: more than 1 target specified. Only 1 of gateway_id, " + var routeTargetValidationError = errors.New("Error: more than 1 target specified. Only 1 of gateway_id, " +
"nat_gateway_id, instance_id, network_interface_id, route_table_id or " + "egress_only_gateway_id, nat_gateway_id, instance_id, network_interface_id, route_table_id or " +
"vpc_peering_connection_id is allowed.") "vpc_peering_connection_id is allowed.")
// AWS Route resource Schema declaration // AWS Route resource Schema declaration
@ -29,62 +29,73 @@ func resourceAwsRoute() *schema.Resource {
Exists: resourceAwsRouteExists, Exists: resourceAwsRouteExists,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"destination_cidr_block": &schema.Schema{ "destination_cidr_block": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
ForceNew: true,
},
"destination_ipv6_cidr_block": {
Type: schema.TypeString,
Optional: true,
ForceNew: true, ForceNew: true,
}, },
"destination_prefix_list_id": &schema.Schema{ "destination_prefix_list_id": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"gateway_id": &schema.Schema{ "gateway_id": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
}, },
"nat_gateway_id": &schema.Schema{ "egress_only_gateway_id": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
}, },
"instance_id": &schema.Schema{ "nat_gateway_id": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
}, },
"instance_owner_id": &schema.Schema{ "instance_id": {
Type: schema.TypeString,
Computed: true,
},
"network_interface_id": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
}, },
"origin": &schema.Schema{ "instance_owner_id": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"state": &schema.Schema{ "network_interface_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"origin": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"route_table_id": &schema.Schema{ "state": {
Type: schema.TypeString,
Computed: true,
},
"route_table_id": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"vpc_peering_connection_id": &schema.Schema{ "vpc_peering_connection_id": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
@ -97,6 +108,7 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
var numTargets int var numTargets int
var setTarget string var setTarget string
allowedTargets := []string{ allowedTargets := []string{
"egress_only_gateway_id",
"gateway_id", "gateway_id",
"nat_gateway_id", "nat_gateway_id",
"instance_id", "instance_id",
@ -125,6 +137,12 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
GatewayId: aws.String(d.Get("gateway_id").(string)), GatewayId: aws.String(d.Get("gateway_id").(string)),
} }
case "egress_only_gateway_id":
createOpts = &ec2.CreateRouteInput{
RouteTableId: aws.String(d.Get("route_table_id").(string)),
DestinationIpv6CidrBlock: aws.String(d.Get("destination_ipv6_cidr_block").(string)),
EgressOnlyInternetGatewayId: aws.String(d.Get("egress_only_gateway_id").(string)),
}
case "nat_gateway_id": case "nat_gateway_id":
createOpts = &ec2.CreateRouteInput{ createOpts = &ec2.CreateRouteInput{
RouteTableId: aws.String(d.Get("route_table_id").(string)), RouteTableId: aws.String(d.Get("route_table_id").(string)),
@ -180,13 +198,26 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
} }
var route *ec2.Route var route *ec2.Route
if v, ok := d.GetOk("destination_cidr_block"); ok {
err = resource.Retry(2*time.Minute, func() *resource.RetryError { err = resource.Retry(2*time.Minute, func() *resource.RetryError {
route, err = findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string)) route, err = findResourceRoute(conn, d.Get("route_table_id").(string), v.(string), "")
return resource.RetryableError(err) return resource.RetryableError(err)
}) })
if err != nil { if err != nil {
return fmt.Errorf("Error finding route after creating it: %s", err) return fmt.Errorf("Error finding route after creating it: %s", err)
} }
}
if v, ok := d.GetOk("destination_ipv6_cidr_block"); ok {
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
route, err = findResourceRoute(conn, d.Get("route_table_id").(string), "", v.(string))
return resource.RetryableError(err)
})
if err != nil {
return fmt.Errorf("Error finding route after creating it: %s", err)
}
}
d.SetId(routeIDHash(d, route)) d.SetId(routeIDHash(d, route))
resourceAwsRouteSetResourceData(d, route) resourceAwsRouteSetResourceData(d, route)
@ -197,7 +228,10 @@ func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn conn := meta.(*AWSClient).ec2conn
routeTableId := d.Get("route_table_id").(string) routeTableId := d.Get("route_table_id").(string)
route, err := findResourceRoute(conn, routeTableId, d.Get("destination_cidr_block").(string)) destinationCidrBlock := d.Get("destination_cidr_block").(string)
destinationIpv6CidrBlock := d.Get("destination_ipv6_cidr_block").(string)
route, err := findResourceRoute(conn, routeTableId, destinationCidrBlock, destinationIpv6CidrBlock)
if err != nil { if err != nil {
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidRouteTableID.NotFound" { if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidRouteTableID.NotFound" {
log.Printf("[WARN] Route Table %q could not be found. Removing Route from state.", log.Printf("[WARN] Route Table %q could not be found. Removing Route from state.",
@ -214,6 +248,7 @@ func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
func resourceAwsRouteSetResourceData(d *schema.ResourceData, route *ec2.Route) { func resourceAwsRouteSetResourceData(d *schema.ResourceData, route *ec2.Route) {
d.Set("destination_prefix_list_id", route.DestinationPrefixListId) d.Set("destination_prefix_list_id", route.DestinationPrefixListId)
d.Set("gateway_id", route.GatewayId) d.Set("gateway_id", route.GatewayId)
d.Set("egress_only_gateway_id", route.EgressOnlyInternetGatewayId)
d.Set("nat_gateway_id", route.NatGatewayId) d.Set("nat_gateway_id", route.NatGatewayId)
d.Set("instance_id", route.InstanceId) d.Set("instance_id", route.InstanceId)
d.Set("instance_owner_id", route.InstanceOwnerId) d.Set("instance_owner_id", route.InstanceOwnerId)
@ -229,6 +264,7 @@ func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error {
var setTarget string var setTarget string
allowedTargets := []string{ allowedTargets := []string{
"egress_only_gateway_id",
"gateway_id", "gateway_id",
"nat_gateway_id", "nat_gateway_id",
"network_interface_id", "network_interface_id",
@ -267,6 +303,12 @@ func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error {
DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
GatewayId: aws.String(d.Get("gateway_id").(string)), GatewayId: aws.String(d.Get("gateway_id").(string)),
} }
case "egress_only_gateway_id":
replaceOpts = &ec2.ReplaceRouteInput{
RouteTableId: aws.String(d.Get("route_table_id").(string)),
DestinationIpv6CidrBlock: aws.String(d.Get("destination_ipv6_cidr_block").(string)),
EgressOnlyInternetGatewayId: aws.String(d.Get("egress_only_gateway_id").(string)),
}
case "nat_gateway_id": case "nat_gateway_id":
replaceOpts = &ec2.ReplaceRouteInput{ replaceOpts = &ec2.ReplaceRouteInput{
RouteTableId: aws.String(d.Get("route_table_id").(string)), RouteTableId: aws.String(d.Get("route_table_id").(string)),
@ -310,7 +352,12 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error {
deleteOpts := &ec2.DeleteRouteInput{ deleteOpts := &ec2.DeleteRouteInput{
RouteTableId: aws.String(d.Get("route_table_id").(string)), RouteTableId: aws.String(d.Get("route_table_id").(string)),
DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), }
if v, ok := d.GetOk("destination_cidr_block"); ok {
deleteOpts.DestinationCidrBlock = aws.String(v.(string))
}
if v, ok := d.GetOk("destination_ipv6_cidr_block"); ok {
deleteOpts.DestinationIpv6CidrBlock = aws.String(v.(string))
} }
log.Printf("[DEBUG] Route delete opts: %s", deleteOpts) log.Printf("[DEBUG] Route delete opts: %s", deleteOpts)
@ -368,23 +415,37 @@ func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, err
return false, nil return false, nil
} }
cidr := d.Get("destination_cidr_block").(string) if v, ok := d.GetOk("destination_cidr_block"); ok {
for _, route := range (*res.RouteTables[0]).Routes { for _, route := range (*res.RouteTables[0]).Routes {
if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr { if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == v.(string) {
return true, nil return true, nil
} }
} }
}
if v, ok := d.GetOk("destination_ipv6_cidr_block"); ok {
for _, route := range (*res.RouteTables[0]).Routes {
if route.DestinationIpv6CidrBlock != nil && *route.DestinationIpv6CidrBlock == v.(string) {
return true, nil
}
}
}
return false, nil return false, nil
} }
// Create an ID for a route // Create an ID for a route
func routeIDHash(d *schema.ResourceData, r *ec2.Route) string { func routeIDHash(d *schema.ResourceData, r *ec2.Route) string {
if r.DestinationIpv6CidrBlock != nil && *r.DestinationIpv6CidrBlock != "" {
return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationIpv6CidrBlock))
}
return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock)) return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock))
} }
// Helper: retrieve a route // Helper: retrieve a route
func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) { func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string, ipv6cidr string) (*ec2.Route, error) {
routeTableID := rtbid routeTableID := rtbid
findOpts := &ec2.DescribeRouteTablesInput{ findOpts := &ec2.DescribeRouteTablesInput{
@ -401,6 +462,7 @@ func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, er
routeTableID) routeTableID)
} }
if cidr != "" {
for _, route := range (*resp.RouteTables[0]).Routes { for _, route := range (*resp.RouteTables[0]).Routes {
if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr { if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr {
return route, nil return route, nil
@ -410,3 +472,19 @@ func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, er
return nil, fmt.Errorf("Unable to find matching route for Route Table (%s) "+ return nil, fmt.Errorf("Unable to find matching route for Route Table (%s) "+
"and destination CIDR block (%s).", rtbid, cidr) "and destination CIDR block (%s).", rtbid, cidr)
} }
if ipv6cidr != "" {
for _, route := range (*resp.RouteTables[0]).Routes {
if route.DestinationIpv6CidrBlock != nil && *route.DestinationIpv6CidrBlock == ipv6cidr {
return route, nil
}
}
return nil, fmt.Errorf("Unable to find matching route for Route Table (%s) "+
"and destination IPv6 CIDR block (%s).", rtbid, ipv6cidr)
}
return nil, fmt.Errorf("When trying to find a matching route for Route Table %q "+
"you need to specify a CIDR block of IPv6 CIDR Block", rtbid)
}

View File

@ -38,7 +38,7 @@ func TestAccAWSRoute_basic(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy, CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSRouteBasicConfig, Config: testAccAWSRouteBasicConfig,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route), testAccCheckAWSRouteExists("aws_route.bar", &route),
@ -49,6 +49,43 @@ func TestAccAWSRoute_basic(t *testing.T) {
}) })
} }
func TestAccAWSRoute_ipv6Support(t *testing.T) {
var route ec2.Route
//aws creates a default route
testCheck := func(s *terraform.State) error {
name := "aws_egress_only_internet_gateway.foo"
gwres, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s\n", name)
}
if *route.EgressOnlyInternetGatewayId != gwres.Primary.ID {
return fmt.Errorf("Egress Only Internet Gateway Id (Expected=%s, Actual=%s)\n", gwres.Primary.ID, *route.EgressOnlyInternetGatewayId)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSRouteConfigIpv6,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route),
testCheck,
),
},
},
})
}
func TestAccAWSRoute_changeCidr(t *testing.T) { func TestAccAWSRoute_changeCidr(t *testing.T) {
var route ec2.Route var route ec2.Route
var routeTable ec2.RouteTable var routeTable ec2.RouteTable
@ -101,14 +138,14 @@ func TestAccAWSRoute_changeCidr(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy, CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSRouteBasicConfig, Config: testAccAWSRouteBasicConfig,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route), testAccCheckAWSRouteExists("aws_route.bar", &route),
testCheck, testCheck,
), ),
}, },
resource.TestStep{ {
Config: testAccAWSRouteBasicConfigChangeCidr, Config: testAccAWSRouteBasicConfigChangeCidr,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route), testAccCheckAWSRouteExists("aws_route.bar", &route),
@ -139,14 +176,14 @@ func TestAccAWSRoute_noopdiff(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy, CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSRouteNoopChange, Config: testAccAWSRouteNoopChange,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.test", &route), testAccCheckAWSRouteExists("aws_route.test", &route),
testCheck, testCheck,
), ),
}, },
resource.TestStep{ {
Config: testAccAWSRouteNoopChange, Config: testAccAWSRouteNoopChange,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.test", &route), testAccCheckAWSRouteExists("aws_route.test", &route),
@ -166,7 +203,7 @@ func TestAccAWSRoute_doesNotCrashWithVPCEndpoint(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy, CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccAWSRouteWithVPCEndpoint, Config: testAccAWSRouteWithVPCEndpoint,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route), testAccCheckAWSRouteExists("aws_route.bar", &route),
@ -192,6 +229,7 @@ func testAccCheckAWSRouteExists(n string, res *ec2.Route) resource.TestCheckFunc
conn, conn,
rs.Primary.Attributes["route_table_id"], rs.Primary.Attributes["route_table_id"],
rs.Primary.Attributes["destination_cidr_block"], rs.Primary.Attributes["destination_cidr_block"],
rs.Primary.Attributes["destination_ipv6_cidr_block"],
) )
if err != nil { if err != nil {
@ -219,6 +257,7 @@ func testAccCheckAWSRouteDestroy(s *terraform.State) error {
conn, conn,
rs.Primary.Attributes["route_table_id"], rs.Primary.Attributes["route_table_id"],
rs.Primary.Attributes["destination_cidr_block"], rs.Primary.Attributes["destination_cidr_block"],
rs.Primary.Attributes["destination_ipv6_cidr_block"],
) )
if route == nil && err == nil { if route == nil && err == nil {
@ -249,6 +288,29 @@ resource "aws_route" "bar" {
} }
`) `)
var testAccAWSRouteConfigIpv6 = fmt.Sprintf(`
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
assign_generated_ipv6_cidr_block = true
}
resource "aws_egress_only_internet_gateway" "foo" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_route_table" "foo" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_route" "bar" {
route_table_id = "${aws_route_table.foo.id}"
destination_ipv6_cidr_block = "::/0"
egress_only_gateway_id = "${aws_egress_only_internet_gateway.foo.id}"
}
`)
var testAccAWSRouteBasicConfigChangeCidr = fmt.Sprint(` var testAccAWSRouteBasicConfigChangeCidr = fmt.Sprint(`
resource "aws_vpc" "foo" { resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16" cidr_block = "10.1.0.0/16"

View File

@ -27,19 +27,40 @@ resource "aws_route" "r" {
} }
``` ```
##Example IPv6 Usage:
```
resource "aws_vpc" "vpc" {
cidr_block = "10.1.0.0/16"
assign_generated_ipv6_cidr_block = true
}
resource "aws_egress_only_internet_gateway" "egress" {
vpc_id = "${aws_vpc.vpc.id}"
}
resource "aws_route" "r" {
route_table_id = "rtb-4fbb3ac4"
destination_ipv6_cidr_block = "::/0"
egress_only_gateway_id = "${aws_egress_only_internet_gateway.egress.id}"
}
```
## Argument Reference ## Argument Reference
The following arguments are supported: The following arguments are supported:
* `route_table_id` - (Required) The ID of the routing table. * `route_table_id` - (Required) The ID of the routing table.
* `destination_cidr_block` - (Required) The destination CIDR block. * `destination_cidr_block` - (Optional) The destination CIDR block.
* `destination_ipv6_cidr_block` - (Optional) The destination IPv6 CIDR block.
* `vpc_peering_connection_id` - (Optional) An ID of a VPC peering connection. * `vpc_peering_connection_id` - (Optional) An ID of a VPC peering connection.
* `egress_only_gateway_id` - (Optional) An ID of a VPC Egress Only Internet Gateway.
* `gateway_id` - (Optional) An ID of a VPC internet gateway or a virtual private gateway. * `gateway_id` - (Optional) An ID of a VPC internet gateway or a virtual private gateway.
* `nat_gateway_id` - (Optional) An ID of a VPC NAT gateway. * `nat_gateway_id` - (Optional) An ID of a VPC NAT gateway.
* `instance_id` - (Optional) An ID of an EC2 instance. * `instance_id` - (Optional) An ID of an EC2 instance.
* `network_interface_id` - (Optional) An ID of a network interface. * `network_interface_id` - (Optional) An ID of a network interface.
Each route must contain either a `gateway_id`, a `nat_gateway_id`, an Each route must contain either a `gateway_id`, `egress_only_gateway_id` a `nat_gateway_id`, an
`instance_id` or a `vpc_peering_connection_id` or a `network_interface_id`. `instance_id` or a `vpc_peering_connection_id` or a `network_interface_id`.
Note that the default route, mapping the VPC's CIDR block to "local", is Note that the default route, mapping the VPC's CIDR block to "local", is
created implicitly and cannot be specified. created implicitly and cannot be specified.
@ -53,7 +74,9 @@ will be exported as an attribute once the resource is created.
* `route_table_id` - The ID of the routing table. * `route_table_id` - The ID of the routing table.
* `destination_cidr_block` - The destination CIDR block. * `destination_cidr_block` - The destination CIDR block.
* `destination_ipv6_cidr_block` - The destination IPv6 CIDR block.
* `vpc_peering_connection_id` - An ID of a VPC peering connection. * `vpc_peering_connection_id` - An ID of a VPC peering connection.
* `egress_only_gateway_id` - An ID of a VPC Egress Only Internet Gateway.
* `gateway_id` - An ID of a VPC internet gateway or a virtual private gateway. * `gateway_id` - An ID of a VPC internet gateway or a virtual private gateway.
* `nat_gateway_id` - An ID of a VPC NAT gateway. * `nat_gateway_id` - An ID of a VPC NAT gateway.
* `instance_id` - An ID of a NAT instance. * `instance_id` - An ID of a NAT instance.