Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for VPN connection routes #1793

Merged
merged 3 commits into from
May 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func Provider() terraform.ResourceProvider {
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
"aws_vpn_connection": resourceAwsVpnConnection(),
"aws_vpn_connection_route": resourceAwsVpnConnectionRoute(),
"aws_vpn_gateway": resourceAwsVpnGateway(),
},

Expand Down
135 changes: 135 additions & 0 deletions builtin/providers/aws/resource_vpn_connection_route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package aws

import (
"fmt"
"log"
"strings"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/ec2"

"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpnConnectionRoute() *schema.Resource {
return &schema.Resource{
// You can't update a route. You can just delete one and make
// a new one.
Create: resourceAwsVpnConnectionRouteCreate,
Update: resourceAwsVpnConnectionRouteCreate,

Read: resourceAwsVpnConnectionRouteRead,
Delete: resourceAwsVpnConnectionRouteDelete,

Schema: map[string]*schema.Schema{
"destination_cidr_block": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"vpn_connection_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func resourceAwsVpnConnectionRouteCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn

createOpts := &ec2.CreateVPNConnectionRouteInput{
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
VPNConnectionID: aws.String(d.Get("vpn_connection_id").(string)),
}

// Create the route.
log.Printf("[DEBUG] Creating VPN connection route")
_, err := conn.CreateVPNConnectionRoute(createOpts)
if err != nil {
return fmt.Errorf("Error creating VPN connection route: %s", err)
}

// Store the ID by the only two data we have available to us.
d.SetId(fmt.Sprintf("%s:%s", *createOpts.DestinationCIDRBlock, *createOpts.VPNConnectionID))

return resourceAwsVpnConnectionRouteRead(d, meta)
}

func resourceAwsVpnConnectionRouteRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn

cidrBlock, vpnConnectionId := resourceAwsVpnConnectionRouteParseId(d.Id())

routeFilters := []*ec2.Filter{
&ec2.Filter{
Name: aws.String("route.destination-cidr-block"),
Values: []*string{aws.String(cidrBlock)},
},
&ec2.Filter{
Name: aws.String("vpn-connection-id"),
Values: []*string{aws.String(vpnConnectionId)},
},
}

// Technically, we know everything there is to know about the route
// from its ID, but we still want to catch cases where it changes
// outside of terraform and results in a stale state file. Hence,
// conduct a read.
resp, err := conn.DescribeVPNConnections(&ec2.DescribeVPNConnectionsInput{
Filters: routeFilters,
})
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpnConnectionID.NotFound" {
d.SetId("")
return nil
} else {
log.Printf("[ERROR] Error finding VPN connection route: %s", err)
return err
}
}

vpnConnection := resp.VPNConnections[0]

var found bool
for _, r := range vpnConnection.Routes {
if *r.DestinationCIDRBlock == cidrBlock {
d.Set("destination_cidr_block", *r.DestinationCIDRBlock)
d.Set("vpn_connection_id", *vpnConnection.VPNConnectionID)
found = true
}
}
if !found {
// Something other than terraform eliminated the route.
d.SetId("")
}

return nil
}

func resourceAwsVpnConnectionRouteDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn

_, err := conn.DeleteVPNConnectionRoute(&ec2.DeleteVPNConnectionRouteInput{
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
VPNConnectionID: aws.String(d.Get("vpn_connection_id").(string)),
})
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpnConnectionID.NotFound" {
d.SetId("")
return nil
} else {
log.Printf("[ERROR] Error deleting VPN connection route: %s", err)
return err
}
}

return nil
}

func resourceAwsVpnConnectionRouteParseId(id string) (string, string) {
parts := strings.SplitN(id, ":", 2)
return parts[0], parts[1]
}
150 changes: 150 additions & 0 deletions builtin/providers/aws/resource_vpn_connection_route_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package aws

import (
"fmt"
"testing"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/ec2"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAwsVpnConnectionRoute(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccAwsVpnConnectionRouteDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAwsVpnConnectionRouteConfig,
Check: resource.ComposeTestCheckFunc(
testAccAwsVpnConnectionRoute(
"aws_vpn_gateway.vpn_gateway",
"aws_customer_gateway.customer_gateway",
"aws_vpn_connection.vpn_connection",
"aws_vpn_connection_route.foo",
),
),
},
resource.TestStep{
Config: testAccAwsVpnConnectionRouteConfigUpdate,
Check: resource.ComposeTestCheckFunc(
testAccAwsVpnConnectionRoute(
"aws_vpn_gateway.vpn_gateway",
"aws_customer_gateway.customer_gateway",
"aws_vpn_connection.vpn_connection",
"aws_vpn_connection_route.foo",
),
),
},
},
})
}

