From 1aff439c3db62a4d80b42ed064a8c322fbc302d0 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Tue, 6 Jun 2017 17:56:31 -0700 Subject: [PATCH] provider/aws: aws_vpn_gateway_route_propagation resource This is a separate resource that serves a similar purpose to the propagating_vgws argument on aws_route_table, but allows route propagations to be created independently of the route table, which in turn allows the VPN gateway to be created after the route table it will contribute to, possibly in a separate Terraform module. To make this work, propagating_vgws on aws_route_table is now marked as Computed, meaning that it won't try to delete any existing propagation edges if there is no setting for it in configuration at all. This allows the user to choose whether to use the argument or the separate resource, though using both together will not work, as explained in the docs. --- builtin/providers/aws/provider.go | 1 + .../providers/aws/resource_aws_route_table.go | 1 + ...ource_aws_vpn_gateway_route_propagation.go | 102 ++++++++++++++++++ ..._aws_vpn_gateway_route_propagation_test.go | 90 ++++++++++++++++ .../providers/aws/r/route_table.html.markdown | 7 ++ .../providers/aws/r/vpn_gateway.html.markdown | 2 +- ...pn_gateway_route_propagation.html.markdown | 35 ++++++ website/source/layouts/aws.erb | 6 +- 8 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 builtin/providers/aws/resource_aws_vpn_gateway_route_propagation.go create mode 100644 builtin/providers/aws/resource_aws_vpn_gateway_route_propagation_test.go create mode 100644 website/source/docs/providers/aws/r/vpn_gateway_route_propagation.html.markdown diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 0a961929767c..d5880d730791 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -462,6 +462,7 @@ func Provider() terraform.ResourceProvider { "aws_vpn_connection_route": resourceAwsVpnConnectionRoute(), "aws_vpn_gateway": resourceAwsVpnGateway(), "aws_vpn_gateway_attachment": resourceAwsVpnGatewayAttachment(), + "aws_vpn_gateway_route_propagation": resourceAwsVpnGatewayRoutePropagation(), "aws_waf_byte_match_set": resourceAwsWafByteMatchSet(), "aws_waf_ipset": resourceAwsWafIPSet(), "aws_waf_rule": resourceAwsWafRule(), diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index 892c330503a7..f5c72e2d5cfb 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -36,6 +36,7 @@ func resourceAwsRouteTable() *schema.Resource { "propagating_vgws": { Type: schema.TypeSet, Optional: true, + Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, diff --git a/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation.go b/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation.go new file mode 100644 index 000000000000..9e87197e7039 --- /dev/null +++ b/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation.go @@ -0,0 +1,102 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsVpnGatewayRoutePropagation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsVpnGatewayRoutePropagationEnable, + Read: resourceAwsVpnGatewayRoutePropagationRead, + Delete: resourceAwsVpnGatewayRoutePropagationDisable, + + Schema: map[string]*schema.Schema{ + "vpn_gateway_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "route_table_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsVpnGatewayRoutePropagationEnable(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + gwID := d.Get("vpn_gateway_id").(string) + rtID := d.Get("route_table_id").(string) + + log.Printf("[INFO] Enabling VGW propagation from %s to %s", gwID, rtID) + _, err := conn.EnableVgwRoutePropagation(&ec2.EnableVgwRoutePropagationInput{ + GatewayId: aws.String(gwID), + RouteTableId: aws.String(rtID), + }) + if err != nil { + return fmt.Errorf("error enabling VGW propagation: %s", err) + } + + d.SetId(fmt.Sprintf("%s_%s", gwID, rtID)) + return nil +} + +func resourceAwsVpnGatewayRoutePropagationDisable(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + gwID := d.Get("vpn_gateway_id").(string) + rtID := d.Get("route_table_id").(string) + + log.Printf("[INFO] Disabling VGW propagation from %s to %s", gwID, rtID) + _, err := conn.DisableVgwRoutePropagation(&ec2.DisableVgwRoutePropagationInput{ + GatewayId: aws.String(gwID), + RouteTableId: aws.String(rtID), + }) + if err != nil { + return fmt.Errorf("error disabling VGW propagation: %s", err) + } + + d.SetId("") + return nil +} + +func resourceAwsVpnGatewayRoutePropagationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + gwID := d.Get("vpn_gateway_id").(string) + rtID := d.Get("route_table_id").(string) + + log.Printf("[INFO] Reading route table %s to check for VPN gateway %s", rtID, gwID) + rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(conn, rtID)() + if err != nil { + return err + } + if rtRaw == nil { + log.Printf("[INFO] Route table %d doesn't exist, so dropping %s route propagation from state", rtID, gwID) + d.SetId("") + return nil + } + + rt := rtRaw.(*ec2.RouteTable) + exists := false + for _, vgw := range rt.PropagatingVgws { + if *vgw.GatewayId == gwID { + exists = true + } + } + if !exists { + log.Printf("[INFO] %s is no longer propagating to %s, so dropping route propagation from state", rtID, gwID) + d.SetId("") + return nil + } + + return nil +} diff --git a/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation_test.go b/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation_test.go new file mode 100644 index 000000000000..49b1764d3f33 --- /dev/null +++ b/builtin/providers/aws/resource_aws_vpn_gateway_route_propagation_test.go @@ -0,0 +1,90 @@ +package aws + +import ( + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSVPNGatewayRoutePropagation_basic(t *testing.T) { + var rtID, gwID string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_vpn_gateway_route_propagation.foo", + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSVPNGatewayRoutePropagation_basic, + Check: func(state *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + rs := state.RootModule().Resources["aws_vpn_gateway_route_propagation.foo"] + if rs == nil { + return errors.New("missing resource state") + } + + rtID = rs.Primary.Attributes["route_table_id"] + gwID = rs.Primary.Attributes["vpn_gateway_id"] + + rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(conn, rtID)() + if err != nil { + return fmt.Errorf("failed to read route table: %s", err) + } + if rtRaw == nil { + return errors.New("route table doesn't exist") + } + + rt := rtRaw.(*ec2.RouteTable) + exists := false + for _, vgw := range rt.PropagatingVgws { + if *vgw.GatewayId == gwID { + exists = true + } + } + if !exists { + return errors.New("route table does not list VPN gateway as a propagator") + } + + return nil + }, + }, + }, + CheckDestroy: func(state *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(conn, rtID)() + if err != nil { + return fmt.Errorf("failed to read route table: %s", err) + } + if rtRaw != nil { + return errors.New("route table still exists") + } + return nil + }, + }) + +} + +const testAccAWSVPNGatewayRoutePropagation_basic = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" +} + +resource "aws_vpn_gateway" "foo" { + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_route_table" "foo" { + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_vpn_gateway_route_propagation" "foo" { + vpn_gateway_id = "${aws_vpn_gateway.foo.id}" + route_table_id = "${aws_route_table.foo.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 da5f3ddef98f..dadc8e423bfd 100644 --- a/website/source/docs/providers/aws/r/route_table.html.markdown +++ b/website/source/docs/providers/aws/r/route_table.html.markdown @@ -22,6 +22,13 @@ This _will_ lead to a permanent diff between your configuration and statefile, a parameters in the returned route table. If you're experiencing constant diffs in your `aws_route_table` resources, the first thing to check is whether or not you're specifying a NAT ID instead of a Gateway ID, or vice-versa. +~> **NOTE on `propagating_vgws` and the `aws_vpn_gateway_route_propagation` resource:** +If the `propagating_vgws` argument is present, it's not supported to _also_ +define route propagations using `aws_vpn_gateway_route_propagation`, since +this resource will delete any propagating gateways not explicitly listed in +`propagating_vgws`. Omit this argument when defining route propagation using +the separate resource. + ## Example usage with tags: ```hcl diff --git a/website/source/docs/providers/aws/r/vpn_gateway.html.markdown b/website/source/docs/providers/aws/r/vpn_gateway.html.markdown index 1ec90e74463a..d4b391b9158f 100644 --- a/website/source/docs/providers/aws/r/vpn_gateway.html.markdown +++ b/website/source/docs/providers/aws/r/vpn_gateway.html.markdown @@ -1,7 +1,7 @@ --- layout: "aws" page_title: "AWS: aws_vpn_gateway" -sidebar_current: "docs-aws-resource-vpn-gateway" +sidebar_current: "docs-aws-resource-vpn-gateway-x" description: |- Provides a resource to create a VPC VPN Gateway. --- diff --git a/website/source/docs/providers/aws/r/vpn_gateway_route_propagation.html.markdown b/website/source/docs/providers/aws/r/vpn_gateway_route_propagation.html.markdown new file mode 100644 index 000000000000..d72940e30e46 --- /dev/null +++ b/website/source/docs/providers/aws/r/vpn_gateway_route_propagation.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "aws" +page_title: "AWS: aws_vpn_gateway_route_propagation" +sidebar_current: "docs-aws-resource-vpn-gateway-route-propagation" +description: |- + Requests automatic route propagation between a VPN gateway and a route table. +--- + +# aws_vpn_gateway_route_propagation + +Requests automatic route propagation between a VPN gateway and a route table. + +~> **Note:** This resource should not be used with a route table that has +the `propagating_vgws` argument set. If that argument is set, any route +propagation not explicitly listed in its value will be removed. + +## Example Usage + +```hcl +resource "aws_vpn_gateway_route_propagation" "example" { + vpn_gateway_id = "${aws_vpn_gateway.example.id}" + route_table_id = "${aws_route_table.example.id}" +} +``` + +## Argument Reference + +The following arguments are required: + +* `vpn_gateway_id` - The id of the `aws_vpn_gateway` to propagate routes from. +* `route_table_id` - The id of the `aws_route_table` to propagate routes into. + +## Attributes Reference + +This resource does not export any additional attributes. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 3f03761a66a2..3b974d574fc6 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -1475,7 +1475,7 @@ aws_vpn_connection_route - > + > aws_vpn_gateway @@ -1483,6 +1483,10 @@ aws_vpn_gateway_attachment + > + aws_vpn_gateway_route_propagation + +