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 AWS customer gateways #1746

Merged
merged 3 commits into from
Apr 30, 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 @@ -77,6 +77,7 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{
"aws_autoscaling_group": resourceAwsAutoscalingGroup(),
"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
"aws_customer_gateway": resourceAwsCustomerGateway(),
"aws_db_instance": resourceAwsDbInstance(),
"aws_db_parameter_group": resourceAwsDbParameterGroup(),
"aws_db_security_group": resourceAwsDbSecurityGroup(),
Expand Down
185 changes: 185 additions & 0 deletions builtin/providers/aws/resource_aws_customer_gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package aws

import (
"fmt"
"log"
"time"

"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/helper/schema"
)

func resourceAwsCustomerGateway() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCustomerGatewayCreate,
Read: resourceAwsCustomerGatewayRead,
Update: resourceAwsCustomerGatewayUpdate,
Delete: resourceAwsCustomerGatewayDelete,

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

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

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

"tags": tagsSchema(),
},
}
}

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

createOpts := &ec2.CreateCustomerGatewayInput{
BGPASN: aws.Long(int64(d.Get("bgp_asn").(int))),
PublicIP: aws.String(d.Get("ip_address").(string)),
Type: aws.String(d.Get("type").(string)),
}

// Create the Customer Gateway.
log.Printf("[DEBUG] Creating customer gateway")
resp, err := conn.CreateCustomerGateway(createOpts)
if err != nil {
return fmt.Errorf("Error creating customer gateway: %s", err)
}

// Store the ID
customerGateway := resp.CustomerGateway
d.SetId(*customerGateway.CustomerGatewayID)
log.Printf("[INFO] Customer gateway ID: %s", *customerGateway.CustomerGatewayID)

// Wait for the CustomerGateway to be available.
stateConf := &resource.StateChangeConf{
Pending: []string{"pending"},
Target: "available",
Refresh: customerGatewayRefreshFunc(conn, *customerGateway.CustomerGatewayID),
Timeout: 10 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

_, stateErr := stateConf.WaitForState()
if stateErr != nil {
return fmt.Errorf(
"Error waiting for customer gateway (%s) to become ready: %s",
*customerGateway.CustomerGatewayID, err)
}

// Create tags.
if err := setTagsSDK(conn, d); err != nil {
return err
}

return nil
}

func customerGatewayRefreshFunc(conn *ec2.EC2, gatewayId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
gatewayFilter := &ec2.Filter{
Name: aws.String("customer-gateway-id"),
Values: []*string{aws.String(gatewayId)},
}

resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
Filters: []*ec2.Filter{gatewayFilter},
})
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidCustomerGatewayID.NotFound" {
resp = nil
} else {
log.Printf("Error on CustomerGatewayRefresh: %s", err)
return nil, "", err
}
}

if resp == nil || len(resp.CustomerGateways) == 0 {
// handle consistency issues
return nil, "", nil
}

gateway := resp.CustomerGateways[0]
return gateway, *gateway.State, nil
}
}

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

gatewayFilter := &ec2.Filter{
Name: aws.String("customer-gateway-id"),
Values: []*string{aws.String(d.Id())},
}

resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
Filters: []*ec2.Filter{gatewayFilter},
})
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidCustomerGatewayID.NotFound" {
d.SetId("")
return nil
} else {
log.Printf("[ERROR] Error finding CustomerGateway: %s", err)
return err
}
}

if len(resp.CustomerGateways) != 1 {
return fmt.Errorf("[ERROR] Error finding CustomerGateway: %s", d.Id())
}

customerGateway := resp.CustomerGateways[0]
d.Set("bgp_asn", customerGateway.BGPASN)
d.Set("ip_address", customerGateway.IPAddress)
d.Set("type", customerGateway.Type)
d.Set("tags", tagsToMapSDK(customerGateway.Tags))

return nil
}

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

// Update tags if required.
if err := setTagsSDK(conn, d); err != nil {
return err
}

d.SetPartial("tags")

return resourceAwsCustomerGatewayRead(d, meta)
}

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

