From 2794a1c5abbe9f1963e91c0618132354c04ababa Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Tue, 28 Apr 2015 10:28:52 -0400 Subject: [PATCH 1/3] aws: Add support for aws_customer_gateway --- builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_customer_gateway.go | 185 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_customer_gateway.go diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index c3e07d559..9efc95a04 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -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(), diff --git a/builtin/providers/aws/resource_aws_customer_gateway.go b/builtin/providers/aws/resource_aws_customer_gateway.go new file mode 100644 index 000000000..9c18a53d9 --- /dev/null +++ b/builtin/providers/aws/resource_aws_customer_gateway.go @@ -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 +} From eb03f08454621dd46cfc0452d68d9d21cbe62256 Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Wed, 29 Apr 2015 19:05:16 -0400 Subject: [PATCH 2/3] aws: Add acceptance test for aws_customer_gateway. --- .../aws/resource_aws_customer_gateway_test.go | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_customer_gateway_test.go diff --git a/builtin/providers/aws/resource_aws_customer_gateway_test.go b/builtin/providers/aws/resource_aws_customer_gateway_test.go new file mode 100644 index 000000000..1d64bbd6b --- /dev/null +++ b/builtin/providers/aws/resource_aws_customer_gateway_test.go @@ -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" + } +} +` From 2b4fb16e3a1c9e36c3dbd700b2a2c5d77088c1ab Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Wed, 29 Apr 2015 19:06:16 -0400 Subject: [PATCH 3/3] aws: Add docs for aws_customer_gateway. --- .../aws/r/customer_gateway.html.markdown | 46 +++++++++++++++++++ website/source/layouts/aws.erb | 4 ++ 2 files changed, 50 insertions(+) create mode 100644 website/source/docs/providers/aws/r/customer_gateway.html.markdown diff --git a/website/source/docs/providers/aws/r/customer_gateway.html.markdown b/website/source/docs/providers/aws/r/customer_gateway.html.markdown new file mode 100644 index 000000000..78222f2a8 --- /dev/null +++ b/website/source/docs/providers/aws/r/customer_gateway.html.markdown @@ -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. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index e7d015c94..48f349500 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -17,6 +17,10 @@ aws_autoscaling_group + > + aws_customer_gateway + + > aws_db_instance