func testAccAwsVpnConnectionRouteDestroy(s *terraform.State) error {
if len(s.RootModule().Resources) > 0 {
return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources)
}

return nil
}

func testAccAwsVpnConnectionRoute(
vpnGatewayResource string,
customerGatewayResource string,
vpnConnectionResource string,
vpnConnectionRouteResource string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[vpnConnectionRouteResource]
if !ok {
return fmt.Errorf("Not found: %s", vpnConnectionRouteResource)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
route, ok := s.RootModule().Resources[vpnConnectionRouteResource]
if !ok {
return fmt.Errorf("Not found: %s", vpnConnectionRouteResource)
}

cidrBlock, vpnConnectionId := resourceAwsVpnConnectionRouteParseId(route.Primary.ID)

routeFilters := []*ec2.Filter{
&ec2.Filter{
Name: aws.String("route.destination-cidr-block"),
Values: []*string{aws.String(cidrBlock)},
},
&ec2.Filter{
Name: aws.String("vpn-connection-id"),
Values: []*string{aws.String(vpnConnectionId)},
},
}

ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn

_, err := ec2conn.DescribeVPNConnections(&ec2.DescribeVPNConnectionsInput{
Filters: routeFilters,
})
if err != nil {
return err
}

return nil
}
}

const testAccAwsVpnConnectionRouteConfig = `
resource "aws_vpn_gateway" "vpn_gateway" {
tags {
Name = "vpn_gateway"
}
}
resource "aws_customer_gateway" "customer_gateway" {
bgp_asn = 60000
ip_address = "182.0.0.1"
type = "ipsec.1"
}
resource "aws_vpn_connection" "vpn_connection" {
vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
type = "ipsec.1"
static_routes_only = true
}
resource "aws_vpn_connection_route" "foo" {
destination_cidr_block = "172.168.10.0/24"
vpn_connection_id = "${aws_vpn_connection.vpn_connection.id}"
}
`

// Change destination_cidr_block
const testAccAwsVpnConnectionRouteConfigUpdate = `
resource "aws_vpn_gateway" "vpn_gateway" {
tags {
Name = "vpn_gateway"
}
}
resource "aws_customer_gateway" "customer_gateway" {
bgp_asn = 60000
ip_address = "182.0.0.1"
type = "ipsec.1"
}
resource "aws_vpn_connection" "vpn_connection" {
vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
type = "ipsec.1"
static_routes_only = true
}
resource "aws_vpn_connection_route" "foo" {
destination_cidr_block = "172.168.20.0/24"
vpn_connection_id = "${aws_vpn_connection.vpn_connection.id}"
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
layout: "aws"
page_title: "AWS: aws_vpn_connection_route"
sidebar_current: "docs-aws-resource-vpn-connection-route"
description: |-
Provides a static route between a VPN connection and a customer gateway.
---

# aws\_vpn\_connection\_route

Provides a static route between a VPN connection and a customer gateway.

## Example Usage

```
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpn_gateway" "vpn_gateway" {
vpc_id = "${aws_vpc.vpc.id}"
}
resource "aws_customer_gateway" "customer_gateway" {
bgp_asn = 60000
ip_address = "172.0.0.1"
type = ipsec.1
}
resource "aws_vpn_connection" "main" {
vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
type = "ipsec.1"
static_routes_only = true
}
resource "aws_vpn_connection_route" "office" {
destination_cidr_block = "192.168.10.0/24"
vpn_connection_id = "${aws_vpn_connection.main.id}"
}
```

## Argument Reference

The following arguments are supported:

* `destination_cidr_block` - (Required) The CIDR block associated with the local subnet of the customer network.
* `vpn_connection_id` - (Required) The ID of the VPN connection.

## Attribute Reference

The following attributes are exported:

* `destination_cidr_block` - The CIDR block associated with the local subnet of the customer network.
* `vpn_connection_id` - The ID of the VPN connection.
4 changes: 4 additions & 0 deletions website/source/layouts/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@
<a href="/docs/providers/aws/r/vpn_connection.html">aws_vpn_connection</a>
</li>

<li<%= sidebar_current("docs-aws-resource-vpn-connection-route") %>>
<a href="/docs/providers/aws/r/vpn_connection_route.html">aws_vpn_connection_route</a>
</li>

<li<%= sidebar_current("docs-aws-resource-vpn-gateway") %>>
<a href="/docs/providers/aws/r/vpn_gateway.html">aws_vpn_gateway</a>
</li>
Expand Down