_, err := conn.DeleteCustomerGateway(&ec2.DeleteCustomerGatewayInput{
CustomerGatewayID: aws.String(d.Id()),
})
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidCustomerGatewayID.NotFound" {
d.SetId("")
return nil
} else {
log.Printf("[ERROR] Error deleting CustomerGateway: %s", err)
return err
}
}

return nil
}
110 changes: 110 additions & 0 deletions builtin/providers/aws/resource_aws_customer_gateway_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
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 TestAccCustomerGateway(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCustomerGatewayDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCustomerGatewayConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway(
"aws_customer_gateway.foo",
),
),
},
resource.TestStep{
Config: testAccCustomerGatewayUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway(
"aws_customer_gateway.bar",
),
),
},
},
})
}

func testAccCheckCustomerGatewayDestroy(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 testAccCheckCustomerGateway(gatewayResource string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[gatewayResource]
if !ok {
return fmt.Errorf("Not found: %s", gatewayResource)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

gateway, ok := s.RootModule().Resources[gatewayResource]
if !ok {
return fmt.Errorf("Not found: %s", gatewayResource)
}

ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
gatewayFilter := &ec2.Filter{
Name: aws.String("customer-gateway-id"),
Values: []*string{aws.String(gateway.Primary.ID)},
}

_, err := ec2conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
Filters: []*ec2.Filter{gatewayFilter},
})

if err != nil {
return err
}

return nil
}
}

const testAccCustomerGatewayConfig = `
resource "aws_customer_gateway" "foo" {
bgp_asn = 60000
ip_address = "172.0.0.1"
type = ipsec.1
tags {
Name = "foo-gateway"
}
}
`

const testAccCustomerGatewayUpdate = `
resource "aws_customer_gateway" "foo" {
bgp_asn = 60000
ip_address = "172.0.0.1"
type = ipsec.1
tags {
Name = "foo-gateway"
}
}

resource "aws_customer_gateway" "bar" {
bgp_asn = 60000
ip_address = "172.0.0.1"
type = ipsec.1
tags {
Name = "foo-gateway"
}
}
`
46 changes: 46 additions & 0 deletions website/source/docs/providers/aws/r/customer_gateway.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
layout: "aws"
page_title: "AWS: aws_customer_gateway"
sidebar_current: "docs-aws-resource-customer-gateway"
description: |-
Provides a customer gateway inside a VPC. These objects can be
connected to VPN gateways via VPN connections, and allow you to
establish tunnels between your network and the VPC.
---

# aws\_customer\_gateway

Provides a customer gateway inside a VPC. These objects can be connected to VPN gateways via VPN connections, and allow you to establish tunnels between your network and the VPC.

## Example Usage

```
resource "aws_customer_gateway" "main" {
bgp_asn = 60000
ip_address = "172.83.124.10"
type = ipsec.1
tags {
Name = "main-customer-gateway"
}
}
```

## Argument Reference

The following arguments are supported:

* `bgp_asn` - (Required) The gateway's Border Gateway Protocol (BGP) Autonomous System Number (ASN).
* `ip_address` - (Required) The IP address of the gateway's Internet-routable external interface.
* `type` - (Required) The type of customer gateway. The only type AWS
supports at this time is "ipsec.1".
* `tags` - (Optional) Tags to apply to the gateway.

## Attribute Reference

The following attributes are exported:

* `id` - The amazon-assigned ID of the gateway.
* `bgp_asn` - The gateway's Border Gateway Protocol (BGP) Autonomous System Number (ASN).
* `ip_address` - The IP address of the gateway's Internet-routable external interface.
* `type` - The type of customer gateway.
* `tags` - Tags applied to the gateway.
4 changes: 4 additions & 0 deletions website/source/layouts/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
<a href="/docs/providers/aws/r/autoscale.html">aws_autoscaling_group</a>
</li>

<li<%= sidebar_current("docs-aws-resource-customer-gateway") %>>
<a href="/docs/providers/aws/r/customer_gateway.html">aws_customer_gateway</a>
</li>

<li<%= sidebar_current("docs-aws-resource-db-instance") %>>
<a href="/docs/providers/aws/r/db_instance.html">aws_db_instance</a>
</li>
Expand Down