provider/aws: Error on trying to recreate an existing customer gateway (#12501)

Fixes: #7492

When we use the same IP Address, BGP ASN and VPN Type as an existing
aws_customer_gateway, terraform will take control of that gateway (not
import it!) and try and modify it. This could be very bad

There is a warning on the AWS documentation that one gateway of the same
parameters can be created, Terraform is now going to error if a gateway
of the same parameters is attempted to be created

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSCustomerGateway_'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/03/07 18:40:39 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSCustomerGateway_ -timeout 120m
=== RUN   TestAccAWSCustomerGateway_importBasic
--- PASS: TestAccAWSCustomerGateway_importBasic (31.11s)
=== RUN   TestAccAWSCustomerGateway_basic
--- PASS: TestAccAWSCustomerGateway_basic (68.72s)
=== RUN   TestAccAWSCustomerGateway_similarAlreadyExists
--- PASS: TestAccAWSCustomerGateway_similarAlreadyExists (35.18s)
=== RUN   TestAccAWSCustomerGateway_disappears
--- PASS: TestAccAWSCustomerGateway_disappears (25.13s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	160.172s
```
This commit is contained in:
Paul Stack 2017-03-08 21:11:59 +02:00 committed by GitHub
parent 0b0a76a3d5
commit b5b53bc56a
2 changed files with 97 additions and 10 deletions

View File

@ -25,19 +25,19 @@ func resourceAwsCustomerGateway() *schema.Resource {
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"bgp_asn": &schema.Schema{ "bgp_asn": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
}, },
"ip_address": &schema.Schema{ "ip_address": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
}, },
"type": &schema.Schema{ "type": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, ForceNew: true,
@ -51,10 +51,23 @@ func resourceAwsCustomerGateway() *schema.Resource {
func resourceAwsCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn conn := meta.(*AWSClient).ec2conn
ipAddress := d.Get("ip_address").(string)
vpnType := d.Get("type").(string)
bgpAsn := d.Get("bgp_asn").(int)
alreadyExists, err := resourceAwsCustomerGatewayExists(vpnType, ipAddress, bgpAsn, conn)
if err != nil {
return err
}
if alreadyExists {
return fmt.Errorf("An existing customer gateway for IpAddress: %s, VpnType: %s, BGP ASN: %d has been found", ipAddress, vpnType, bgpAsn)
}
createOpts := &ec2.CreateCustomerGatewayInput{ createOpts := &ec2.CreateCustomerGatewayInput{
BgpAsn: aws.Int64(int64(d.Get("bgp_asn").(int))), BgpAsn: aws.Int64(int64(bgpAsn)),
PublicIp: aws.String(d.Get("ip_address").(string)), PublicIp: aws.String(ipAddress),
Type: aws.String(d.Get("type").(string)), Type: aws.String(vpnType),
} }
// Create the Customer Gateway. // Create the Customer Gateway.
@ -123,6 +136,37 @@ func customerGatewayRefreshFunc(conn *ec2.EC2, gatewayId string) resource.StateR
} }
} }
func resourceAwsCustomerGatewayExists(vpnType, ipAddress string, bgpAsn int, conn *ec2.EC2) (bool, error) {
ipAddressFilter := &ec2.Filter{
Name: aws.String("ip-address"),
Values: []*string{aws.String(ipAddress)},
}
typeFilter := &ec2.Filter{
Name: aws.String("type"),
Values: []*string{aws.String(vpnType)},
}
bgp := strconv.Itoa(bgpAsn)
bgpAsnFilter := &ec2.Filter{
Name: aws.String("bgp-asn"),
Values: []*string{aws.String(bgp)},
}
resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
Filters: []*ec2.Filter{ipAddressFilter, typeFilter, bgpAsnFilter},
})
if err != nil {
return false, err
}
if len(resp.CustomerGateways) > 0 && *resp.CustomerGateways[0].State != "deleted" {
return true, nil
}
return false, nil
}
func resourceAwsCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn conn := meta.(*AWSClient).ec2conn

View File

@ -2,6 +2,7 @@ package aws
import ( import (
"fmt" "fmt"
"regexp"
"testing" "testing"
"time" "time"
@ -21,19 +22,19 @@ func TestAccAWSCustomerGateway_basic(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckCustomerGatewayDestroy, CheckDestroy: testAccCheckCustomerGatewayDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccCustomerGatewayConfig, Config: testAccCustomerGatewayConfig,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway), testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway),
), ),
}, },
resource.TestStep{ {
Config: testAccCustomerGatewayConfigUpdateTags, Config: testAccCustomerGatewayConfigUpdateTags,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway), testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway),
), ),
}, },
resource.TestStep{ {
Config: testAccCustomerGatewayConfigForceReplace, Config: testAccCustomerGatewayConfigForceReplace,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway), testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway),
@ -43,6 +44,28 @@ func TestAccAWSCustomerGateway_basic(t *testing.T) {
}) })
} }
func TestAccAWSCustomerGateway_similarAlreadyExists(t *testing.T) {
var gateway ec2.CustomerGateway
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "aws_customer_gateway.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckCustomerGatewayDestroy,
Steps: []resource.TestStep{
{
Config: testAccCustomerGatewayConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway),
),
},
{
Config: testAccCustomerGatewayConfigIdentical,
ExpectError: regexp.MustCompile("An existing customer gateway"),
},
},
})
}
func TestAccAWSCustomerGateway_disappears(t *testing.T) { func TestAccAWSCustomerGateway_disappears(t *testing.T) {
var gateway ec2.CustomerGateway var gateway ec2.CustomerGateway
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
@ -50,7 +73,7 @@ func TestAccAWSCustomerGateway_disappears(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckCustomerGatewayDestroy, CheckDestroy: testAccCheckCustomerGatewayDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccCustomerGatewayConfig, Config: testAccCustomerGatewayConfig,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway), testAccCheckCustomerGateway("aws_customer_gateway.foo", &gateway),
@ -178,6 +201,26 @@ resource "aws_customer_gateway" "foo" {
} }
` `
const testAccCustomerGatewayConfigIdentical = `
resource "aws_customer_gateway" "foo" {
bgp_asn = 65000
ip_address = "172.0.0.1"
type = "ipsec.1"
tags {
Name = "foo-gateway"
}
}
resource "aws_customer_gateway" "identical" {
bgp_asn = 65000
ip_address = "172.0.0.1"
type = "ipsec.1"
tags {
Name = "foo-gateway-identical"
}
}
`
// Add the Another: "tag" tag. // Add the Another: "tag" tag.
const testAccCustomerGatewayConfigUpdateTags = ` const testAccCustomerGatewayConfigUpdateTags = `
resource "aws_customer_gateway" "foo" { resource "aws_customer_gateway" "foo" {