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.
This commit is contained in:
Martin Atkins 2017-06-06 17:56:31 -07:00
parent 0f113c3cc3
commit 1aff439c3d
8 changed files with 242 additions and 2 deletions

View File

@ -462,6 +462,7 @@ func Provider() terraform.ResourceProvider {
"aws_vpn_connection_route": resourceAwsVpnConnectionRoute(), "aws_vpn_connection_route": resourceAwsVpnConnectionRoute(),
"aws_vpn_gateway": resourceAwsVpnGateway(), "aws_vpn_gateway": resourceAwsVpnGateway(),
"aws_vpn_gateway_attachment": resourceAwsVpnGatewayAttachment(), "aws_vpn_gateway_attachment": resourceAwsVpnGatewayAttachment(),
"aws_vpn_gateway_route_propagation": resourceAwsVpnGatewayRoutePropagation(),
"aws_waf_byte_match_set": resourceAwsWafByteMatchSet(), "aws_waf_byte_match_set": resourceAwsWafByteMatchSet(),
"aws_waf_ipset": resourceAwsWafIPSet(), "aws_waf_ipset": resourceAwsWafIPSet(),
"aws_waf_rule": resourceAwsWafRule(), "aws_waf_rule": resourceAwsWafRule(),

View File

@ -36,6 +36,7 @@ func resourceAwsRouteTable() *schema.Resource {
"propagating_vgws": { "propagating_vgws": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString}, Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString, Set: schema.HashString,
}, },

View File

@ -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
}

View File

@ -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}"
}
`

View File

@ -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, 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. 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: ## Example usage with tags:
```hcl ```hcl

View File

@ -1,7 +1,7 @@
--- ---
layout: "aws" layout: "aws"
page_title: "AWS: aws_vpn_gateway" page_title: "AWS: aws_vpn_gateway"
sidebar_current: "docs-aws-resource-vpn-gateway" sidebar_current: "docs-aws-resource-vpn-gateway-x"
description: |- description: |-
Provides a resource to create a VPC VPN Gateway. Provides a resource to create a VPC VPN Gateway.
--- ---

View File

@ -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.

View File

@ -1475,7 +1475,7 @@
<a href="/docs/providers/aws/r/vpn_connection_route.html">aws_vpn_connection_route</a> <a href="/docs/providers/aws/r/vpn_connection_route.html">aws_vpn_connection_route</a>
</li> </li>
<li<%= sidebar_current("docs-aws-resource-vpn-gateway") %>> <li<%= sidebar_current("docs-aws-resource-vpn-gateway-x") %>>
<a href="/docs/providers/aws/r/vpn_gateway.html">aws_vpn_gateway</a> <a href="/docs/providers/aws/r/vpn_gateway.html">aws_vpn_gateway</a>
</li> </li>
@ -1483,6 +1483,10 @@
<a href="/docs/providers/aws/r/vpn_gateway_attachment.html">aws_vpn_gateway_attachment</a> <a href="/docs/providers/aws/r/vpn_gateway_attachment.html">aws_vpn_gateway_attachment</a>
</li> </li>
<li<%= sidebar_current("docs-aws-resource-vpn-gateway-route-propagation") %>>
<a href="/docs/providers/aws/r/vpn_gateway_route_propagation.html">aws_vpn_gateway_route_propagation</a>
</li>
</ul> </ul>
</li> </li>