Merge branch 'master' into aws-go-vpn

This commit is contained in:
Dan Everton 2015-03-19 11:03:48 +10:00
commit f7289599cc
40 changed files with 611 additions and 507 deletions

View File

@ -3,21 +3,16 @@ package aws
import (
"fmt"
"log"
"strings"
"unicode"
"github.com/hashicorp/terraform/helper/multierror"
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/ec2"
awsGo "github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/autoscaling"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/aws-sdk-go/gen/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/aws-sdk-go/gen/route53"
"github.com/hashicorp/aws-sdk-go/gen/s3"
awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
)
type Config struct {
@ -29,7 +24,6 @@ type Config struct {
type AWSClient struct {
ec2conn *ec2.EC2
awsEC2conn *awsEC2.EC2
elbconn *elb.ELB
autoscalingconn *autoscaling.AutoScaling
s3conn *s3.S3
@ -45,14 +39,9 @@ func (c *Config) Client() (interface{}, error) {
// Get the auth and region. This can fail if keys/regions were not
// specified and we're attempting to use the environment.
var errs []error
log.Println("[INFO] Building AWS auth structure")
auth, err := c.AWSAuth()
if err != nil {
errs = append(errs, err)
}
log.Println("[INFO] Building AWS region structure")
region, err := c.AWSRegion()
err := c.ValidateRegion()
if err != nil {
errs = append(errs, err)
}
@ -62,10 +51,9 @@ func (c *Config) Client() (interface{}, error) {
// bucket storage in S3
client.region = c.Region
creds := awsGo.Creds(c.AccessKey, c.SecretKey, c.Token)
log.Println("[INFO] Building AWS auth structure")
creds := aws.Creds(c.AccessKey, c.SecretKey, c.Token)
log.Println("[INFO] Initializing EC2 connection")
client.ec2conn = ec2.New(auth, region)
log.Println("[INFO] Initializing ELB connection")
client.elbconn = elb.New(creds, c.Region, nil)
log.Println("[INFO] Initializing AutoScaling connection")
@ -80,8 +68,8 @@ func (c *Config) Client() (interface{}, error) {
// See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
log.Println("[INFO] Initializing Route53 connection")
client.r53conn = route53.New(creds, "us-east-1", nil)
log.Println("[INFO] Initializing AWS-GO EC2 Connection")
client.awsEC2conn = awsEC2.New(creds, c.Region, nil)
log.Println("[INFO] Initializing EC2 Connection")
client.ec2conn = ec2.New(creds, c.Region, nil)
}
if len(errs) > 0 {
@ -91,54 +79,17 @@ func (c *Config) Client() (interface{}, error) {
return &client, nil
}
// AWSAuth returns a valid aws.Auth object for access to AWS services, or
// an error if the authentication couldn't be resolved.
//
// TODO(mitchellh): Test in some way.
func (c *Config) AWSAuth() (aws.Auth, error) {
auth, err := aws.GetAuth(c.AccessKey, c.SecretKey)
if err == nil {
// Store the accesskey and secret that we got...
c.AccessKey = auth.AccessKey
c.SecretKey = auth.SecretKey
c.Token = auth.Token
}
return auth, err
}
// IsValidRegion returns true if the configured region is a valid AWS
// region and false if it's not
func (c *Config) IsValidRegion() bool {
func (c *Config) ValidateRegion() error {
var regions = [11]string{"us-east-1", "us-west-2", "us-west-1", "eu-west-1",
"eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1",
"sa-east-1", "cn-north-1", "us-gov-west-1"}
for _, valid := range regions {
if c.Region == valid {
return true
return nil
}
}
return false
}
// AWSRegion returns the configured region.
//
// TODO(mitchellh): Test in some way.
func (c *Config) AWSRegion() (aws.Region, error) {
if c.Region != "" {
if c.IsValidRegion() {
return aws.Regions[c.Region], nil
} else {
return aws.Region{}, fmt.Errorf("Not a valid region: %s", c.Region)
}
}
md, err := aws.GetMetaData("placement/availability-zone")
if err != nil {
return aws.Region{}, err
}
region := strings.TrimRightFunc(string(md), unicode.IsLetter)
return aws.Regions[region], nil
return fmt.Errorf("Not a valid region: %s", c.Region)
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"log"
"strings"
"time"
"github.com/hashicorp/terraform/helper/hashcode"
@ -152,7 +153,7 @@ func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{})
os := o.(*schema.Set)
ns := n.(*schema.Set)
// Expand the "parameter" set to goamz compat []rds.Parameter
// Expand the "parameter" set to aws-sdk-go compat []rds.Parameter
parameters, err := expandParameters(ns.Difference(os).List())
if err != nil {
return err
@ -220,7 +221,8 @@ func resourceAwsDbParameterHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["value"].(string)))
// Store the value as a lower case string, to match how we store them in flattenParameters
buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["value"].(string))))
return hashcode.String(buf.String())
}

View File

@ -60,7 +60,7 @@ func resourceAwsEip() *schema.Resource {
}
func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// By default, we're not in a VPC
domainOpt := ""
@ -97,7 +97,7 @@ func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
domain := resourceAwsEipDomain(d)
id := d.Id()
@ -148,7 +148,7 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
domain := resourceAwsEipDomain(d)
@ -181,7 +181,7 @@ func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
if err := resourceAwsEipRead(d, meta); err != nil {
return err

View File

@ -58,7 +58,7 @@ func TestAccAWSEIP_instance(t *testing.T) {
}
func testAccCheckAWSEIPDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_eip" {
@ -113,7 +113,7 @@ func testAccCheckAWSEIPExists(n string, res *ec2.Address) resource.TestCheckFunc
return fmt.Errorf("No EIP ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
if strings.Contains(rs.Primary.ID, "eipalloc") {
req := &ec2.DescribeAddressesRequest{

View File

@ -161,7 +161,7 @@ func resourceAwsElb() *schema.Resource {
func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbconn
// Expand the "listener" set to goamz compat []elb.Listener
// Expand the "listener" set to aws-sdk-go compat []elb.Listener
listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
if err != nil {
return err

View File

@ -3,6 +3,7 @@ package aws
import (
"bytes"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"log"
@ -253,17 +254,19 @@ func resourceAwsInstance() *schema.Resource {
}
func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Figure out user data
userData := ""
if v := d.Get("user_data"); v != nil {
userData = v.(string)
userData = base64.StdEncoding.EncodeToString([]byte(v.(string)))
}
placement := &ec2.Placement{
AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
Tenancy: aws.String(d.Get("tenancy").(string)),
}
if v := d.Get("tenancy").(string); v != "" {
placement.Tenancy = aws.String(v)
}
iam := &ec2.IAMInstanceProfileSpecification{
@ -292,6 +295,17 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
subnet, hasSubnet := d.GetOk("subnet_id")
subnetID := subnet.(string)
var groups []string
if v := d.Get("security_groups"); v != nil {
// Security group names.
// For a nondefault VPC, you must use security group IDs instead.
// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html
for _, v := range v.(*schema.Set).List() {
str := v.(string)
groups = append(groups, str)
}
}
if hasSubnet && associatePublicIPAddress {
// If we have a non-default VPC / Subnet specified, we can flag
// AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
@ -310,6 +324,10 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
ni.PrivateIPAddress = aws.String(v.(string))
}
if len(groups) > 0 {
ni.Groups = groups
}
runOpts.NetworkInterfaces = []ec2.InstanceNetworkInterfaceSpecification{ni}
} else {
if subnetID != "" {
@ -319,21 +337,6 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
if v, ok := d.GetOk("private_ip"); ok {
runOpts.PrivateIPAddress = aws.String(v.(string))
}
}
if v, ok := d.GetOk("key_name"); ok {
runOpts.KeyName = aws.String(v.(string))
}
if v := d.Get("security_groups"); v != nil {
// Security group names.
// For a nondefault VPC, you must use security group IDs instead.
// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html
var groups []string
for _, v := range v.(*schema.Set).List() {
str := v.(string)
groups = append(groups, str)
}
if runOpts.SubnetID != nil &&
*runOpts.SubnetID != "" {
runOpts.SecurityGroupIDs = groups
@ -342,6 +345,10 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
}
}
if v, ok := d.GetOk("key_name"); ok {
runOpts.KeyName = aws.String(v.(string))
}
blockDevices := make([]interface{}, 0)
if v := d.Get("block_device"); v != nil {
@ -437,7 +444,7 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
resp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesRequest{
InstanceIDs: []string{d.Id()},
@ -481,7 +488,7 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("subnet_id", instance.SubnetID)
}
d.Set("ebs_optimized", instance.EBSOptimized)
d.Set("tags", tagsToMapSDK(instance.Tags))
d.Set("tags", tagsToMap(instance.Tags))
d.Set("tenancy", instance.Placement.Tenancy)
// Determine whether we're referring to security groups with
@ -489,7 +496,7 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
// we use IDs if we're in a VPC. However, if we previously had an
// all-name list of security groups, we use names. Or, if we had any
// IDs, we use IDs.
useID := *instance.SubnetID != ""
useID := instance.SubnetID != nil && *instance.SubnetID != ""
if v := d.Get("security_groups"); v != nil {
match := false
for _, v := range v.(*schema.Set).List() {
@ -561,25 +568,26 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
opts := new(ec2.ModifyInstanceAttributeRequest)
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[INFO] Modifying instance %s: %#v", d.Id(), opts)
err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeRequest{
InstanceID: aws.String(d.Id()),
SourceDestCheck: &ec2.AttributeBooleanValue{
Value: aws.Boolean(d.Get("source_dest_check").(bool)),
},
})
if err != nil {
return err
// SourceDestCheck can only be set on VPC instances
if d.Get("subnet_id").(string) != "" {
log.Printf("[INFO] Modifying instance %s", d.Id())
err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeRequest{
InstanceID: aws.String(d.Id()),
SourceDestCheck: &ec2.AttributeBooleanValue{
Value: aws.Boolean(d.Get("source_dest_check").(bool)),
},
})
if err != nil {
return err
}
}
// TODO(mitchellh): wait for the attributes we modified to
// persist the change...
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
@ -589,7 +597,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsInstanceDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[INFO] Terminating instance: %s", d.Id())
req := &ec2.TerminateInstancesRequest{

View File

@ -44,7 +44,7 @@ func TestAccAWSInstance_normal(t *testing.T) {
resource.TestCheckResourceAttr(
"aws_instance.foo",
"user_data",
"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
"3dc39dda39be1205215e776bad998da361a5955d"),
),
},
@ -60,7 +60,7 @@ func TestAccAWSInstance_normal(t *testing.T) {
resource.TestCheckResourceAttr(
"aws_instance.foo",
"user_data",
"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
"3dc39dda39be1205215e776bad998da361a5955d"),
),
},
},
@ -207,6 +207,25 @@ func TestAccAWSInstance_vpc(t *testing.T) {
})
}
func TestAccInstance_NetworkInstanceSecurityGroups(t *testing.T) {
var v ec2.Instance
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccInstanceNetworkInstanceSecurityGroups,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists(
"aws_instance.foo_instance", &v),
),
},
},
})
}
func TestAccAWSInstance_tags(t *testing.T) {
var v ec2.Instance
@ -219,9 +238,9 @@ func TestAccAWSInstance_tags(t *testing.T) {
Config: testAccCheckInstanceConfigTags,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("aws_instance.foo", &v),
testAccCheckTagsSDK(&v.Tags, "foo", "bar"),
testAccCheckTags(&v.Tags, "foo", "bar"),
// Guard against regression of https://github.com/hashicorp/terraform/issues/914
testAccCheckTagsSDK(&v.Tags, "#", ""),
testAccCheckTags(&v.Tags, "#", ""),
),
},
@ -229,8 +248,8 @@ func TestAccAWSInstance_tags(t *testing.T) {
Config: testAccCheckInstanceConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("aws_instance.foo", &v),
testAccCheckTagsSDK(&v.Tags, "foo", ""),
testAccCheckTagsSDK(&v.Tags, "bar", "baz"),
testAccCheckTags(&v.Tags, "foo", ""),
testAccCheckTags(&v.Tags, "bar", "baz"),
),
},
},
@ -296,7 +315,7 @@ func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
}
func testAccCheckInstanceDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_instance" {
@ -339,7 +358,7 @@ func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFun
return fmt.Errorf("No ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{
InstanceIDs: []string{rs.Primary.ID},
})
@ -392,7 +411,7 @@ resource "aws_instance" "foo" {
instance_type = "m1.small"
security_groups = ["${aws_security_group.tf_test_foo.name}"]
user_data = "foo"
user_data = "foo:-with-character's"
}
`
@ -533,3 +552,49 @@ resource "aws_instance" "foo" {
private_ip = "10.1.1.42"
}
`
const testAccInstanceNetworkInstanceSecurityGroups = `
resource "aws_internet_gateway" "gw" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
tags {
Name = "tf-network-test"
}
}
resource "aws_security_group" "tf_test_foo" {
name = "tf_test_foo"
description = "foo"
vpc_id="${aws_vpc.foo.id}"
ingress {
protocol = "icmp"
from_port = -1
to_port = -1
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_subnet" "foo" {
cidr_block = "10.1.1.0/24"
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_instance" "foo_instance" {
ami = "ami-21f78e11"
instance_type = "t1.micro"
security_groups = ["${aws_security_group.tf_test_foo.id}"]
subnet_id = "${aws_subnet.foo.id}"
associate_public_ip_address = true
depends_on = ["aws_internet_gateway.gw"]
}
resource "aws_eip" "foo_eip" {
instance = "${aws_instance.foo_instance.id}"
vpc = true
depends_on = ["aws_internet_gateway.gw"]
}
`

