diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 0a96192976..d5880d7307 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 892c330503..f5c72e2d5c 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 0000000000..9e87197e70 --- /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 0000000000..49b1764d3f --- /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 da5f3ddef9..dadc8e423b 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 1ec90e7446..d4b391b915 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 0000000000..d72940e30e --- /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 3f03761a66..3b974d574f 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 + +