From 7311ba22eacfcb72becf26b5e440c35fc742b44a Mon Sep 17 00:00:00 2001 From: Paul Stack Date: Tue, 14 Mar 2017 12:38:25 +0200 Subject: [PATCH] provider/aws: Add IPv6 Support to aws_route_table (#12640) ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSRouteTable_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/03/13 10:11:09 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSRouteTable_ -timeout 120m === RUN TestAccAWSRouteTable_importBasic --- PASS: TestAccAWSRouteTable_importBasic (63.14s) === RUN TestAccAWSRouteTable_complex --- PASS: TestAccAWSRouteTable_complex (241.57s) === RUN TestAccAWSRouteTable_basic --- PASS: TestAccAWSRouteTable_basic (91.26s) === RUN TestAccAWSRouteTable_instance --- PASS: TestAccAWSRouteTable_instance (158.18s) === RUN TestAccAWSRouteTable_ipv6 --- PASS: TestAccAWSRouteTable_ipv6 (48.99s) === RUN TestAccAWSRouteTable_tags --- PASS: TestAccAWSRouteTable_tags (71.68s) === RUN TestAccAWSRouteTable_vpcPeering --- PASS: TestAccAWSRouteTable_vpcPeering (58.33s) === RUN TestAccAWSRouteTable_vgwRoutePropagation --- PASS: TestAccAWSRouteTable_vgwRoutePropagation (59.64s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 780.400s ``` --- .../aws/data_source_aws_route_table.go | 16 +++ .../aws/data_source_aws_route_table_test.go | 4 +- .../providers/aws/import_aws_route_table.go | 1 + .../aws/import_aws_route_table_test.go | 8 +- .../providers/aws/resource_aws_route_table.go | 118 +++++++++++++----- .../aws/resource_aws_route_table_test.go | 63 ++++++++-- .../providers/aws/d/route_table.html.markdown | 2 + .../providers/aws/r/route_table.html.markdown | 9 +- 8 files changed, 178 insertions(+), 43 deletions(-) diff --git a/builtin/providers/aws/data_source_aws_route_table.go b/builtin/providers/aws/data_source_aws_route_table.go index 6f6667262..c332bdd91 100644 --- a/builtin/providers/aws/data_source_aws_route_table.go +++ b/builtin/providers/aws/data_source_aws_route_table.go @@ -41,6 +41,16 @@ func dataSourceAwsRouteTable() *schema.Resource { Computed: true, }, + "ipv6_cidr_block": { + Type: schema.TypeString, + Computed: true, + }, + + "egress_only_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + "gateway_id": { Type: schema.TypeString, Computed: true, @@ -177,6 +187,12 @@ func dataSourceRoutesRead(ec2Routes []*ec2.Route) []map[string]interface{} { if r.DestinationCidrBlock != nil { m["cidr_block"] = *r.DestinationCidrBlock } + if r.DestinationIpv6CidrBlock != nil { + m["ipv6_cidr_block"] = *r.DestinationIpv6CidrBlock + } + if r.EgressOnlyInternetGatewayId != nil { + m["egress_only_gateway_id"] = *r.EgressOnlyInternetGatewayId + } if r.GatewayId != nil { m["gateway_id"] = *r.GatewayId } diff --git a/builtin/providers/aws/data_source_aws_route_table_test.go b/builtin/providers/aws/data_source_aws_route_table_test.go index f459dd33b..71957541f 100644 --- a/builtin/providers/aws/data_source_aws_route_table_test.go +++ b/builtin/providers/aws/data_source_aws_route_table_test.go @@ -14,7 +14,7 @@ func TestAccDataSourceAwsRouteTable_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccDataSourceAwsRouteTableGroupConfig, Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRouteTableCheck("data.aws_route_table.by_tag"), @@ -33,7 +33,7 @@ func TestAccDataSourceAwsRouteTable_main(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccDataSourceAwsRouteTableMainRoute, Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsRouteTableCheckMain("data.aws_route_table.by_filter"), diff --git a/builtin/providers/aws/import_aws_route_table.go b/builtin/providers/aws/import_aws_route_table.go index a3ff401be..185d99411 100644 --- a/builtin/providers/aws/import_aws_route_table.go +++ b/builtin/providers/aws/import_aws_route_table.go @@ -51,6 +51,7 @@ func resourceAwsRouteTableImportState( d.SetType("aws_route") d.Set("route_table_id", id) d.Set("destination_cidr_block", route.DestinationCidrBlock) + d.Set("destination_ipv6_cidr_block", route.DestinationIpv6CidrBlock) d.SetId(routeIDHash(d, route)) results = append(results, d) } diff --git a/builtin/providers/aws/import_aws_route_table_test.go b/builtin/providers/aws/import_aws_route_table_test.go index 248bf03dd..8200bc839 100644 --- a/builtin/providers/aws/import_aws_route_table_test.go +++ b/builtin/providers/aws/import_aws_route_table_test.go @@ -23,11 +23,11 @@ func TestAccAWSRouteTable_importBasic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableConfig, }, - resource.TestStep{ + { ResourceName: "aws_route_table.foo", ImportState: true, ImportStateCheck: checkFn, @@ -51,11 +51,11 @@ func TestAccAWSRouteTable_complex(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableConfig_complexImport, }, - resource.TestStep{ + { ResourceName: "aws_route_table.mod", ImportState: true, ImportStateCheck: checkFn, diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index e8e0cb803..c92dbde16 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -25,7 +25,7 @@ func resourceAwsRouteTable() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "vpc_id": &schema.Schema{ + "vpc_id": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -33,45 +33,55 @@ func resourceAwsRouteTable() *schema.Resource { "tags": tagsSchema(), - "propagating_vgws": &schema.Schema{ + "propagating_vgws": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, - "route": &schema.Schema{ + "route": { Type: schema.TypeSet, Computed: true, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "cidr_block": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - - "gateway_id": &schema.Schema{ + "cidr_block": { Type: schema.TypeString, Optional: true, }, - "instance_id": &schema.Schema{ + "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, }, - "nat_gateway_id": &schema.Schema{ + "egress_only_gateway_id": { Type: schema.TypeString, Optional: true, }, - "vpc_peering_connection_id": &schema.Schema{ + "gateway_id": { Type: schema.TypeString, Optional: true, }, - "network_interface_id": &schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Optional: true, + }, + + "nat_gateway_id": { + Type: schema.TypeString, + Optional: true, + }, + + "vpc_peering_connection_id": { + Type: schema.TypeString, + Optional: true, + }, + + "network_interface_id": { Type: schema.TypeString, Optional: true, }, @@ -166,6 +176,12 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { if r.DestinationCidrBlock != nil { m["cidr_block"] = *r.DestinationCidrBlock } + if r.DestinationIpv6CidrBlock != nil { + m["ipv6_cidr_block"] = *r.DestinationIpv6CidrBlock + } + if r.EgressOnlyInternetGatewayId != nil { + m["egress_only_gateway_id"] = *r.EgressOnlyInternetGatewayId + } if r.GatewayId != nil { m["gateway_id"] = *r.GatewayId } @@ -266,14 +282,27 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error for _, route := range ors.List() { m := route.(map[string]interface{}) - // Delete the route as it no longer exists in the config - log.Printf( - "[INFO] Deleting route from %s: %s", - d.Id(), m["cidr_block"].(string)) - _, err := conn.DeleteRoute(&ec2.DeleteRouteInput{ - RouteTableId: aws.String(d.Id()), - DestinationCidrBlock: aws.String(m["cidr_block"].(string)), - }) + deleteOpts := &ec2.DeleteRouteInput{ + RouteTableId: aws.String(d.Id()), + } + + if s := m["ipv6_cidr_block"].(string); s != "" { + deleteOpts.DestinationIpv6CidrBlock = aws.String(s) + + log.Printf( + "[INFO] Deleting route from %s: %s", + d.Id(), m["ipv6_cidr_block"].(string)) + } + + if s := m["cidr_block"].(string); s != "" { + deleteOpts.DestinationCidrBlock = aws.String(s) + + log.Printf( + "[INFO] Deleting route from %s: %s", + d.Id(), m["cidr_block"].(string)) + } + + _, err := conn.DeleteRoute(deleteOpts) if err != nil { return err } @@ -288,16 +317,39 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error m := route.(map[string]interface{}) opts := ec2.CreateRouteInput{ - RouteTableId: aws.String(d.Id()), - DestinationCidrBlock: aws.String(m["cidr_block"].(string)), - GatewayId: aws.String(m["gateway_id"].(string)), - InstanceId: aws.String(m["instance_id"].(string)), - VpcPeeringConnectionId: aws.String(m["vpc_peering_connection_id"].(string)), - NetworkInterfaceId: aws.String(m["network_interface_id"].(string)), + RouteTableId: aws.String(d.Id()), } - if m["nat_gateway_id"].(string) != "" { - opts.NatGatewayId = aws.String(m["nat_gateway_id"].(string)) + if s := m["vpc_peering_connection_id"].(string); s != "" { + opts.VpcPeeringConnectionId = aws.String(s) + } + + if s := m["network_interface_id"].(string); s != "" { + opts.NetworkInterfaceId = aws.String(s) + } + + if s := m["instance_id"].(string); s != "" { + opts.InstanceId = aws.String(s) + } + + if s := m["ipv6_cidr_block"].(string); s != "" { + opts.DestinationIpv6CidrBlock = aws.String(s) + } + + if s := m["cidr_block"].(string); s != "" { + opts.DestinationCidrBlock = aws.String(s) + } + + if s := m["gateway_id"].(string); s != "" { + opts.GatewayId = aws.String(s) + } + + if s := m["egress_only_gateway_id"].(string); s != "" { + opts.EgressOnlyInternetGatewayId = aws.String(s) + } + + if s := m["nat_gateway_id"].(string); s != "" { + opts.NatGatewayId = aws.String(s) } log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts) @@ -402,6 +454,10 @@ func resourceAwsRouteTableHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) + if v, ok := m["ipv6_cidr_block"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["cidr_block"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } @@ -410,6 +466,10 @@ func resourceAwsRouteTableHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } + if v, ok := m["egress_only_gateway_id"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + natGatewaySet := false if v, ok := m["nat_gateway_id"]; ok { natGatewaySet = v.(string) != "" diff --git a/builtin/providers/aws/resource_aws_route_table_test.go b/builtin/providers/aws/resource_aws_route_table_test.go index 910f8c013..68fd9237b 100644 --- a/builtin/providers/aws/resource_aws_route_table_test.go +++ b/builtin/providers/aws/resource_aws_route_table_test.go @@ -63,7 +63,7 @@ func TestAccAWSRouteTable_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableConfig, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists( @@ -72,7 +72,7 @@ func TestAccAWSRouteTable_basic(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccRouteTableConfigChange, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists( @@ -113,7 +113,7 @@ func TestAccAWSRouteTable_instance(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableConfigInstance, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists( @@ -125,6 +125,35 @@ func TestAccAWSRouteTable_instance(t *testing.T) { }) } +func TestAccAWSRouteTable_ipv6(t *testing.T) { + var v ec2.RouteTable + + testCheck := func(*terraform.State) error { + // Expect 3: 2 IPv6 (local + all outbound) + 1 IPv4 + if len(v.Routes) != 3 { + return fmt.Errorf("bad routes: %#v", v.Routes) + } + + return nil + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_route_table.foo", + Providers: testAccProviders, + CheckDestroy: testAccCheckRouteTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRouteTableConfigIpv6, + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists("aws_route_table.foo", &v), + testCheck, + ), + }, + }, + }) +} + func TestAccAWSRouteTable_tags(t *testing.T) { var route_table ec2.RouteTable @@ -134,7 +163,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableConfigTags, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists("aws_route_table.foo", &route_table), @@ -142,7 +171,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) { ), }, - resource.TestStep{ + { Config: testAccRouteTableConfigTagsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists("aws_route_table.foo", &route_table), @@ -244,7 +273,7 @@ func TestAccAWSRouteTable_vpcPeering(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckRouteTableDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableVpcPeeringConfig, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists( @@ -285,7 +314,7 @@ func TestAccAWSRouteTable_vgwRoutePropagation(t *testing.T) { testAccCheckRouteTableDestroy, ), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccRouteTableVgwRoutePropagationConfig, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists( @@ -342,6 +371,26 @@ resource "aws_route_table" "foo" { } ` +const testAccRouteTableConfigIpv6 = ` +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}" + + route { + ipv6_cidr_block = "::/0" + egress_only_gateway_id = "${aws_egress_only_internet_gateway.foo.id}" + } +} +` + const testAccRouteTableConfigInstance = ` resource "aws_vpc" "foo" { cidr_block = "10.1.0.0/16" diff --git a/website/source/docs/providers/aws/d/route_table.html.markdown b/website/source/docs/providers/aws/d/route_table.html.markdown index 09ed6aa28..e8e17e4fe 100644 --- a/website/source/docs/providers/aws/d/route_table.html.markdown +++ b/website/source/docs/providers/aws/d/route_table.html.markdown @@ -71,6 +71,8 @@ the selected Route Table. Each route supports the following: * `cidr_block` - The CIDR block of the route. +* `ipv6_cidr_block` - The IPv6 CIDR block of the route. +* `egress_only_gateway_id` - The ID of the Egress Only Internet Gateway. * `gateway_id` - The Internet Gateway ID. * `nat_gateway_id` - The NAT Gateway ID. * `instance_id` - The EC2 instance ID. diff --git a/website/source/docs/providers/aws/r/route_table.html.markdown b/website/source/docs/providers/aws/r/route_table.html.markdown index 679dbe2da..f8e79d6fa 100644 --- a/website/source/docs/providers/aws/r/route_table.html.markdown +++ b/website/source/docs/providers/aws/r/route_table.html.markdown @@ -27,6 +27,11 @@ resource "aws_route_table" "r" { gateway_id = "${aws_internet_gateway.main.id}" } + route { + ipv6_cidr_block = "::/0" + egress_only_gateway_id = "${aws_egress_only_internet_gateway.foo.id}" + } + tags { Name = "main" } @@ -44,7 +49,9 @@ The following arguments are supported: Each route supports the following: -* `cidr_block` - (Required) The CIDR block of the route. +* `cidr_block` - (Optional) The CIDR block of the route. +* `ipv6_cidr_block` - Optional) The Ipv6 CIDR block of the route +* `egress_only_gateway_id` - (Optional) The Egress Only Internet Gateway ID. * `gateway_id` - (Optional) The Internet Gateway ID. * `nat_gateway_id` - (Optional) The NAT Gateway ID. * `instance_id` - (Optional) The EC2 instance ID.