View File

@ -29,7 +29,7 @@ func resourceAwsInternetGateway() *schema.Resource {
}
func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Create the gateway
log.Printf("[DEBUG] Creating internet gateway")
@ -43,7 +43,7 @@ func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{})
d.SetId(*ig.InternetGatewayID)
log.Printf("[INFO] InternetGateway ID: %s", d.Id())
err = setTagsSDK(ec2conn, d)
err = setTags(ec2conn, d)
if err != nil {
return err
}
@ -53,7 +53,7 @@ func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{})
}
func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
igRaw, _, err := IGStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
@ -73,7 +73,7 @@ func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) er
d.Set("vpc_id", ig.Attachments[0].VPCID)
}
d.Set("tags", tagsToMapSDK(ig.Tags))
d.Set("tags", tagsToMap(ig.Tags))
return nil
}
@ -91,9 +91,9 @@ func resourceAwsInternetGatewayUpdate(d *schema.ResourceData, meta interface{})
}
}
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
}
@ -103,7 +103,7 @@ func resourceAwsInternetGatewayUpdate(d *schema.ResourceData, meta interface{})
}
func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Detach if it is attached
if err := resourceAwsInternetGatewayDetach(d, meta); err != nil {
@ -137,7 +137,7 @@ func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{})
}
func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
if d.Get("vpc_id").(string) == "" {
log.Printf(
@ -182,7 +182,7 @@ func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{})
}
func resourceAwsInternetGatewayDetach(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Get the old VPC ID to detach from
vpcID, _ := d.GetChange("vpc_id")

View File

@ -98,7 +98,7 @@ func TestAccInternetGateway_tags(t *testing.T) {
Config: testAccCheckInternetGatewayConfigTags,
Check: resource.ComposeTestCheckFunc(
testAccCheckInternetGatewayExists("aws_internet_gateway.foo", &v),
testAccCheckTagsSDK(&v.Tags, "foo", "bar"),
testAccCheckTags(&v.Tags, "foo", "bar"),
),
},
@ -106,8 +106,8 @@ func TestAccInternetGateway_tags(t *testing.T) {
Config: testAccCheckInternetGatewayConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckInternetGatewayExists("aws_internet_gateway.foo", &v),
testAccCheckTagsSDK(&v.Tags, "foo", ""),
testAccCheckTagsSDK(&v.Tags, "bar", "baz"),
testAccCheckTags(&v.Tags, "foo", ""),
testAccCheckTags(&v.Tags, "bar", "baz"),
),
},
},
@ -115,7 +115,7 @@ func TestAccInternetGateway_tags(t *testing.T) {
}
func testAccCheckInternetGatewayDestroy(s *terraform.State) error {
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_internet_gateway" {
@ -158,7 +158,7 @@ func testAccCheckInternetGatewayExists(n string, ig *ec2.InternetGateway) resour
return fmt.Errorf("No ID is set")
}
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := ec2conn.DescribeInternetGateways(&ec2.DescribeInternetGatewaysRequest{
InternetGatewayIDs: []string{rs.Primary.ID},
})

