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 ( import (
"fmt" "fmt"
"log" "log"
"strings"
"unicode"
"github.com/hashicorp/terraform/helper/multierror" "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/autoscaling"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/aws-sdk-go/gen/elb" "github.com/hashicorp/aws-sdk-go/gen/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds" "github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/aws-sdk-go/gen/route53" "github.com/hashicorp/aws-sdk-go/gen/route53"
"github.com/hashicorp/aws-sdk-go/gen/s3" "github.com/hashicorp/aws-sdk-go/gen/s3"
awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
) )
type Config struct { type Config struct {
@ -29,7 +24,6 @@ type Config struct {
type AWSClient struct { type AWSClient struct {
ec2conn *ec2.EC2 ec2conn *ec2.EC2
awsEC2conn *awsEC2.EC2
elbconn *elb.ELB elbconn *elb.ELB
autoscalingconn *autoscaling.AutoScaling autoscalingconn *autoscaling.AutoScaling
s3conn *s3.S3 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 // Get the auth and region. This can fail if keys/regions were not
// specified and we're attempting to use the environment. // specified and we're attempting to use the environment.
var errs []error 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") log.Println("[INFO] Building AWS region structure")
region, err := c.AWSRegion() err := c.ValidateRegion()
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
@ -62,10 +51,9 @@ func (c *Config) Client() (interface{}, error) {
// bucket storage in S3 // bucket storage in S3
client.region = c.Region 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") log.Println("[INFO] Initializing ELB connection")
client.elbconn = elb.New(creds, c.Region, nil) client.elbconn = elb.New(creds, c.Region, nil)
log.Println("[INFO] Initializing AutoScaling connection") 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 // See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
log.Println("[INFO] Initializing Route53 connection") log.Println("[INFO] Initializing Route53 connection")
client.r53conn = route53.New(creds, "us-east-1", nil) client.r53conn = route53.New(creds, "us-east-1", nil)
log.Println("[INFO] Initializing AWS-GO EC2 Connection") log.Println("[INFO] Initializing EC2 Connection")
client.awsEC2conn = awsEC2.New(creds, c.Region, nil) client.ec2conn = ec2.New(creds, c.Region, nil)
} }
if len(errs) > 0 { if len(errs) > 0 {
@ -91,54 +79,17 @@ func (c *Config) Client() (interface{}, error) {
return &client, nil 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 // IsValidRegion returns true if the configured region is a valid AWS
// region and false if it's not // 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", 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", "eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1",
"sa-east-1", "cn-north-1", "us-gov-west-1"} "sa-east-1", "cn-north-1", "us-gov-west-1"}
for _, valid := range regions { for _, valid := range regions {
if c.Region == valid { if c.Region == valid {
return true return nil
} }
} }
return false return fmt.Errorf("Not a valid region: %s", c.Region)
}
// 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
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"log" "log"
"strings"
"time" "time"
"github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/hashcode"
@ -152,7 +153,7 @@ func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{})
os := o.(*schema.Set) os := o.(*schema.Set)
ns := n.(*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()) parameters, err := expandParameters(ns.Difference(os).List())
if err != nil { if err != nil {
return err return err
@ -220,7 +221,8 @@ func resourceAwsDbParameterHash(v interface{}) int {
var buf bytes.Buffer var buf bytes.Buffer
m := v.(map[string]interface{}) m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 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()) return hashcode.String(buf.String())
} }

View File

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

View File

@ -58,7 +58,7 @@ func TestAccAWSEIP_instance(t *testing.T) {
} }
func testAccCheckAWSEIPDestroy(s *terraform.State) error { func testAccCheckAWSEIPDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_eip" { 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") 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") { if strings.Contains(rs.Primary.ID, "eipalloc") {
req := &ec2.DescribeAddressesRequest{ req := &ec2.DescribeAddressesRequest{

View File

@ -161,7 +161,7 @@ func resourceAwsElb() *schema.Resource {
func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbconn 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()) listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
if err != nil { if err != nil {
return err return err

View File

@ -3,6 +3,7 @@ package aws
import ( import (
"bytes" "bytes"
"crypto/sha1" "crypto/sha1"
"encoding/base64"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"log" "log"
@ -253,17 +254,19 @@ func resourceAwsInstance() *schema.Resource {
} }
func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
// Figure out user data // Figure out user data
userData := "" userData := ""
if v := d.Get("user_data"); v != nil { if v := d.Get("user_data"); v != nil {
userData = v.(string) userData = base64.StdEncoding.EncodeToString([]byte(v.(string)))
} }
placement := &ec2.Placement{ placement := &ec2.Placement{
AvailabilityZone: aws.String(d.Get("availability_zone").(string)), 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{ iam := &ec2.IAMInstanceProfileSpecification{
@ -292,6 +295,17 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
subnet, hasSubnet := d.GetOk("subnet_id") subnet, hasSubnet := d.GetOk("subnet_id")
subnetID := subnet.(string) 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 hasSubnet && associatePublicIPAddress {
// If we have a non-default VPC / Subnet specified, we can flag // 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. // 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)) ni.PrivateIPAddress = aws.String(v.(string))
} }
if len(groups) > 0 {
ni.Groups = groups
}
runOpts.NetworkInterfaces = []ec2.InstanceNetworkInterfaceSpecification{ni} runOpts.NetworkInterfaces = []ec2.InstanceNetworkInterfaceSpecification{ni}
} else { } else {
if subnetID != "" { if subnetID != "" {
@ -319,21 +337,6 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
if v, ok := d.GetOk("private_ip"); ok { if v, ok := d.GetOk("private_ip"); ok {
runOpts.PrivateIPAddress = aws.String(v.(string)) 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 && if runOpts.SubnetID != nil &&
*runOpts.SubnetID != "" { *runOpts.SubnetID != "" {
runOpts.SecurityGroupIDs = groups 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) blockDevices := make([]interface{}, 0)
if v := d.Get("block_device"); v != nil { 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 { func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
resp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesRequest{ resp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesRequest{
InstanceIDs: []string{d.Id()}, InstanceIDs: []string{d.Id()},
@ -481,7 +488,7 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("subnet_id", instance.SubnetID) d.Set("subnet_id", instance.SubnetID)
} }
d.Set("ebs_optimized", instance.EBSOptimized) d.Set("ebs_optimized", instance.EBSOptimized)
d.Set("tags", tagsToMapSDK(instance.Tags)) d.Set("tags", tagsToMap(instance.Tags))
d.Set("tenancy", instance.Placement.Tenancy) d.Set("tenancy", instance.Placement.Tenancy)
// Determine whether we're referring to security groups with // 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 // 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 // all-name list of security groups, we use names. Or, if we had any
// IDs, we use IDs. // IDs, we use IDs.
useID := *instance.SubnetID != "" useID := instance.SubnetID != nil && *instance.SubnetID != ""
if v := d.Get("security_groups"); v != nil { if v := d.Get("security_groups"); v != nil {
match := false match := false
for _, v := range v.(*schema.Set).List() { 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 { func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
opts := new(ec2.ModifyInstanceAttributeRequest)
log.Printf("[INFO] Modifying instance %s: %#v", d.Id(), opts) // 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{ err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeRequest{
InstanceID: aws.String(d.Id()), InstanceID: aws.String(d.Id()),
SourceDestCheck: &ec2.AttributeBooleanValue{ SourceDestCheck: &ec2.AttributeBooleanValue{
Value: aws.Boolean(d.Get("source_dest_check").(bool)), Value: aws.Boolean(d.Get("source_dest_check").(bool)),
}, },
}) })
if err != nil { if err != nil {
return err return err
} }
}
// TODO(mitchellh): wait for the attributes we modified to // TODO(mitchellh): wait for the attributes we modified to
// persist the change... // persist the change...
if err := setTagsSDK(ec2conn, d); err != nil { if err := setTags(ec2conn, d); err != nil {
return err return err
} else { } else {
d.SetPartial("tags") d.SetPartial("tags")
@ -589,7 +597,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
} }
func resourceAwsInstanceDelete(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()) log.Printf("[INFO] Terminating instance: %s", d.Id())
req := &ec2.TerminateInstancesRequest{ req := &ec2.TerminateInstancesRequest{

View File

@ -44,7 +44,7 @@ func TestAccAWSInstance_normal(t *testing.T) {
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"aws_instance.foo", "aws_instance.foo",
"user_data", "user_data",
"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), "3dc39dda39be1205215e776bad998da361a5955d"),
), ),
}, },
@ -60,7 +60,7 @@ func TestAccAWSInstance_normal(t *testing.T) {
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"aws_instance.foo", "aws_instance.foo",
"user_data", "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) { func TestAccAWSInstance_tags(t *testing.T) {
var v ec2.Instance var v ec2.Instance
@ -219,9 +238,9 @@ func TestAccAWSInstance_tags(t *testing.T) {
Config: testAccCheckInstanceConfigTags, Config: testAccCheckInstanceConfigTags,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("aws_instance.foo", &v), 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 // 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, Config: testAccCheckInstanceConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("aws_instance.foo", &v), testAccCheckInstanceExists("aws_instance.foo", &v),
testAccCheckTagsSDK(&v.Tags, "foo", ""), testAccCheckTags(&v.Tags, "foo", ""),
testAccCheckTagsSDK(&v.Tags, "bar", "baz"), testAccCheckTags(&v.Tags, "bar", "baz"),
), ),
}, },
}, },
@ -296,7 +315,7 @@ func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
} }
func testAccCheckInstanceDestroy(s *terraform.State) error { func testAccCheckInstanceDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_instance" { 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") return fmt.Errorf("No ID is set")
} }
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{ resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{
InstanceIDs: []string{rs.Primary.ID}, InstanceIDs: []string{rs.Primary.ID},
}) })
@ -392,7 +411,7 @@ resource "aws_instance" "foo" {
instance_type = "m1.small" instance_type = "m1.small"
security_groups = ["${aws_security_group.tf_test_foo.name}"] 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" 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 { func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
// Create the gateway // Create the gateway
log.Printf("[DEBUG] Creating internet gateway") log.Printf("[DEBUG] Creating internet gateway")
@ -43,7 +43,7 @@ func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{})
d.SetId(*ig.InternetGatewayID) d.SetId(*ig.InternetGatewayID)
log.Printf("[INFO] InternetGateway ID: %s", d.Id()) log.Printf("[INFO] InternetGateway ID: %s", d.Id())
err = setTagsSDK(ec2conn, d) err = setTags(ec2conn, d)
if err != nil { if err != nil {
return err return err
} }
@ -53,7 +53,7 @@ func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{})
} }
func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
igRaw, _, err := IGStateRefreshFunc(ec2conn, d.Id())() igRaw, _, err := IGStateRefreshFunc(ec2conn, d.Id())()
if err != nil { 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("vpc_id", ig.Attachments[0].VPCID)
} }
d.Set("tags", tagsToMapSDK(ig.Tags)) d.Set("tags", tagsToMap(ig.Tags))
return nil 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 return err
} }
@ -103,7 +103,7 @@ func resourceAwsInternetGatewayUpdate(d *schema.ResourceData, meta interface{})
} }
func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error { func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
// Detach if it is attached // Detach if it is attached
if err := resourceAwsInternetGatewayDetach(d, meta); err != nil { 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 { func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
if d.Get("vpc_id").(string) == "" { if d.Get("vpc_id").(string) == "" {
log.Printf( log.Printf(
@ -182,7 +182,7 @@ func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{})
} }
func resourceAwsInternetGatewayDetach(d *schema.ResourceData, meta interface{}) error { func resourceAwsInternetGatewayDetach(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
// Get the old VPC ID to detach from // Get the old VPC ID to detach from
vpcID, _ := d.GetChange("vpc_id") vpcID, _ := d.GetChange("vpc_id")

View File

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

View File

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

View File

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

View File

@ -40,7 +40,7 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource {
} }
func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string) vpcId := d.Get("vpc_id").(string)
routeTableId := d.Get("route_table_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 { func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
mainAssociation, err := findMainRouteTableAssociation( mainAssociation, err := findMainRouteTableAssociation(
ec2conn, 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 // original_route_table_id - this needs to stay recorded as the AWS-created
// table from VPC creation. // table from VPC creation.
func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string) vpcId := d.Get("vpc_id").(string)
routeTableId := d.Get("route_table_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 { func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
vpcId := d.Get("vpc_id").(string) vpcId := d.Get("vpc_id").(string)
originalRouteTableId := d.Get("original_route_table_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) return fmt.Errorf("Not found: %s", vpcResource)
} }
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
mainAssociation, err := findMainRouteTableAssociation(conn, vpc.Primary.ID) mainAssociation, err := findMainRouteTableAssociation(conn, vpc.Primary.ID)
if err != nil { if err != nil {
return err return err

View File

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

View File

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

View File

@ -173,7 +173,8 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro
// Scan for a matching record // Scan for a matching record
found := false found := false
for _, record := range resp.ResourceRecordSets { for _, record := range resp.ResourceRecordSets {
if FQDN(*record.Name) != FQDN(*lopts.StartRecordName) { name := cleanRecordName(*record.Name)
if FQDN(name) != FQDN(*lopts.StartRecordName) {
continue continue
} }
if strings.ToUpper(*record.Type) != strings.ToUpper(*lopts.StartRecordType) { if strings.ToUpper(*record.Type) != strings.ToUpper(*lopts.StartRecordType) {
@ -232,16 +233,18 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
Refresh: func() (interface{}, string, error) { Refresh: func() (interface{}, string, error) {
_, err := conn.ChangeResourceRecordSets(req) _, err := conn.ChangeResourceRecordSets(req)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "PriorRequestNotComplete") { if r53err, ok := err.(aws.APIError); ok {
if r53err.Code == "PriorRequestNotComplete" {
// There is some pending operation, so just retry // There is some pending operation, so just retry
// in a bit. // in a bit.
return 42, "rejected", nil return 42, "rejected", nil
} }
if strings.Contains(err.Error(), "InvalidChangeBatch") { if r53err.Code == "InvalidChangeBatch" {
// This means that the record is already gone. // This means that the record is already gone.
return 42, "accepted", nil return 42, "accepted", nil
} }
}
return 42, "failure", err return 42, "failure", err
} }
@ -282,3 +285,15 @@ func FQDN(name string) string {
return name + "." 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/terraform/terraform"
"github.com/hashicorp/aws-sdk-go/aws" "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) { func TestAccRoute53Record(t *testing.T) {
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) }, 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 { func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).r53conn conn := testAccProvider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
@ -56,7 +97,7 @@ func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
name := parts[1] name := parts[1]
rType := parts[2] rType := parts[2]
lopts := &awsr53.ListResourceRecordSetsRequest{ lopts := &route53.ListResourceRecordSetsRequest{
HostedZoneID: aws.String(cleanZoneID(zone)), HostedZoneID: aws.String(cleanZoneID(zone)),
StartRecordName: aws.String(name), StartRecordName: aws.String(name),
StartRecordType: aws.String(rType), StartRecordType: aws.String(rType),
@ -94,7 +135,7 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
name := parts[1] name := parts[1]
rType := parts[2] rType := parts[2]
lopts := &awsr53.ListResourceRecordSetsRequest{ lopts := &route53.ListResourceRecordSetsRequest{
HostedZoneID: aws.String(cleanZoneID(zone)), HostedZoneID: aws.String(cleanZoneID(zone)),
StartRecordName: aws.String(name), StartRecordName: aws.String(name),
StartRecordType: aws.String(rType), StartRecordType: aws.String(rType),
@ -107,11 +148,14 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
if len(resp.ResourceRecordSets) == 0 { if len(resp.ResourceRecordSets) == 0 {
return fmt.Errorf("Record does not exist") return fmt.Errorf("Record does not exist")
} }
rec := resp.ResourceRecordSets[0] // rec := resp.ResourceRecordSets[0]
if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType { for _, rec := range resp.ResourceRecordSets {
recName := cleanRecordName(*rec.Name)
if FQDN(recName) == FQDN(name) && *rec.Type == rType {
return nil 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"] 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 { func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
// Create the routing table // Create the routing table
createOpts := &ec2.CreateRouteTableRequest{ createOpts := &ec2.CreateRouteTableRequest{
@ -100,7 +100,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAwsRouteTableRead(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())() rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())()
if err != nil { if err != nil {
@ -146,13 +146,13 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
d.Set("route", route) d.Set("route", route)
// Tags // Tags
d.Set("tags", tagsToMapSDK(rt.Tags)) d.Set("tags", tagsToMap(rt.Tags))
return nil return nil
} }
func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error { 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 // Check if the route set as a whole has changed
if d.HasChange("route") { 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 return err
} else { } else {
d.SetPartial("tags") d.SetPartial("tags")
@ -213,7 +213,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAwsRouteTableDelete(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 // First request the routing table since we'll have to disassociate
// all the subnets first. // all the subnets first.

View File

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

View File

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

View File

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

View File

@ -142,7 +142,7 @@ func resourceAwsSecurityGroup() *schema.Resource {
} }
func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
securityGroupOpts := &ec2.CreateSecurityGroupRequest{ securityGroupOpts := &ec2.CreateSecurityGroupRequest{
GroupName: aws.String(d.Get("name").(string)), 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 { func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())() sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
if err != nil { if err != nil {
@ -209,12 +209,12 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro
d.Set("owner_id", sg.OwnerID) d.Set("owner_id", sg.OwnerID)
d.Set("ingress", ingressRules) d.Set("ingress", ingressRules)
d.Set("egress", egressRules) d.Set("egress", egressRules)
d.Set("tags", tagsToMapSDK(sg.Tags)) d.Set("tags", tagsToMap(sg.Tags))
return nil return nil
} }
func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())() sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
if err != nil { 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 return err
} }
@ -249,7 +249,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er
} }
func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { 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()) 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["from_port"].(int)))
buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string))) 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 // 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. // 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 var groups []string
if len(perm.UserIDGroupPairs) > 0 { if len(perm.UserIDGroupPairs) > 0 {
groups = flattenSecurityGroupsSDK(perm.UserIDGroupPairs) groups = flattenSecurityGroups(perm.UserIDGroupPairs)
} }
for i, id := range groups { for i, id := range groups {
if id == d.Id() { if id == d.Id() {
@ -396,9 +397,8 @@ func resourceAwsSecurityGroupUpdateRules(
os := o.(*schema.Set) os := o.(*schema.Set)
ns := n.(*schema.Set) ns := n.(*schema.Set)
// TODO: re-munge this when test is updated remove := expandIPPerms(group, os.Difference(ns).List())
remove := expandIPPerms(d.Id(), os.Difference(ns).List()) add := expandIPPerms(group, ns.Difference(os).List())
add := expandIPPerms(d.Id(), ns.Difference(os).List())
// TODO: We need to handle partial state better in the in-between // TODO: We need to handle partial state better in the in-between
// in this update. // in this update.
@ -410,7 +410,7 @@ func resourceAwsSecurityGroupUpdateRules(
// not have service issues. // not have service issues.
if len(remove) > 0 || len(add) > 0 { if len(remove) > 0 || len(add) > 0 {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
var err error var err error
if len(remove) > 0 { if len(remove) > 0 {
@ -453,6 +453,11 @@ func resourceAwsSecurityGroupUpdateRules(
GroupID: group.GroupID, GroupID: group.GroupID,
IPPermissions: add, IPPermissions: add,
} }
if group.VPCID == nil || *group.VPCID == "" {
req.GroupID = nil
req.GroupName = group.GroupName
}
err = ec2conn.AuthorizeSecurityGroupIngress(req) err = ec2conn.AuthorizeSecurityGroupIngress(req)
} }

View File

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

View File

@ -51,7 +51,7 @@ func resourceAwsSubnet() *schema.Resource {
} }
func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
createOpts := &ec2.CreateSubnetRequest{ createOpts := &ec2.CreateSubnetRequest{
AvailabilityZone: aws.String(d.Get("availability_zone").(string)), 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 { func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{ resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
SubnetIDs: []string{d.Id()}, SubnetIDs: []string{d.Id()},
@ -115,17 +115,17 @@ func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
d.Set("availability_zone", subnet.AvailabilityZone) d.Set("availability_zone", subnet.AvailabilityZone)
d.Set("cidr_block", subnet.CIDRBlock) d.Set("cidr_block", subnet.CIDRBlock)
d.Set("map_public_ip_on_launch", subnet.MapPublicIPOnLaunch) d.Set("map_public_ip_on_launch", subnet.MapPublicIPOnLaunch)
d.Set("tags", tagsToMapSDK(subnet.Tags)) d.Set("tags", tagsToMap(subnet.Tags))
return nil return nil
} }
func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).awsEC2conn ec2conn := meta.(*AWSClient).ec2conn
d.Partial(true) d.Partial(true)
if err := setTagsSDK(ec2conn, d); err != nil { if err := setTags(ec2conn, d); err != nil {
return err return err
} else { } else {
d.SetPartial("tags") d.SetPartial("tags")
@ -154,7 +154,7 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
} }
func resourceAwsSubnetDelete(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()) 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 { func testAccCheckSubnetDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_subnet" { 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") return fmt.Errorf("No ID is set")
} }
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{ resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
SubnetIDs: []string{rs.Primary.ID}, SubnetIDs: []string{rs.Primary.ID},
}) })

View File

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

View File

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

View File

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

View File

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

View File

@ -4,11 +4,10 @@ import (
"strings" "strings"
"github.com/hashicorp/aws-sdk-go/aws" "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/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds" "github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
) )
// Takes the result of flatmap.Expand for an array of listeners and // 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)) listeners := make([]elb.Listener, 0, len(configured))
// Loop over our configured listeners and create // 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 { for _, lRaw := range configured {
data := lRaw.(map[string]interface{}) 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 // Takes the result of flatmap.Expand for an array of ingress/egress
// security group rules and returns EC2 API compatible objects // security group rules and returns EC2 API compatible objects
func expandIPPerms(id string, configured []interface{}) []awsEC2.IPPermission { func expandIPPerms(
perms := make([]awsEC2.IPPermission, len(configured)) group ec2.SecurityGroup, configured []interface{}) []ec2.IPPermission {
vpc := group.VPCID != nil
perms := make([]ec2.IPPermission, len(configured))
for i, mRaw := range configured { for i, mRaw := range configured {
var perm awsEC2.IPPermission var perm ec2.IPPermission
m := mRaw.(map[string]interface{}) m := mRaw.(map[string]interface{})
perm.FromPort = aws.Integer(m["from_port"].(int)) 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) { 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 { if len(groups) > 0 {
perm.UserIDGroupPairs = make([]awsEC2.UserIDGroupPair, len(groups)) perm.UserIDGroupPairs = make([]ec2.UserIDGroupPair, len(groups))
for i, name := range groups { for i, name := range groups {
ownerId, id := "", name ownerId, id := "", name
if items := strings.Split(id, "/"); len(items) > 1 { if items := strings.Split(id, "/"); len(items) > 1 {
ownerId, id = items[0], items[1] ownerId, id = items[0], items[1]
} }
perm.UserIDGroupPairs[i] = awsEC2.UserIDGroupPair{ perm.UserIDGroupPairs[i] = ec2.UserIDGroupPair{
GroupID: aws.String(id), GroupID: aws.String(id),
UserID: aws.String(ownerId), 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 { if raw, ok := m["cidr_blocks"]; ok {
list := raw.([]interface{}) list := raw.([]interface{})
perm.IPRanges = make([]awsEC2.IPRange, len(list)) perm.IPRanges = make([]ec2.IPRange, len(list))
for i, v := range 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)) parameters := make([]rds.Parameter, 0, len(configured))
// Loop over our configured parameters and create // 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 { for _, pRaw := range configured {
data := pRaw.(map[string]interface{}) 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 // Flattens an array of UserSecurityGroups into a []string
func flattenSecurityGroups(list []ec2.UserSecurityGroup) []string { func flattenSecurityGroups(list []ec2.UserIDGroupPair) []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 {
result := make([]string, 0, len(list)) result := make([]string, 0, len(list))
for _, g := range list { for _, g := range list {
result = append(result, *g.GroupID) result = append(result, *g.GroupID)

View File

@ -5,7 +5,7 @@ import (
"testing" "testing"
"github.com/hashicorp/aws-sdk-go/aws" "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/elb"
"github.com/hashicorp/aws-sdk-go/gen/rds" "github.com/hashicorp/aws-sdk-go/gen/rds"
"github.com/hashicorp/terraform/flatmap" "github.com/hashicorp/terraform/flatmap"
@ -59,30 +59,34 @@ func TestExpandIPPerms(t *testing.T) {
"self": true, "self": true,
}, },
} }
perms := expandIPPerms("foo", expanded) group := ec2.SecurityGroup{
GroupID: aws.String("foo"),
VPCID: aws.String("bar"),
}
perms := expandIPPerms(group, expanded)
expected := []awsEC2.IPPermission{ expected := []ec2.IPPermission{
awsEC2.IPPermission{ ec2.IPPermission{
IPProtocol: aws.String("icmp"), IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1), FromPort: aws.Integer(1),
ToPort: aws.Integer(-1), ToPort: aws.Integer(-1),
IPRanges: []awsEC2.IPRange{awsEC2.IPRange{aws.String("0.0.0.0/0")}}, IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("0.0.0.0/0")}},
UserIDGroupPairs: []awsEC2.UserIDGroupPair{ UserIDGroupPairs: []ec2.UserIDGroupPair{
awsEC2.UserIDGroupPair{ ec2.UserIDGroupPair{
UserID: aws.String("foo"), UserID: aws.String("foo"),
GroupID: aws.String("sg-22222"), GroupID: aws.String("sg-22222"),
}, },
awsEC2.UserIDGroupPair{ ec2.UserIDGroupPair{
GroupID: aws.String("sg-22222"), GroupID: aws.String("sg-22222"),
}, },
}, },
}, },
awsEC2.IPPermission{ ec2.IPPermission{
IPProtocol: aws.String("icmp"), IPProtocol: aws.String("icmp"),
FromPort: aws.Integer(1), FromPort: aws.Integer(1),
ToPort: aws.Integer(-1), ToPort: aws.Integer(-1),
UserIDGroupPairs: []awsEC2.UserIDGroupPair{ UserIDGroupPairs: []ec2.UserIDGroupPair{
awsEC2.UserIDGroupPair{ ec2.UserIDGroupPair{
UserID: aws.String("foo"), 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) { func TestExpandListeners(t *testing.T) {
expanded := []interface{}{ expanded := []interface{}{
map[string]interface{}{ map[string]interface{}{

View File

@ -3,11 +3,13 @@ package aws
import ( import (
"log" "log"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
) )
// tagsSchema returns the schema to use for tags. // tagsSchema returns the schema to use for tags.
//
func tagsSchema() *schema.Schema { func tagsSchema() *schema.Schema {
return &schema.Schema{ return &schema.Schema{
Type: schema.TypeMap, Type: schema.TypeMap,
@ -27,13 +29,21 @@ func setTags(conn *ec2.EC2, d *schema.ResourceData) error {
// Set tags // Set tags
if len(remove) > 0 { if len(remove) > 0 {
log.Printf("[DEBUG] Removing tags: %#v", remove) 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 return err
} }
} }
if len(create) > 0 { if len(create) > 0 {
log.Printf("[DEBUG] Creating tags: %#v", create) 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 return err
} }
} }
@ -49,14 +59,14 @@ func diffTags(oldTags, newTags []ec2.Tag) ([]ec2.Tag, []ec2.Tag) {
// First, we're creating everything we have // First, we're creating everything we have
create := make(map[string]interface{}) create := make(map[string]interface{})
for _, t := range newTags { for _, t := range newTags {
create[t.Key] = t.Value create[*t.Key] = *t.Value
} }
// Build the list of what to remove // Build the list of what to remove
var remove []ec2.Tag var remove []ec2.Tag
for _, t := range oldTags { for _, t := range oldTags {
old, ok := create[t.Key] old, ok := create[*t.Key]
if !ok || old != t.Value { if !ok || old != *t.Value {
// Delete it! // Delete it!
remove = append(remove, t) remove = append(remove, t)
} }
@ -70,8 +80,8 @@ func tagsFromMap(m map[string]interface{}) []ec2.Tag {
result := make([]ec2.Tag, 0, len(m)) result := make([]ec2.Tag, 0, len(m))
for k, v := range m { for k, v := range m {
result = append(result, ec2.Tag{ result = append(result, ec2.Tag{
Key: k, Key: aws.String(k),
Value: v.(string), 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 { func tagsToMap(ts []ec2.Tag) map[string]string {
result := make(map[string]string) result := make(map[string]string)
for _, t := range ts { for _, t := range ts {
result[t.Key] = t.Value result[*t.Key] = *t.Value
} }
return result 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" "reflect"
"testing" "testing"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/goamz/ec2"
) )
func TestDiffTags(t *testing.T) { 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 != "" { if addr, ok := conf["address"]; ok && addr != "" {
config.Address = addr config.Address = addr
} }
if scheme, ok := conf["scheme"]; ok && scheme != "" {
config.Scheme = scheme
}
client, err := consulapi.NewClient(config) client, err := consulapi.NewClient(config)
if err != nil { 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 server when necessary and if any updates are made, the newest state
is persisted back to the remote server. is persisted back to the remote server.
In this mode, users do not need to durably store the state using version In this mode, users do not need to durably store the state using version
control or shared storaged. control or shared storage.
## Usage ## Usage

View File

@ -29,6 +29,18 @@ The following arguments are supported:
* `vpc_id` - (Required) The VPC ID to create in. * `vpc_id` - (Required) The VPC ID to create in.
* `tags` - (Optional) A mapping of tags to assign to the resource. * `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 ## Attributes Reference
The following attributes are exported: The following attributes are exported:

View File

@ -56,4 +56,4 @@ The following attributes are exported:
## Notes ## 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.