View File

@ -37,7 +37,7 @@ func resourceAwsKeyPair() *schema.Resource {
}
func resourceAwsKeyPairCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
keyName := d.Get("key_name").(string)
publicKey := d.Get("public_key").(string)
@ -55,7 +55,7 @@ func resourceAwsKeyPairCreate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsKeyPairRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
req := &ec2.DescribeKeyPairsRequest{
KeyNames: []string{d.Id()},
@ -77,7 +77,7 @@ func resourceAwsKeyPairRead(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsKeyPairDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
err := ec2conn.DeleteKeyPair(&ec2.DeleteKeyPairRequest{
KeyName: aws.String(d.Id()),

View File

@ -30,7 +30,7 @@ func TestAccAWSKeyPair_normal(t *testing.T) {
}
func testAccCheckAWSKeyPairDestroy(s *terraform.State) error {
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_key_pair" {
@ -81,7 +81,7 @@ func testAccCheckAWSKeyPairExists(n string, res *ec2.KeyPairInfo) resource.TestC
return fmt.Errorf("No KeyPair name is set")
}
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := ec2conn.DescribeKeyPairs(&ec2.DescribeKeyPairsRequest{
KeyNames: []string{rs.Primary.ID},

View File

@ -40,7 +40,7 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource {
}
func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string)
routeTableId := d.Get("route_table_id").(string)
@ -67,7 +67,7 @@ func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta int
}
func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
mainAssociation, err := findMainRouteTableAssociation(
ec2conn,
@ -88,7 +88,7 @@ func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta inter
// original_route_table_id - this needs to stay recorded as the AWS-created
// table from VPC creation.
func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string)
routeTableId := d.Get("route_table_id").(string)
@ -109,7 +109,7 @@ func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta int
}
func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string)
originalRouteTableId := d.Get("original_route_table_id").(string)

View File

@ -65,7 +65,7 @@ func testAccCheckMainRouteTableAssociation(
return fmt.Errorf("Not found: %s", vpcResource)
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
mainAssociation, err := findMainRouteTableAssociation(conn, vpc.Primary.ID)
if err != nil {
return err

View File

@ -109,7 +109,7 @@ func resourceAwsNetworkAcl() *schema.Resource {
func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Create the Network Acl
createOpts := &ec2.CreateNetworkACLRequest{
@ -132,7 +132,7 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error
}
func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
NetworkACLIDs: []string{d.Id()},
@ -161,13 +161,13 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error {
d.Set("vpc_id", networkAcl.VPCID)
d.Set("ingress", ingressEntries)
d.Set("egress", egressEntries)
d.Set("tags", tagsToMapSDK(networkAcl.Tags))
d.Set("tags", tagsToMap(networkAcl.Tags))
return nil
}
func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
d.Partial(true)
if d.HasChange("ingress") {
@ -202,7 +202,7 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error
}
}
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
@ -265,7 +265,7 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *
}
func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[INFO] Deleting Network Acl: %s", d.Id())
return resource.Retry(5*time.Minute, func() error {

View File

@ -151,7 +151,7 @@ func TestAccAWSNetworkAclsOnlyEgressRules(t *testing.T) {
Config: testAccAWSNetworkAclEgressConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSNetworkAclExists("aws_network_acl.bond", &networkAcl),
testAccCheckTagsSDK(&networkAcl.Tags, "foo", "bar"),
testAccCheckTags(&networkAcl.Tags, "foo", "bar"),
),
},
},
@ -184,7 +184,7 @@ func TestAccAWSNetworkAcl_SubnetChange(t *testing.T) {
}
func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_network" {
@ -226,7 +226,7 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkACL) resou
if rs.Primary.ID == "" {
return fmt.Errorf("No Security Group is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
NetworkACLIDs: []string{rs.Primary.ID},
@ -266,7 +266,7 @@ func testAccCheckSubnetIsAssociatedWithAcl(acl string, sub string) resource.Test
networkAcl := s.RootModule().Resources[acl]
subnet := s.RootModule().Resources[sub]
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
NetworkACLIDs: []string{networkAcl.Primary.ID},
Filters: []ec2.Filter{
@ -296,7 +296,7 @@ func testAccCheckSubnetIsNotAssociatedWithAcl(acl string, subnet string) resourc
networkAcl := s.RootModule().Resources[acl]
subnet := s.RootModule().Resources[subnet]
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
NetworkACLIDs: []string{networkAcl.Primary.ID},
Filters: []ec2.Filter{

View File

@ -173,7 +173,8 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro
// Scan for a matching record
found := false
for _, record := range resp.ResourceRecordSets {
if FQDN(*record.Name) != FQDN(*lopts.StartRecordName) {
name := cleanRecordName(*record.Name)
if FQDN(name) != FQDN(*lopts.StartRecordName) {
continue
}
if strings.ToUpper(*record.Type) != strings.ToUpper(*lopts.StartRecordType) {
@ -232,15 +233,17 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
Refresh: func() (interface{}, string, error) {
_, err := conn.ChangeResourceRecordSets(req)
if err != nil {
if strings.Contains(err.Error(), "PriorRequestNotComplete") {
// There is some pending operation, so just retry
// in a bit.
return 42, "rejected", nil
}
if r53err, ok := err.(aws.APIError); ok {
if r53err.Code == "PriorRequestNotComplete" {
// There is some pending operation, so just retry
// in a bit.
return 42, "rejected", nil
}
if strings.Contains(err.Error(), "InvalidChangeBatch") {
// This means that the record is already gone.
return 42, "accepted", nil
if r53err.Code == "InvalidChangeBatch" {
// This means that the record is already gone.
return 42, "accepted", nil
}
}
return 42, "failure", err
@ -282,3 +285,15 @@ func FQDN(name string) string {
return name + "."
}
}
// Route 53 stores the "*" wildcard indicator as ASCII 42 and returns the
// octal equivalent, "\\052". Here we look for that, and convert back to "*"
// as needed.
func cleanRecordName(name string) string {
str := name
if strings.HasPrefix(name, "\\052") {
str = strings.Replace(name, "\\052", "*", 1)
log.Printf("[DEBUG] Replacing octal \\052 for * in: %s", name)
}
return str
}

View File

@ -9,9 +9,26 @@ import (
"github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/aws-sdk-go/aws"
awsr53 "github.com/hashicorp/aws-sdk-go/gen/route53"
route53 "github.com/hashicorp/aws-sdk-go/gen/route53"
)
func TestCleanRecordName(t *testing.T) {
cases := []struct {
Input, Output string
}{
{"www.nonexample.com", "www.nonexample.com"},
{"\\052.nonexample.com", "*.nonexample.com"},
{"nonexample.com", "nonexample.com"},
}
for _, tc := range cases {
actual := cleanRecordName(tc.Input)
if actual != tc.Output {
t.Fatalf("input: %s\noutput: %s", tc.Input, actual)
}
}
}
func TestAccRoute53Record(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@ -44,6 +61,30 @@ func TestAccRoute53Record_generatesSuffix(t *testing.T) {
})
}
func TestAccRoute53Record_wildcard(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53RecordDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53WildCardRecordConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53RecordExists("aws_route53_record.wildcard"),
),
},
// Cause a change, which will trigger a refresh
resource.TestStep{
Config: testAccRoute53WildCardRecordConfigUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53RecordExists("aws_route53_record.wildcard"),
),
},
},
})
}
func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources {
@ -56,7 +97,7 @@ func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
name := parts[1]
rType := parts[2]
lopts := &awsr53.ListResourceRecordSetsRequest{
lopts := &route53.ListResourceRecordSetsRequest{
HostedZoneID: aws.String(cleanZoneID(zone)),
StartRecordName: aws.String(name),
StartRecordType: aws.String(rType),
@ -94,7 +135,7 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
name := parts[1]
rType := parts[2]
lopts := &awsr53.ListResourceRecordSetsRequest{
lopts := &route53.ListResourceRecordSetsRequest{
HostedZoneID: aws.String(cleanZoneID(zone)),
StartRecordName: aws.String(name),
StartRecordType: aws.String(rType),
@ -107,11 +148,14 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
if len(resp.ResourceRecordSets) == 0 {
return fmt.Errorf("Record does not exist")
}
rec := resp.ResourceRecordSets[0]
if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
return nil
// rec := resp.ResourceRecordSets[0]
for _, rec := range resp.ResourceRecordSets {
recName := cleanRecordName(*rec.Name)
if FQDN(recName) == FQDN(name) && *rec.Type == rType {
return nil
}
}
return fmt.Errorf("Record does not exist: %#v", rec)
return fmt.Errorf("Record does not exist: %#v", rs.Primary.ID)
}
}
@ -142,3 +186,47 @@ resource "aws_route53_record" "default" {
records = ["127.0.0.1", "127.0.0.27"]
}
`
const testAccRoute53WildCardRecordConfig = `
resource "aws_route53_zone" "main" {
name = "notexample.com"
}
resource "aws_route53_record" "default" {
zone_id = "${aws_route53_zone.main.zone_id}"
name = "subdomain"
type = "A"
ttl = "30"
records = ["127.0.0.1", "127.0.0.27"]
}
resource "aws_route53_record" "wildcard" {
zone_id = "${aws_route53_zone.main.zone_id}"
name = "*.notexample.com"
type = "A"
ttl = "30"
records = ["127.0.0.1"]
}
`
const testAccRoute53WildCardRecordConfigUpdate = `
resource "aws_route53_zone" "main" {
name = "notexample.com"
}
resource "aws_route53_record" "default" {
zone_id = "${aws_route53_zone.main.zone_id}"
name = "subdomain"
type = "A"
ttl = "30"
records = ["127.0.0.1", "127.0.0.27"]
}
resource "aws_route53_record" "wildcard" {
zone_id = "${aws_route53_zone.main.zone_id}"
name = "*.notexample.com"
type = "A"
ttl = "60"
records = ["127.0.0.1"]
}
`

View File

@ -62,7 +62,7 @@ func resourceAwsRouteTable() *schema.Resource {
}
func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Create the routing table
createOpts := &ec2.CreateRouteTableRequest{
@ -100,7 +100,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
}
func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
@ -146,13 +146,13 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
d.Set("route", route)
// Tags
d.Set("tags", tagsToMapSDK(rt.Tags))
d.Set("tags", tagsToMap(rt.Tags))
return nil
}
func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Check if the route set as a whole has changed
if d.HasChange("route") {
@ -203,7 +203,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
}
}
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
@ -213,7 +213,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
}
func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// First request the routing table since we'll have to disassociate
// all the subnets first.

View File

@ -32,7 +32,7 @@ func resourceAwsRouteTableAssociation() *schema.Resource {
}
func resourceAwsRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf(
"[INFO] Creating route table association: %s => %s",
@ -56,7 +56,7 @@ func resourceAwsRouteTableAssociationCreate(d *schema.ResourceData, meta interfa
}
func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Get the routing table that this association belongs to
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(
@ -88,7 +88,7 @@ func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface
}
func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf(
"[INFO] Creating route table association: %s => %s",
@ -119,7 +119,7 @@ func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interfa
}
func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[INFO] Deleting route table association: %s", d.Id())
err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{

View File

@ -38,7 +38,7 @@ func TestAccAWSRouteTableAssociation(t *testing.T) {
}
func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route_table_association" {
@ -83,7 +83,7 @@ func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTable) resour
return fmt.Errorf("No ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
RouteTableIDs: []string{rs.Primary.Attributes["route_table_id"]},
})

View File

@ -134,7 +134,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
Config: testAccRouteTableConfigTags,
Check: resource.ComposeTestCheckFunc(
testAccCheckRouteTableExists("aws_route_table.foo", &route_table),
testAccCheckTagsSDK(&route_table.Tags, "foo", "bar"),
testAccCheckTags(&route_table.Tags, "foo", "bar"),
),
},
@ -142,8 +142,8 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
Config: testAccRouteTableConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckRouteTableExists("aws_route_table.foo", &route_table),
testAccCheckTagsSDK(&route_table.Tags, "foo", ""),
testAccCheckTagsSDK(&route_table.Tags, "bar", "baz"),
testAccCheckTags(&route_table.Tags, "foo", ""),
testAccCheckTags(&route_table.Tags, "bar", "baz"),
),
},
},
@ -151,7 +151,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
}
func testAccCheckRouteTableDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route_table" {
@ -194,7 +194,7 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
return fmt.Errorf("No ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
RouteTableIDs: []string{rs.Primary.ID},
})

View File

@ -142,7 +142,7 @@ func resourceAwsSecurityGroup() *schema.Resource {
}
func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
securityGroupOpts := &ec2.CreateSecurityGroupRequest{
GroupName: aws.String(d.Get("name").(string)),
@ -187,7 +187,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er
}
func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
@ -209,12 +209,12 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro
d.Set("owner_id", sg.OwnerID)
d.Set("ingress", ingressRules)
d.Set("egress", egressRules)
d.Set("tags", tagsToMapSDK(sg.Tags))
d.Set("tags", tagsToMap(sg.Tags))
return nil
}
func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
@ -239,7 +239,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er
}
}
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
}
@ -249,7 +249,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er
}
func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[DEBUG] Security Group destroy: %v", d.Id())
@ -285,6 +285,7 @@ func resourceAwsSecurityGroupRuleHash(v interface{}) int {
buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
buf.WriteString(fmt.Sprintf("%t-", m["self"].(bool)))
// We need to make sure to sort the strings below so that we always
// generate the same hash code no matter what is in the set.
@ -354,7 +355,7 @@ func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []
var groups []string
if len(perm.UserIDGroupPairs) > 0 {
groups = flattenSecurityGroupsSDK(perm.UserIDGroupPairs)
groups = flattenSecurityGroups(perm.UserIDGroupPairs)
}
for i, id := range groups {
if id == d.Id() {
@ -396,9 +397,8 @@ func resourceAwsSecurityGroupUpdateRules(
os := o.(*schema.Set)
ns := n.(*schema.Set)
// TODO: re-munge this when test is updated
remove := expandIPPerms(d.Id(), os.Difference(ns).List())
add := expandIPPerms(d.Id(), ns.Difference(os).List())
remove := expandIPPerms(group, os.Difference(ns).List())
add := expandIPPerms(group, ns.Difference(os).List())
// TODO: We need to handle partial state better in the in-between
// in this update.
@ -410,7 +410,7 @@ func resourceAwsSecurityGroupUpdateRules(
// not have service issues.
if len(remove) > 0 || len(add) > 0 {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
var err error
if len(remove) > 0 {
@ -453,6 +453,11 @@ func resourceAwsSecurityGroupUpdateRules(
GroupID: group.GroupID,
IPPermissions: add,
}
if group.VPCID == nil || *group.VPCID == "" {
req.GroupID = nil
req.GroupName = group.GroupName
}
err = ec2conn.AuthorizeSecurityGroupIngress(req)
}

View File

@ -186,7 +186,7 @@ func TestAccAWSSecurityGroup_Change(t *testing.T) {
}
func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_security_group" {
@ -230,7 +230,7 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroup) reso
return fmt.Errorf("No Security Group is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
req := &ec2.DescribeSecurityGroupsRequest{
GroupIDs: []string{rs.Primary.ID},
}
@ -296,7 +296,7 @@ func TestAccAWSSecurityGroup_tags(t *testing.T) {
Config: testAccAWSSecurityGroupConfigTags,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityGroupExists("aws_security_group.foo", &group),
testAccCheckTagsSDK(&group.Tags, "foo", "bar"),
testAccCheckTags(&group.Tags, "foo", "bar"),
),
},
@ -304,8 +304,8 @@ func TestAccAWSSecurityGroup_tags(t *testing.T) {
Config: testAccAWSSecurityGroupConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityGroupExists("aws_security_group.foo", &group),
testAccCheckTagsSDK(&group.Tags, "foo", ""),
testAccCheckTagsSDK(&group.Tags, "bar", "baz"),
testAccCheckTags(&group.Tags, "foo", ""),
testAccCheckTags(&group.Tags, "bar", "baz"),
),
},
},

View File

@ -51,7 +51,7 @@ func resourceAwsSubnet() *schema.Resource {
}
func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
createOpts := &ec2.CreateSubnetRequest{
AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
@ -91,7 +91,7 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
SubnetIDs: []string{d.Id()},
@ -115,17 +115,17 @@ func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
d.Set("availability_zone", subnet.AvailabilityZone)
d.Set("cidr_block", subnet.CIDRBlock)
d.Set("map_public_ip_on_launch", subnet.MapPublicIPOnLaunch)
d.Set("tags", tagsToMapSDK(subnet.Tags))
d.Set("tags", tagsToMap(subnet.Tags))
return nil
}
func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
d.Partial(true)
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
@ -154,7 +154,7 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
}
func resourceAwsSubnetDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
log.Printf("[INFO] Deleting subnet: %s", d.Id())

View File

@ -43,7 +43,7 @@ func TestAccAWSSubnet(t *testing.T) {
}
func testAccCheckSubnetDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_subnet" {
@ -86,7 +86,7 @@ func testAccCheckSubnetExists(n string, v *ec2.Subnet) resource.TestCheckFunc {
return fmt.Errorf("No ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
SubnetIDs: []string{rs.Primary.ID},
})

View File

@ -5,9 +5,10 @@ import (
"log"
"time"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
)
func resourceAwsVpc() *schema.Resource {
@ -64,22 +65,25 @@ func resourceAwsVpc() *schema.Resource {
func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
// Create the VPC
createOpts := &ec2.CreateVpc{
CidrBlock: d.Get("cidr_block").(string),
InstanceTenancy: d.Get("instance_tenancy").(string),
instance_tenancy := "default"
if v, ok := d.GetOk("instance_tenancy"); ok {
instance_tenancy = v.(string)
}
log.Printf("[DEBUG] VPC create config: %#v", createOpts)
vpcResp, err := ec2conn.CreateVpc(createOpts)
// Create the VPC
createOpts := &ec2.CreateVPCRequest{
CIDRBlock: aws.String(d.Get("cidr_block").(string)),
InstanceTenancy: aws.String(instance_tenancy),
}
log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
vpcResp, err := ec2conn.CreateVPC(createOpts)
if err != nil {
return fmt.Errorf("Error creating VPC: %s", err)
}
// Get the ID and store it
vpc := &vpcResp.VPC
log.Printf("[INFO] VPC ID: %s", vpc.VpcId)
d.SetId(vpc.VpcId)
vpc := vpcResp.VPC
d.SetId(*vpc.VPCID)
log.Printf("[INFO] VPC ID: %s", d.Id())
// Set partial mode and say that we setup the cidr block
d.Partial(true)
@ -120,34 +124,53 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
// VPC stuff
vpc := vpcRaw.(*ec2.VPC)
d.Set("cidr_block", vpc.CidrBlock)
vpcid := d.Id()
d.Set("cidr_block", vpc.CIDRBlock)
// Tags
d.Set("tags", tagsToMap(vpc.Tags))
// Attributes
resp, err := ec2conn.VpcAttribute(d.Id(), "enableDnsSupport")
attribute := "enableDnsSupport"
DescribeAttrOpts := &ec2.DescribeVPCAttributeRequest{
Attribute: aws.String(attribute),
VPCID: aws.String(vpcid),
}
resp, err := ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
if err != nil {
return err
}
d.Set("enable_dns_support", resp.EnableDnsSupport)
resp, err = ec2conn.VpcAttribute(d.Id(), "enableDnsHostnames")
d.Set("enable_dns_support", *resp.EnableDNSSupport)
attribute = "enableDnsHostnames"
DescribeAttrOpts = &ec2.DescribeVPCAttributeRequest{
Attribute: &attribute,
VPCID: &vpcid,
}
resp, err = ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
if err != nil {
return err
}
d.Set("enable_dns_hostnames", resp.EnableDnsHostnames)
d.Set("enable_dns_hostnames", *resp.EnableDNSHostnames)
// Get the main routing table for this VPC
filter := ec2.NewFilter()
filter.Add("association.main", "true")
filter.Add("vpc-id", d.Id())
routeResp, err := ec2conn.DescribeRouteTables(nil, filter)
// Really Ugly need to make this better - rmenn
filter1 := &ec2.Filter{
Name: aws.String("association.main"),
Values: []string{("true")},
}
filter2 := &ec2.Filter{
Name: aws.String("vpc-id"),
Values: []string{(d.Id())},
}
DescribeRouteOpts := &ec2.DescribeRouteTablesRequest{
Filters: []ec2.Filter{*filter1, *filter2},
}
routeResp, err := ec2conn.DescribeRouteTables(DescribeRouteOpts)
if err != nil {
return err
}
if v := routeResp.RouteTables; len(v) > 0 {
d.Set("main_route_table_id", v[0].RouteTableId)
d.Set("main_route_table_id", *v[0].RouteTableID)
}
resourceAwsVpcSetDefaultNetworkAcl(ec2conn, d)
@ -161,16 +184,20 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
// Turn on partial mode
d.Partial(true)
vpcid := d.Id()
modifyOpts := &ec2.ModifyVPCAttributeRequest{
VPCID: &vpcid,
}
if d.HasChange("enable_dns_hostnames") {
options := new(ec2.ModifyVpcAttribute)
options.EnableDnsHostnames = d.Get("enable_dns_hostnames").(bool)
options.SetEnableDnsHostnames = true
val := d.Get("enable_dns_hostnames").(bool)
modifyOpts.EnableDNSHostnames = &ec2.AttributeBooleanValue{
Value: &val,
}
log.Printf(
"[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v",
d.Id(), options)
if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil {
d.Id(), modifyOpts)
if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
return err
}
@ -178,14 +205,15 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
}
if d.HasChange("enable_dns_support") {
options := new(ec2.ModifyVpcAttribute)
options.EnableDnsSupport = d.Get("enable_dns_support").(bool)
options.SetEnableDnsSupport = true
val := d.Get("enable_dns_hostnames").(bool)
modifyOpts.EnableDNSSupport = &ec2.AttributeBooleanValue{
Value: &val,
}
log.Printf(
"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
d.Id(), options)
if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil {
d.Id(), modifyOpts)
if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
return err
}
@ -204,10 +232,13 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
vpcID := d.Id()
DeleteVpcOpts := &ec2.DeleteVPCRequest{
VPCID: &vpcID,
}
log.Printf("[INFO] Deleting VPC: %s", d.Id())
if _, err := ec2conn.DeleteVpc(d.Id()); err != nil {
ec2err, ok := err.(*ec2.Error)
if err := ec2conn.DeleteVPC(DeleteVpcOpts); err != nil {
ec2err, ok := err.(*aws.APIError)
if ok && ec2err.Code == "InvalidVpcID.NotFound" {
return nil
}
@ -222,9 +253,12 @@ func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
// a VPC.
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.DescribeVpcs([]string{id}, ec2.NewFilter())
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
VPCIDs: []string{id},
}
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
if err != nil {
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcID.NotFound" {
if ec2err, ok := err.(*aws.APIError); ok && ec2err.Code == "InvalidVpcID.NotFound" {
resp = nil
} else {
log.Printf("Error on VPCStateRefresh: %s", err)
@ -239,37 +273,53 @@ func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
}
vpc := &resp.VPCs[0]
return vpc, vpc.State, nil
return vpc, *vpc.State, nil
}
}
func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
filter := ec2.NewFilter()
filter.Add("default", "true")
filter.Add("vpc-id", d.Id())
networkAclResp, err := conn.NetworkAcls(nil, filter)
filter1 := &ec2.Filter{
Name: aws.String("default"),
Values: []string{("true")},
}
filter2 := &ec2.Filter{
Name: aws.String("vpc-id"),
Values: []string{(d.Id())},
}
DescribeNetworkACLOpts := &ec2.DescribeNetworkACLsRequest{
Filters: []ec2.Filter{*filter1, *filter2},
}
networkAclResp, err := conn.DescribeNetworkACLs(DescribeNetworkACLOpts)
if err != nil {
return err
}
if v := networkAclResp.NetworkAcls; len(v) > 0 {
d.Set("default_network_acl_id", v[0].NetworkAclId)
if v := networkAclResp.NetworkACLs; len(v) > 0 {
d.Set("default_network_acl_id", v[0].NetworkACLID)
}
return nil
}
func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
filter := ec2.NewFilter()
filter.Add("group-name", "default")
filter.Add("vpc-id", d.Id())
securityGroupResp, err := conn.SecurityGroups(nil, filter)
filter1 := &ec2.Filter{
Name: aws.String("group-name"),
Values: []string{("default")},
}
filter2 := &ec2.Filter{
Name: aws.String("vpc-id"),
Values: []string{(d.Id())},
}
DescribeSgOpts := &ec2.DescribeSecurityGroupsRequest{
Filters: []ec2.Filter{*filter1, *filter2},
}
securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)
if err != nil {
return err
}
if v := securityGroupResp.Groups; len(v) > 0 {
d.Set("default_security_group_id", v[0].Id)
if v := securityGroupResp.SecurityGroups; len(v) > 0 {
d.Set("default_security_group_id", v[0].GroupID)
}
return nil

View File

@ -41,7 +41,7 @@ func resourceAwsVpcPeeringConnection() *schema.Resource {
}
func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
// Create the vpc peering connection
createOpts := &ec2.CreateVPCPeeringConnectionRequest{
@ -80,7 +80,7 @@ func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error
}
func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
return err
@ -95,15 +95,15 @@ func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
d.Set("peer_owner_id", pc.AccepterVPCInfo.OwnerID)
d.Set("peer_vpc_id", pc.AccepterVPCInfo.VPCID)
d.Set("vpc_id", pc.RequesterVPCInfo.VPCID)
d.Set("tags", tagsToMapSDK(pc.Tags))
d.Set("tags", tagsToMap(pc.Tags))
return nil
}
func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
if err := setTagsSDK(ec2conn, d); err != nil {
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
@ -113,7 +113,7 @@ func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error
}
func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn
ec2conn := meta.(*AWSClient).ec2conn
_, err := ec2conn.DeleteVPCPeeringConnection(
&ec2.DeleteVPCPeeringConnectionRequest{

View File

@ -28,7 +28,7 @@ func TestAccAWSVPCPeeringConnection_normal(t *testing.T) {
}
func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_vpc_peering_connection" {

View File

@ -2,11 +2,11 @@ package aws
import (
"fmt"
"testing"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/goamz/ec2"
"testing"
)
func TestAccVpc_basic(t *testing.T) {
@ -119,7 +119,10 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
}
// Try to find the VPC
resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter())
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
VPCIDs: []string{rs.Primary.ID},
}
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
if err == nil {
if len(resp.VPCs) > 0 {
return fmt.Errorf("VPCs still exist.")
@ -129,7 +132,7 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
}
// Verify the error is what we want
ec2err, ok := err.(*ec2.Error)
ec2err, ok := err.(*aws.APIError)
if !ok {
return err
}
@ -143,8 +146,9 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
func testAccCheckVpcCidr(vpc *ec2.VPC, expected string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if vpc.CidrBlock != expected {
return fmt.Errorf("Bad cidr: %s", vpc.CidrBlock)
CIDRBlock := vpc.CIDRBlock
if *CIDRBlock != expected {
return fmt.Errorf("Bad cidr: %s", *vpc.CIDRBlock)
}
return nil
@ -163,7 +167,10 @@ func testAccCheckVpcExists(n string, vpc *ec2.VPC) resource.TestCheckFunc {
}
conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter())
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
VPCIDs: []string{rs.Primary.ID},
}
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
if err != nil {
return err
}

View File

@ -4,11 +4,10 @@ import (
"strings"
"github.com/hashicorp/aws-sdk-go/aws"
awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/aws-sdk-go/gen/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
)
// Takes the result of flatmap.Expand for an array of listeners and
@ -17,7 +16,7 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) {
listeners := make([]elb.Listener, 0, len(configured))
// Loop over our configured listeners and create
// an array of goamz compatabile objects
// an array of aws-sdk-go compatabile objects
for _, lRaw := range configured {
data := lRaw.(map[string]interface{})
@ -40,10 +39,13 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) {
// Takes the result of flatmap.Expand for an array of ingress/egress
// security group rules and returns EC2 API compatible objects
func expandIPPerms(id string, configured []interface{}) []awsEC2.IPPermission {
perms := make([]awsEC2.IPPermission, len(configured))
func expandIPPerms(
group ec2.SecurityGroup, configured []interface{}) []ec2.IPPermission {
vpc := group.VPCID != nil
perms := make([]ec2.IPPermission, len(configured))
for i, mRaw := range configured {
var perm awsEC2.IPPermission
var perm ec2.IPPermission
m := mRaw.(map[string]interface{})
perm.FromPort = aws.Integer(m["from_port"].(int))
@ -58,29 +60,38 @@ func expandIPPerms(id string, configured []interface{}) []awsEC2.IPPermission {
}
}
if v, ok := m["self"]; ok && v.(bool) {
groups = append(groups, id)
if vpc {
groups = append(groups, *group.GroupID)
} else {
groups = append(groups, *group.GroupName)
}
}
if len(groups) > 0 {
perm.UserIDGroupPairs = make([]awsEC2.UserIDGroupPair, len(groups))
perm.UserIDGroupPairs = make([]ec2.UserIDGroupPair, len(groups))
for i, name := range groups {
ownerId, id := "", name
if items := strings.Split(id, "/"); len(items) > 1 {
ownerId, id = items[0], items[1]
}
perm.UserIDGroupPairs[i] = awsEC2.UserIDGroupPair{
perm.UserIDGroupPairs[i] = ec2.UserIDGroupPair{
GroupID: aws.String(id),
UserID: aws.String(ownerId),
}
if !vpc {
perm.UserIDGroupPairs[i].GroupID = nil
perm.UserIDGroupPairs[i].GroupName = aws.String(id)
perm.UserIDGroupPairs[i].UserID = nil
}
}
}
if raw, ok := m["cidr_blocks"]; ok {
list := raw.([]interface{})
perm.IPRanges = make([]awsEC2.IPRange, len(list))
perm.IPRanges = make([]ec2.IPRange, len(list))
for i, v := range list {
perm.IPRanges[i] = awsEC2.IPRange{aws.String(v.(string))}
perm.IPRanges[i] = ec2.IPRange{aws.String(v.(string))}
}
}
@ -96,7 +107,7 @@ func expandParameters(configured []interface{}) ([]rds.Parameter, error) {
parameters := make([]rds.Parameter, 0, len(configured))
// Loop over our configured parameters and create
// an array of goamz compatabile objects
// an array of aws-sdk-go compatabile objects
for _, pRaw := range configured {
data := pRaw.(map[string]interface{})
@ -130,16 +141,7 @@ func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
}
// Flattens an array of UserSecurityGroups into a []string
func flattenSecurityGroups(list []ec2.UserSecurityGroup) []string {
result := make([]string, 0, len(list))
for _, g := range list {
result = append(result, g.Id)
}
return result
}
// Flattens an array of UserSecurityGroups into a []string
func flattenSecurityGroupsSDK(list []awsEC2.UserIDGroupPair) []string {
func flattenSecurityGroups(list []ec2.UserIDGroupPair) []string {
result := make([]string, 0, len(list))
for _, g := range list {
result = append(result, *g.GroupID)

View File

@ -5,7 +5,7 @@ import (
"testing"
"github.com/hashicorp/aws-sdk-go/aws"
awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
ec2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/aws-sdk-go/gen/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/terraform/flatmap"
@ -59,30 +59,34 @@ func TestExpandIPPerms(t *testing.T) {
"self": true,
},
}
perms := expandIPPerms("foo", expanded)
group := ec2.SecurityGroup{
GroupID: aws.String("foo"),
VPCID: aws.String("bar"),
}
perms := expandIPPerms(group, expanded)
expected := []awsEC2.IPPermission{
awsEC2.IPPermission{
expected := []ec2.IPPermission{
ec2.IPPermission{
IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1),
ToPort: aws.Integer(-1),
IPRanges: []awsEC2.IPRange{awsEC2.IPRange{aws.String("0.0.0.0/0")}},
UserIDGroupPairs: []awsEC2.UserIDGroupPair{
awsEC2.UserIDGroupPair{
IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("0.0.0.0/0")}},
UserIDGroupPairs: []ec2.UserIDGroupPair{
ec2.UserIDGroupPair{
UserID: aws.String("foo"),
GroupID: aws.String("sg-22222"),
},
awsEC2.UserIDGroupPair{
ec2.UserIDGroupPair{
GroupID: aws.String("sg-22222"),
},
},
},
awsEC2.IPPermission{
ec2.IPPermission{
IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1),
ToPort: aws.Integer(-1),
UserIDGroupPairs: []awsEC2.UserIDGroupPair{
awsEC2.UserIDGroupPair{
UserIDGroupPairs: []ec2.UserIDGroupPair{
ec2.UserIDGroupPair{
UserID: aws.String("foo"),
},
},
@ -115,6 +119,79 @@ func TestExpandIPPerms(t *testing.T) {
}
func TestExpandIPPerms_nonVPC(t *testing.T) {
hash := func(v interface{}) int {
return hashcode.String(v.(string))
}
expanded := []interface{}{
map[string]interface{}{
"protocol": "icmp",
"from_port": 1,
"to_port": -1,
"cidr_blocks": []interface{}{"0.0.0.0/0"},
"security_groups": schema.NewSet(hash, []interface{}{
"sg-11111",
"foo/sg-22222",
}),
},
map[string]interface{}{
"protocol": "icmp",
"from_port": 1,
"to_port": -1,
"self": true,
},
}
group := ec2.SecurityGroup{
GroupName: aws.String("foo"),
}
perms := expandIPPerms(group, expanded)
expected := []ec2.IPPermission{
ec2.IPPermission{
IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1),
ToPort: aws.Integer(-1),
IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("0.0.0.0/0")}},
UserIDGroupPairs: []ec2.UserIDGroupPair{
ec2.UserIDGroupPair{
GroupName: aws.String("sg-22222"),
},
ec2.UserIDGroupPair{
GroupName: aws.String("sg-22222"),
},
},
},
ec2.IPPermission{
IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1),
ToPort: aws.Integer(-1),
UserIDGroupPairs: []ec2.UserIDGroupPair{
ec2.UserIDGroupPair{
GroupName: aws.String("foo"),
},
},
},
}
exp := expected[0]
perm := perms[0]
if *exp.FromPort != *perm.FromPort {
t.Fatalf(
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
*perm.FromPort,
*exp.FromPort)
}
if *exp.IPRanges[0].CIDRIP != *perm.IPRanges[0].CIDRIP {
t.Fatalf(
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
*perm.IPRanges[0].CIDRIP,
*exp.IPRanges[0].CIDRIP)
}
}
func TestExpandListeners(t *testing.T) {
expanded := []interface{}{
map[string]interface{}{

View File

@ -3,11 +3,13 @@ package aws
import (
"log"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
)
// tagsSchema returns the schema to use for tags.
//
func tagsSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeMap,
@ -27,13 +29,21 @@ func setTags(conn *ec2.EC2, d *schema.ResourceData) error {
// Set tags
if len(remove) > 0 {
log.Printf("[DEBUG] Removing tags: %#v", remove)
if _, err := conn.DeleteTags([]string{d.Id()}, remove); err != nil {
err := conn.DeleteTags(&ec2.DeleteTagsRequest{
Resources: []string{d.Id()},
Tags: remove,
})
if err != nil {
return err
}
}
if len(create) > 0 {
log.Printf("[DEBUG] Creating tags: %#v", create)
if _, err := conn.CreateTags([]string{d.Id()}, create); err != nil {
err := conn.CreateTags(&ec2.CreateTagsRequest{
Resources: []string{d.Id()},
Tags: create,
})
if err != nil {
return err
}
}
@ -49,14 +59,14 @@ func diffTags(oldTags, newTags []ec2.Tag) ([]ec2.Tag, []ec2.Tag) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
create[t.Key] = t.Value
create[*t.Key] = *t.Value
}
// Build the list of what to remove
var remove []ec2.Tag
for _, t := range oldTags {
old, ok := create[t.Key]
if !ok || old != t.Value {
old, ok := create[*t.Key]
if !ok || old != *t.Value {
// Delete it!
remove = append(remove, t)
}
@ -70,8 +80,8 @@ func tagsFromMap(m map[string]interface{}) []ec2.Tag {
result := make([]ec2.Tag, 0, len(m))
for k, v := range m {
result = append(result, ec2.Tag{
Key: k,
Value: v.(string),
Key: aws.String(k),
Value: aws.String(v.(string)),
})
}
@ -82,7 +92,7 @@ func tagsFromMap(m map[string]interface{}) []ec2.Tag {
func tagsToMap(ts []ec2.Tag) map[string]string {
result := make(map[string]string)
for _, t := range ts {
result[t.Key] = t.Value
result[*t.Key] = *t.Value
}
return result

View File

@ -1,106 +0,0 @@
package aws
// TODO: Clint: consolidate tags and tags_sdk
// tags_sdk and tags_sdk_test are used only for transition to aws-sdk-go
// and will replace tags and tags_test when the transition to aws-sdk-go/ec2 is
// complete
import (
"log"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/schema"
)
// tagsSchema returns the schema to use for tags.
//
// TODO: uncomment this when we replace the original tags.go
//
// func tagsSchema() *schema.Schema {
// return &schema.Schema{
// Type: schema.TypeMap,
// Optional: true,
// }
// }
// setTags is a helper to set the tags for a resource. It expects the
// tags field to be named "tags"
func setTagsSDK(conn *ec2.EC2, d *schema.ResourceData) error {
if d.HasChange("tags") {
oraw, nraw := d.GetChange("tags")
o := oraw.(map[string]interface{})
n := nraw.(map[string]interface{})
create, remove := diffTagsSDK(tagsFromMapSDK(o), tagsFromMapSDK(n))
// Set tags
if len(remove) > 0 {
log.Printf("[DEBUG] Removing tags: %#v", remove)
err := conn.DeleteTags(&ec2.DeleteTagsRequest{
Resources: []string{d.Id()},
Tags: remove,
})
if err != nil {
return err
}
}
if len(create) > 0 {
log.Printf("[DEBUG] Creating tags: %#v", create)
err := conn.CreateTags(&ec2.CreateTagsRequest{
Resources: []string{d.Id()},
Tags: create,
})
if err != nil {
return err
}
}
}
return nil
}
// diffTags takes our tags locally and the ones remotely and returns
// the set of tags that must be created, and the set of tags that must
// be destroyed.
func diffTagsSDK(oldTags, newTags []ec2.Tag) ([]ec2.Tag, []ec2.Tag) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
create[*t.Key] = *t.Value
}
// Build the list of what to remove
var remove []ec2.Tag
for _, t := range oldTags {
old, ok := create[*t.Key]
if !ok || old != *t.Value {
// Delete it!
remove = append(remove, t)
}
}
return tagsFromMapSDK(create), remove
}
// tagsFromMap returns the tags for the given map of data.
func tagsFromMapSDK(m map[string]interface{}) []ec2.Tag {
result := make([]ec2.Tag, 0, len(m))
for k, v := range m {
result = append(result, ec2.Tag{
Key: aws.String(k),
Value: aws.String(v.(string)),
})
}
return result
}
// tagsToMap turns the list of tags into a map.
func tagsToMapSDK(ts []ec2.Tag) map[string]string {
result := make(map[string]string)
for _, t := range ts {
result[*t.Key] = *t.Value
}
return result
}

View File

@ -1,85 +0,0 @@
package aws
import (
"fmt"
"reflect"
"testing"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestDiffTagsSDK(t *testing.T) {
cases := []struct {
Old, New map[string]interface{}
Create, Remove map[string]string
}{
// Basic add/remove
{
Old: map[string]interface{}{
"foo": "bar",
},
New: map[string]interface{}{
"bar": "baz",
},
Create: map[string]string{
"bar": "baz",
},
Remove: map[string]string{
"foo": "bar",
},
},
// Modify
{
Old: map[string]interface{}{
"foo": "bar",
},
New: map[string]interface{}{
"foo": "baz",
},
Create: map[string]string{
"foo": "baz",
},
Remove: map[string]string{
"foo": "bar",
},
},
}
for i, tc := range cases {
c, r := diffTagsSDK(tagsFromMapSDK(tc.Old), tagsFromMapSDK(tc.New))
cm := tagsToMapSDK(c)
rm := tagsToMapSDK(r)
if !reflect.DeepEqual(cm, tc.Create) {
t.Fatalf("%d: bad create: %#v", i, cm)
}
if !reflect.DeepEqual(rm, tc.Remove) {
t.Fatalf("%d: bad remove: %#v", i, rm)
}
}
}
// testAccCheckTags can be used to check the tags on a resource.
func testAccCheckTagsSDK(
ts *[]ec2.Tag, key string, value string) resource.TestCheckFunc {
return func(s *terraform.State) error {
m := tagsToMapSDK(*ts)
v, ok := m[key]
if value != "" && !ok {
return fmt.Errorf("Missing tag: %s", key)
} else if value == "" && ok {
return fmt.Errorf("Extra tag: %s", key)
}
if value == "" {
return nil
}
if v != value {
return fmt.Errorf("%s: bad value: %s", key, v)
}
return nil
}
}

View File

@ -5,9 +5,9 @@ import (
"reflect"
"testing"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/goamz/ec2"
)
func TestDiffTags(t *testing.T) {

View File

@ -20,6 +20,9 @@ func consulFactory(conf map[string]string) (Client, error) {
if addr, ok := conf["address"]; ok && addr != "" {
config.Address = addr
}
if scheme, ok := conf["scheme"]; ok && scheme != "" {
config.Scheme = scheme
}
client, err := consulapi.NewClient(config)
if err != nil {

View File

@ -16,7 +16,7 @@ Terraform will automatically fetch the latest state from the remote
server when necessary and if any updates are made, the newest state
is persisted back to the remote server.
In this mode, users do not need to durably store the state using version
control or shared storaged.
control or shared storage.
## Usage

View File

@ -29,6 +29,18 @@ The following arguments are supported:
* `vpc_id` - (Required) The VPC ID to create in.
* `tags` - (Optional) A mapping of tags to assign to the resource.
-> **Note:** It's recommended to denote that the AWS Instance or Elastic IP depends on the Internet Gateway. For example:
resource "aws_internet_gateway" "gw" {
vpc_id = "${aws_vpc.main.id}"
}
resource "aws_instance" "foo" {
depends_on = ["aws_internet_gateway.gw"]
}
## Attributes Reference
The following attributes are exported:

View File

@ -17,7 +17,7 @@ Basic usage
```
resource "aws_security_group" "allow_all" {
name = "allow_all"
description = "Allow all inbound traffic"
description = "Allow all inbound traffic"
ingress {
from_port = 0

View File

@ -56,4 +56,4 @@ The following attributes are exported:
## Notes
You still have to accept the peering with the aws console, aws-cli or goamz
You still have to accept the peering with the aws console, aws-cli or aws-sdk-go.