Merge branch 'master' of github.com:hashicorp/terraform
This commit is contained in:
commit
c72918efb3
|
@ -30,6 +30,7 @@ IMPROVEMENTS:
|
|||
info. [GH-1029]
|
||||
* **New config function: `split`** - Split a value based on a delimiter.
|
||||
This is useful for faking lists as parameters to modules.
|
||||
* **New resource: `digitalocean_ssh_key`** [GH-1074]
|
||||
* core: The serial of the state is only updated if there is an actual
|
||||
change. This will lower the amount of state changing on things
|
||||
like refresh.
|
||||
|
@ -48,7 +49,8 @@ BUG FIXES:
|
|||
"resource.0" would ignore the latter completely. [GH-1086]
|
||||
* providers/aws: manually deleted VPC removes it from the state
|
||||
* providers/aws: `source_dest_check` regression fixed (now works). [GH-1020]
|
||||
* providers/aws: Longer wait times for DB instances
|
||||
* providers/aws: Longer wait times for DB instances.
|
||||
* providers/aws: Longer wait times for route53 records (30 mins). [GH-1164]
|
||||
* providers/digitalocean: Waits until droplet is ready to be destroyed [GH-1057]
|
||||
* providers/digitalocean: More lenient about 404's while waiting [GH-1062]
|
||||
* providers/google: Network data in state was not being stored. [GH-1095]
|
||||
|
|
3
Makefile
3
Makefile
|
@ -12,6 +12,9 @@ bin: generate
|
|||
dev: generate
|
||||
@TF_DEV=1 sh -c "'$(CURDIR)/scripts/build.sh'"
|
||||
|
||||
quickdev: generate
|
||||
@TF_QUICKDEV=1 TF_DEV=1 sh -c "'$(CURDIR)/scripts/build.sh'"
|
||||
|
||||
# test runs the unit tests and vets the code
|
||||
test: generate
|
||||
TF_ACC= go test $(TEST) $(TESTARGS) -timeout=30s -parallel=4
|
||||
|
|
|
@ -3,21 +3,16 @@ package aws
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/multierror"
|
||||
"github.com/mitchellh/goamz/aws"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
|
||||
awsGo "github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/autoscaling"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/elb"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/rds"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/route53"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/s3"
|
||||
|
||||
awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -29,7 +24,6 @@ type Config struct {
|
|||
|
||||
type AWSClient struct {
|
||||
ec2conn *ec2.EC2
|
||||
awsEC2conn *awsEC2.EC2
|
||||
elbconn *elb.ELB
|
||||
autoscalingconn *autoscaling.AutoScaling
|
||||
s3conn *s3.S3
|
||||
|
@ -45,14 +39,9 @@ func (c *Config) Client() (interface{}, error) {
|
|||
// Get the auth and region. This can fail if keys/regions were not
|
||||
// specified and we're attempting to use the environment.
|
||||
var errs []error
|
||||
log.Println("[INFO] Building AWS auth structure")
|
||||
auth, err := c.AWSAuth()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
log.Println("[INFO] Building AWS region structure")
|
||||
region, err := c.AWSRegion()
|
||||
err := c.ValidateRegion()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
@ -62,10 +51,9 @@ func (c *Config) Client() (interface{}, error) {
|
|||
// bucket storage in S3
|
||||
client.region = c.Region
|
||||
|
||||
creds := awsGo.Creds(c.AccessKey, c.SecretKey, c.Token)
|
||||
log.Println("[INFO] Building AWS auth structure")
|
||||
creds := aws.Creds(c.AccessKey, c.SecretKey, c.Token)
|
||||
|
||||
log.Println("[INFO] Initializing EC2 connection")
|
||||
client.ec2conn = ec2.New(auth, region)
|
||||
log.Println("[INFO] Initializing ELB connection")
|
||||
client.elbconn = elb.New(creds, c.Region, nil)
|
||||
log.Println("[INFO] Initializing AutoScaling connection")
|
||||
|
@ -80,8 +68,8 @@ func (c *Config) Client() (interface{}, error) {
|
|||
// See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
|
||||
log.Println("[INFO] Initializing Route53 connection")
|
||||
client.r53conn = route53.New(creds, "us-east-1", nil)
|
||||
log.Println("[INFO] Initializing AWS-GO EC2 Connection")
|
||||
client.awsEC2conn = awsEC2.New(creds, c.Region, nil)
|
||||
log.Println("[INFO] Initializing EC2 Connection")
|
||||
client.ec2conn = ec2.New(creds, c.Region, nil)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
|
@ -91,54 +79,17 @@ func (c *Config) Client() (interface{}, error) {
|
|||
return &client, nil
|
||||
}
|
||||
|
||||
// AWSAuth returns a valid aws.Auth object for access to AWS services, or
|
||||
// an error if the authentication couldn't be resolved.
|
||||
//
|
||||
// TODO(mitchellh): Test in some way.
|
||||
func (c *Config) AWSAuth() (aws.Auth, error) {
|
||||
auth, err := aws.GetAuth(c.AccessKey, c.SecretKey)
|
||||
if err == nil {
|
||||
// Store the accesskey and secret that we got...
|
||||
c.AccessKey = auth.AccessKey
|
||||
c.SecretKey = auth.SecretKey
|
||||
c.Token = auth.Token
|
||||
}
|
||||
|
||||
return auth, err
|
||||
}
|
||||
|
||||
// IsValidRegion returns true if the configured region is a valid AWS
|
||||
// region and false if it's not
|
||||
func (c *Config) IsValidRegion() bool {
|
||||
func (c *Config) ValidateRegion() error {
|
||||
var regions = [11]string{"us-east-1", "us-west-2", "us-west-1", "eu-west-1",
|
||||
"eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1",
|
||||
"sa-east-1", "cn-north-1", "us-gov-west-1"}
|
||||
|
||||
for _, valid := range regions {
|
||||
if c.Region == valid {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AWSRegion returns the configured region.
|
||||
//
|
||||
// TODO(mitchellh): Test in some way.
|
||||
func (c *Config) AWSRegion() (aws.Region, error) {
|
||||
if c.Region != "" {
|
||||
if c.IsValidRegion() {
|
||||
return aws.Regions[c.Region], nil
|
||||
} else {
|
||||
return aws.Region{}, fmt.Errorf("Not a valid region: %s", c.Region)
|
||||
}
|
||||
}
|
||||
|
||||
md, err := aws.GetMetaData("placement/availability-zone")
|
||||
if err != nil {
|
||||
return aws.Region{}, err
|
||||
}
|
||||
|
||||
region := strings.TrimRightFunc(string(md), unicode.IsLetter)
|
||||
return aws.Regions[region], nil
|
||||
return fmt.Errorf("Not a valid region: %s", c.Region)
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
)
|
||||
|
||||
func expandNetworkAclEntries(configured []interface{}, entryType string) ([]ec2.NetworkAclEntry, error) {
|
||||
entries := make([]ec2.NetworkAclEntry, 0, len(configured))
|
||||
func expandNetworkAclEntries(configured []interface{}, entryType string) ([]ec2.NetworkACLEntry, error) {
|
||||
entries := make([]ec2.NetworkACLEntry, 0, len(configured))
|
||||
for _, eRaw := range configured {
|
||||
data := eRaw.(map[string]interface{})
|
||||
protocol := data["protocol"].(string)
|
||||
|
@ -15,16 +18,16 @@ func expandNetworkAclEntries(configured []interface{}, entryType string) ([]ec2.
|
|||
return nil, fmt.Errorf("Invalid Protocol %s for rule %#v", protocol, data)
|
||||
}
|
||||
p := extractProtocolInteger(data["protocol"].(string))
|
||||
e := ec2.NetworkAclEntry{
|
||||
Protocol: p,
|
||||
PortRange: ec2.PortRange{
|
||||
From: data["from_port"].(int),
|
||||
To: data["to_port"].(int),
|
||||
e := ec2.NetworkACLEntry{
|
||||
Protocol: aws.String(strconv.Itoa(p)),
|
||||
PortRange: &ec2.PortRange{
|
||||
From: aws.Integer(data["from_port"].(int)),
|
||||
To: aws.Integer(data["to_port"].(int)),
|
||||
},
|
||||
Egress: (entryType == "egress"),
|
||||
RuleAction: data["action"].(string),
|
||||
RuleNumber: data["rule_no"].(int),
|
||||
CidrBlock: data["cidr_block"].(string),
|
||||
Egress: aws.Boolean((entryType == "egress")),
|
||||
RuleAction: aws.String(data["action"].(string)),
|
||||
RuleNumber: aws.Integer(data["rule_no"].(int)),
|
||||
CIDRBlock: aws.String(data["cidr_block"].(string)),
|
||||
}
|
||||
entries = append(entries, e)
|
||||
}
|
||||
|
@ -33,17 +36,17 @@ func expandNetworkAclEntries(configured []interface{}, entryType string) ([]ec2.
|
|||
|
||||
}
|
||||
|
||||
func flattenNetworkAclEntries(list []ec2.NetworkAclEntry) []map[string]interface{} {
|
||||
func flattenNetworkAclEntries(list []ec2.NetworkACLEntry) []map[string]interface{} {
|
||||
entries := make([]map[string]interface{}, 0, len(list))
|
||||
|
||||
for _, entry := range list {
|
||||
entries = append(entries, map[string]interface{}{
|
||||
"from_port": entry.PortRange.From,
|
||||
"to_port": entry.PortRange.To,
|
||||
"action": entry.RuleAction,
|
||||
"rule_no": entry.RuleNumber,
|
||||
"protocol": extractProtocolString(entry.Protocol),
|
||||
"cidr_block": entry.CidrBlock,
|
||||
"from_port": *entry.PortRange.From,
|
||||
"to_port": *entry.PortRange.To,
|
||||
"action": *entry.RuleAction,
|
||||
"rule_no": *entry.RuleNumber,
|
||||
"protocol": *entry.Protocol,
|
||||
"cidr_block": *entry.CIDRBlock,
|
||||
})
|
||||
}
|
||||
return entries
|
||||
|
|
|
@ -4,10 +4,11 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
)
|
||||
|
||||
func Test_expandNetworkAclEntry(t *testing.T) {
|
||||
func Test_expandNetworkACLEntry(t *testing.T) {
|
||||
input := []interface{}{
|
||||
map[string]interface{}{
|
||||
"protocol": "tcp",
|
||||
|
@ -28,30 +29,28 @@ func Test_expandNetworkAclEntry(t *testing.T) {
|
|||
}
|
||||
expanded, _ := expandNetworkAclEntries(input, "egress")
|
||||
|
||||
expected := []ec2.NetworkAclEntry{
|
||||
ec2.NetworkAclEntry{
|
||||
Protocol: 6,
|
||||
PortRange: ec2.PortRange{
|
||||
From: 22,
|
||||
To: 22,
|
||||
expected := []ec2.NetworkACLEntry{
|
||||
ec2.NetworkACLEntry{
|
||||
Protocol: aws.String("6"),
|
||||
PortRange: &ec2.PortRange{
|
||||
From: aws.Integer(22),
|
||||
To: aws.Integer(22),
|
||||
},
|
||||
RuleAction: "deny",
|
||||
RuleNumber: 1,
|
||||
CidrBlock: "0.0.0.0/0",
|
||||
Egress: true,
|
||||
IcmpCode: ec2.IcmpCode{Code: 0, Type: 0},
|
||||
RuleAction: aws.String("deny"),
|
||||
RuleNumber: aws.Integer(1),
|
||||
CIDRBlock: aws.String("0.0.0.0/0"),
|
||||
Egress: aws.Boolean(true),
|
||||
},
|
||||
ec2.NetworkAclEntry{
|
||||
Protocol: 6,
|
||||
PortRange: ec2.PortRange{
|
||||
From: 443,
|
||||
To: 443,
|
||||
ec2.NetworkACLEntry{
|
||||
Protocol: aws.String("6"),
|
||||
PortRange: &ec2.PortRange{
|
||||
From: aws.Integer(443),
|
||||
To: aws.Integer(443),
|
||||
},
|
||||
RuleAction: "deny",
|
||||
RuleNumber: 2,
|
||||
CidrBlock: "0.0.0.0/0",
|
||||
Egress: true,
|
||||
IcmpCode: ec2.IcmpCode{Code: 0, Type: 0},
|
||||
RuleAction: aws.String("deny"),
|
||||
RuleNumber: aws.Integer(2),
|
||||
CIDRBlock: aws.String("0.0.0.0/0"),
|
||||
Egress: aws.Boolean(true),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -64,28 +63,28 @@ func Test_expandNetworkAclEntry(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func Test_flattenNetworkAclEntry(t *testing.T) {
|
||||
func Test_flattenNetworkACLEntry(t *testing.T) {
|
||||
|
||||
apiInput := []ec2.NetworkAclEntry{
|
||||
ec2.NetworkAclEntry{
|
||||
Protocol: 6,
|
||||
PortRange: ec2.PortRange{
|
||||
From: 22,
|
||||
To: 22,
|
||||
apiInput := []ec2.NetworkACLEntry{
|
||||
ec2.NetworkACLEntry{
|
||||
Protocol: aws.String("tcp"),
|
||||
PortRange: &ec2.PortRange{
|
||||
From: aws.Integer(22),
|
||||
To: aws.Integer(22),
|
||||
},
|
||||
RuleAction: "deny",
|
||||
RuleNumber: 1,
|
||||
CidrBlock: "0.0.0.0/0",
|
||||
RuleAction: aws.String("deny"),
|
||||
RuleNumber: aws.Integer(1),
|
||||
CIDRBlock: aws.String("0.0.0.0/0"),
|
||||
},
|
||||
ec2.NetworkAclEntry{
|
||||
Protocol: 6,
|
||||
PortRange: ec2.PortRange{
|
||||
From: 443,
|
||||
To: 443,
|
||||
ec2.NetworkACLEntry{
|
||||
Protocol: aws.String("tcp"),
|
||||
PortRange: &ec2.PortRange{
|
||||
From: aws.Integer(443),
|
||||
To: aws.Integer(443),
|
||||
},
|
||||
RuleAction: "deny",
|
||||
RuleNumber: 2,
|
||||
CidrBlock: "0.0.0.0/0",
|
||||
RuleAction: aws.String("deny"),
|
||||
RuleNumber: aws.Integer(2),
|
||||
CIDRBlock: aws.String("0.0.0.0/0"),
|
||||
},
|
||||
}
|
||||
flattened := flattenNetworkAclEntries(apiInput)
|
||||
|
|
|
@ -156,7 +156,6 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
"final_snapshot_identifier": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"db_subnet_group_name": &schema.Schema{
|
||||
|
|
|
@ -152,7 +152,7 @@ func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{})
|
|||
os := o.(*schema.Set)
|
||||
ns := n.(*schema.Set)
|
||||
|
||||
// Expand the "parameter" set to goamz compat []rds.Parameter
|
||||
// Expand the "parameter" set to aws-sdk-go compat []rds.Parameter
|
||||
parameters, err := expandParameters(ns.Difference(os).List())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -60,7 +60,7 @@ func resourceAwsEip() *schema.Resource {
|
|||
}
|
||||
|
||||
func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// By default, we're not in a VPC
|
||||
domainOpt := ""
|
||||
|
@ -97,7 +97,7 @@ func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
domain := resourceAwsEipDomain(d)
|
||||
id := d.Id()
|
||||
|
@ -148,7 +148,7 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
domain := resourceAwsEipDomain(d)
|
||||
|
||||
|
@ -181,7 +181,7 @@ func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
if err := resourceAwsEipRead(d, meta); err != nil {
|
||||
return err
|
||||
|
|
|
@ -58,7 +58,7 @@ func TestAccAWSEIP_instance(t *testing.T) {
|
|||
}
|
||||
|
||||
func testAccCheckAWSEIPDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_eip" {
|
||||
|
@ -113,7 +113,7 @@ func testAccCheckAWSEIPExists(n string, res *ec2.Address) resource.TestCheckFunc
|
|||
return fmt.Errorf("No EIP ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
if strings.Contains(rs.Primary.ID, "eipalloc") {
|
||||
req := &ec2.DescribeAddressesRequest{
|
||||
|
|
|
@ -161,7 +161,7 @@ func resourceAwsElb() *schema.Resource {
|
|||
func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
elbconn := meta.(*AWSClient).elbconn
|
||||
|
||||
// Expand the "listener" set to goamz compat []elb.Listener
|
||||
// Expand the "listener" set to aws-sdk-go compat []elb.Listener
|
||||
listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -3,17 +3,18 @@ package aws
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsInstance() *schema.Resource {
|
||||
|
@ -258,7 +259,28 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
// Figure out user data
|
||||
userData := ""
|
||||
if v := d.Get("user_data"); v != nil {
|
||||
userData = v.(string)
|
||||
userData = base64.StdEncoding.EncodeToString([]byte(v.(string)))
|
||||
}
|
||||
|
||||
placement := &ec2.Placement{
|
||||
AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
|
||||
Tenancy: aws.String(d.Get("tenancy").(string)),
|
||||
}
|
||||
|
||||
iam := &ec2.IAMInstanceProfileSpecification{
|
||||
Name: aws.String(d.Get("iam_instance_profile").(string)),
|
||||
}
|
||||
|
||||
// Build the creation struct
|
||||
runOpts := &ec2.RunInstancesRequest{
|
||||
ImageID: aws.String(d.Get("ami").(string)),
|
||||
Placement: placement,
|
||||
InstanceType: aws.String(d.Get("instance_type").(string)),
|
||||
MaxCount: aws.Integer(1),
|
||||
MinCount: aws.Integer(1),
|
||||
UserData: aws.String(userData),
|
||||
EBSOptimized: aws.Boolean(d.Get("ebs_optimized").(bool)),
|
||||
IAMInstanceProfile: iam,
|
||||
}
|
||||
|
||||
associatePublicIPAddress := false
|
||||
|
@ -266,34 +288,63 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
associatePublicIPAddress = v.(bool)
|
||||
}
|
||||
|
||||
// Build the creation struct
|
||||
runOpts := &ec2.RunInstances{
|
||||
ImageId: d.Get("ami").(string),
|
||||
AvailZone: d.Get("availability_zone").(string),
|
||||
InstanceType: d.Get("instance_type").(string),
|
||||
KeyName: d.Get("key_name").(string),
|
||||
SubnetId: d.Get("subnet_id").(string),
|
||||
PrivateIPAddress: d.Get("private_ip").(string),
|
||||
AssociatePublicIpAddress: associatePublicIPAddress,
|
||||
UserData: []byte(userData),
|
||||
EbsOptimized: d.Get("ebs_optimized").(bool),
|
||||
IamInstanceProfile: d.Get("iam_instance_profile").(string),
|
||||
Tenancy: d.Get("tenancy").(string),
|
||||
}
|
||||
// check for non-default Subnet, and cast it to a String
|
||||
var hasSubnet bool
|
||||
subnet, hasSubnet := d.GetOk("subnet_id")
|
||||
subnetID := subnet.(string)
|
||||
|
||||
var groups []string
|
||||
if v := d.Get("security_groups"); v != nil {
|
||||
// Security group names.
|
||||
// For a nondefault VPC, you must use security group IDs instead.
|
||||
// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html
|
||||
for _, v := range v.(*schema.Set).List() {
|
||||
str := v.(string)
|
||||
groups = append(groups, str)
|
||||
}
|
||||
}
|
||||
|
||||
var g ec2.SecurityGroup
|
||||
if runOpts.SubnetId != "" {
|
||||
g.Id = str
|
||||
if hasSubnet && associatePublicIPAddress {
|
||||
// If we have a non-default VPC / Subnet specified, we can flag
|
||||
// AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
|
||||
// You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
|
||||
// you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
|
||||
// You also need to attach Security Groups to the NetworkInterface instead of the instance,
|
||||
// to avoid: Network interfaces and an instance-level security groups may not be specified on
|
||||
// the same request
|
||||
ni := ec2.InstanceNetworkInterfaceSpecification{
|
||||
AssociatePublicIPAddress: aws.Boolean(associatePublicIPAddress),
|
||||
DeviceIndex: aws.Integer(0),
|
||||
SubnetID: aws.String(subnetID),
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("private_ip"); ok {
|
||||
ni.PrivateIPAddress = aws.String(v.(string))
|
||||
}
|
||||
|
||||
if len(groups) > 0 {
|
||||
ni.Groups = groups
|
||||
}
|
||||
|
||||
runOpts.NetworkInterfaces = []ec2.InstanceNetworkInterfaceSpecification{ni}
|
||||
} else {
|
||||
g.Name = str
|
||||
if subnetID != "" {
|
||||
runOpts.SubnetID = aws.String(subnetID)
|
||||
}
|
||||
|
||||
runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
|
||||
if v, ok := d.GetOk("private_ip"); ok {
|
||||
runOpts.PrivateIPAddress = aws.String(v.(string))
|
||||
}
|
||||
if runOpts.SubnetID != nil &&
|
||||
*runOpts.SubnetID != "" {
|
||||
runOpts.SecurityGroupIDs = groups
|
||||
} else {
|
||||
runOpts.SecurityGroups = groups
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("key_name"); ok {
|
||||
runOpts.KeyName = aws.String(v.(string))
|
||||
}
|
||||
|
||||
blockDevices := make([]interface{}, 0)
|
||||
|
@ -311,24 +362,27 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
if len(blockDevices) > 0 {
|
||||
runOpts.BlockDevices = make([]ec2.BlockDeviceMapping, len(blockDevices))
|
||||
runOpts.BlockDeviceMappings = make([]ec2.BlockDeviceMapping, len(blockDevices))
|
||||
for i, v := range blockDevices {
|
||||
bd := v.(map[string]interface{})
|
||||
runOpts.BlockDevices[i].DeviceName = bd["device_name"].(string)
|
||||
runOpts.BlockDevices[i].VolumeType = bd["volume_type"].(string)
|
||||
runOpts.BlockDevices[i].VolumeSize = int64(bd["volume_size"].(int))
|
||||
runOpts.BlockDevices[i].DeleteOnTermination = bd["delete_on_termination"].(bool)
|
||||
if v, ok := bd["virtual_name"].(string); ok {
|
||||
runOpts.BlockDevices[i].VirtualName = v
|
||||
runOpts.BlockDeviceMappings[i].DeviceName = aws.String(bd["device_name"].(string))
|
||||
runOpts.BlockDeviceMappings[i].EBS = &ec2.EBSBlockDevice{
|
||||
VolumeType: aws.String(bd["volume_type"].(string)),
|
||||
VolumeSize: aws.Integer(bd["volume_size"].(int)),
|
||||
DeleteOnTermination: aws.Boolean(bd["delete_on_termination"].(bool)),
|
||||
}
|
||||
if v, ok := bd["snapshot_id"].(string); ok {
|
||||
runOpts.BlockDevices[i].SnapshotId = v
|
||||
|
||||
if v, ok := bd["virtual_name"].(string); ok {
|
||||
runOpts.BlockDeviceMappings[i].VirtualName = aws.String(v)
|
||||
}
|
||||
if v, ok := bd["snapshot_id"].(string); ok && v != "" {
|
||||
runOpts.BlockDeviceMappings[i].EBS.SnapshotID = aws.String(v)
|
||||
}
|
||||
if v, ok := bd["encrypted"].(bool); ok {
|
||||
runOpts.BlockDevices[i].Encrypted = v
|
||||
runOpts.BlockDeviceMappings[i].EBS.Encrypted = aws.Boolean(v)
|
||||
}
|
||||
if v, ok := bd["iops"].(int); ok {
|
||||
runOpts.BlockDevices[i].IOPS = int64(v)
|
||||
if v, ok := bd["iops"].(int); ok && v > 0 {
|
||||
runOpts.BlockDeviceMappings[i].EBS.IOPS = aws.Integer(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,21 +395,21 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
instance := &runResp.Instances[0]
|
||||
log.Printf("[INFO] Instance ID: %s", instance.InstanceId)
|
||||
log.Printf("[INFO] Instance ID: %s", *instance.InstanceID)
|
||||
|
||||
// Store the resulting ID so we can look this up later
|
||||
d.SetId(instance.InstanceId)
|
||||
d.SetId(*instance.InstanceID)
|
||||
|
||||
// Wait for the instance to become running so we can get some attributes
|
||||
// that aren't available until later.
|
||||
log.Printf(
|
||||
"[DEBUG] Waiting for instance (%s) to become running",
|
||||
instance.InstanceId)
|
||||
*instance.InstanceID)
|
||||
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"pending"},
|
||||
Target: "running",
|
||||
Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
|
||||
Refresh: InstanceStateRefreshFunc(ec2conn, *instance.InstanceID),
|
||||
Timeout: 10 * time.Minute,
|
||||
Delay: 10 * time.Second,
|
||||
MinTimeout: 3 * time.Second,
|
||||
|
@ -365,16 +419,18 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for instance (%s) to become ready: %s",
|
||||
instance.InstanceId, err)
|
||||
*instance.InstanceID, err)
|
||||
}
|
||||
|
||||
instance = instanceRaw.(*ec2.Instance)
|
||||
|
||||
// Initialize the connection info
|
||||
if instance.PublicIPAddress != nil {
|
||||
d.SetConnInfo(map[string]string{
|
||||
"type": "ssh",
|
||||
"host": instance.PublicIpAddress,
|
||||
"host": *instance.PublicIPAddress,
|
||||
})
|
||||
}
|
||||
|
||||
// Set our attributes
|
||||
if err := resourceAwsInstanceRead(d, meta); err != nil {
|
||||
|
@ -388,11 +444,13 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
resp, err := ec2conn.Instances([]string{d.Id()}, ec2.NewFilter())
|
||||
resp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesRequest{
|
||||
InstanceIDs: []string{d.Id()},
|
||||
})
|
||||
if err != nil {
|
||||
// If the instance was not found, return nil so that we can show
|
||||
// that the instance is gone.
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
@ -410,28 +468,33 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
instance := &resp.Reservations[0].Instances[0]
|
||||
|
||||
// If the instance is terminated, then it is gone
|
||||
if instance.State.Name == "terminated" {
|
||||
if *instance.State.Name == "terminated" {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Set("availability_zone", instance.AvailZone)
|
||||
d.Set("availability_zone", instance.Placement.AvailabilityZone)
|
||||
d.Set("key_name", instance.KeyName)
|
||||
d.Set("public_dns", instance.DNSName)
|
||||
d.Set("public_ip", instance.PublicIpAddress)
|
||||
d.Set("public_dns", instance.PublicDNSName)
|
||||
d.Set("public_ip", instance.PublicIPAddress)
|
||||
d.Set("private_dns", instance.PrivateDNSName)
|
||||
d.Set("private_ip", instance.PrivateIpAddress)
|
||||
d.Set("subnet_id", instance.SubnetId)
|
||||
d.Set("ebs_optimized", instance.EbsOptimized)
|
||||
d.Set("private_ip", instance.PrivateIPAddress)
|
||||
d.Set("subnet_id", instance.SubnetID)
|
||||
if len(instance.NetworkInterfaces) > 0 {
|
||||
d.Set("subnet_id", instance.NetworkInterfaces[0].SubnetID)
|
||||
} else {
|
||||
d.Set("subnet_id", instance.SubnetID)
|
||||
}
|
||||
d.Set("ebs_optimized", instance.EBSOptimized)
|
||||
d.Set("tags", tagsToMap(instance.Tags))
|
||||
d.Set("tenancy", instance.Tenancy)
|
||||
d.Set("tenancy", instance.Placement.Tenancy)
|
||||
|
||||
// Determine whether we're referring to security groups with
|
||||
// IDs or names. We use a heuristic to figure this out. By default,
|
||||
// we use IDs if we're in a VPC. However, if we previously had an
|
||||
// all-name list of security groups, we use names. Or, if we had any
|
||||
// IDs, we use IDs.
|
||||
useID := instance.SubnetId != ""
|
||||
useID := *instance.SubnetID != ""
|
||||
if v := d.Get("security_groups"); v != nil {
|
||||
match := false
|
||||
for _, v := range v.(*schema.Set).List() {
|
||||
|
@ -448,24 +511,26 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
sgs := make([]string, len(instance.SecurityGroups))
|
||||
for i, sg := range instance.SecurityGroups {
|
||||
if useID {
|
||||
sgs[i] = sg.Id
|
||||
sgs[i] = *sg.GroupID
|
||||
} else {
|
||||
sgs[i] = sg.Name
|
||||
sgs[i] = *sg.GroupName
|
||||
}
|
||||
}
|
||||
d.Set("security_groups", sgs)
|
||||
|
||||
blockDevices := make(map[string]ec2.BlockDevice)
|
||||
for _, bd := range instance.BlockDevices {
|
||||
blockDevices[bd.VolumeId] = bd
|
||||
blockDevices := make(map[string]ec2.InstanceBlockDeviceMapping)
|
||||
for _, bd := range instance.BlockDeviceMappings {
|
||||
blockDevices[*bd.EBS.VolumeID] = bd
|
||||
}
|
||||
|
||||
volIDs := make([]string, 0, len(blockDevices))
|
||||
for volID := range blockDevices {
|
||||
volIDs = append(volIDs, volID)
|
||||
for _, vol := range blockDevices {
|
||||
volIDs = append(volIDs, *vol.EBS.VolumeID)
|
||||
}
|
||||
|
||||
volResp, err := ec2conn.Volumes(volIDs, ec2.NewFilter())
|
||||
volResp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesRequest{
|
||||
VolumeIDs: volIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -473,28 +538,25 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
nonRootBlockDevices := make([]map[string]interface{}, 0)
|
||||
rootBlockDevice := make([]interface{}, 0, 1)
|
||||
for _, vol := range volResp.Volumes {
|
||||
volSize, err := strconv.Atoi(vol.Size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blockDevice := make(map[string]interface{})
|
||||
blockDevice["device_name"] = blockDevices[vol.VolumeId].DeviceName
|
||||
blockDevice["volume_type"] = vol.VolumeType
|
||||
blockDevice["volume_size"] = volSize
|
||||
blockDevice["device_name"] = *blockDevices[*vol.VolumeID].DeviceName
|
||||
blockDevice["volume_type"] = *vol.VolumeType
|
||||
blockDevice["volume_size"] = *vol.Size
|
||||
if vol.IOPS != nil {
|
||||
blockDevice["iops"] = *vol.IOPS
|
||||
}
|
||||
blockDevice["delete_on_termination"] =
|
||||
blockDevices[vol.VolumeId].DeleteOnTermination
|
||||
*blockDevices[*vol.VolumeID].EBS.DeleteOnTermination
|
||||
|
||||
// If this is the root device, save it. We stop here since we
|
||||
// can't put invalid keys into this map.
|
||||
if blockDevice["device_name"] == instance.RootDeviceName {
|
||||
if blockDevice["device_name"] == *instance.RootDeviceName {
|
||||
rootBlockDevice = []interface{}{blockDevice}
|
||||
continue
|
||||
}
|
||||
|
||||
blockDevice["snapshot_id"] = vol.SnapshotId
|
||||
blockDevice["encrypted"] = vol.Encrypted
|
||||
blockDevice["iops"] = vol.IOPS
|
||||
blockDevice["snapshot_id"] = *vol.SnapshotID
|
||||
blockDevice["encrypted"] = *vol.Encrypted
|
||||
nonRootBlockDevices = append(nonRootBlockDevices, blockDevice)
|
||||
}
|
||||
d.Set("block_device", nonRootBlockDevices)
|
||||
|
@ -505,13 +567,17 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
opts := new(ec2.ModifyInstance)
|
||||
|
||||
opts.SetSourceDestCheck = true
|
||||
opts.SourceDestCheck = d.Get("source_dest_check").(bool)
|
||||
opts := new(ec2.ModifyInstanceAttributeRequest)
|
||||
|
||||
log.Printf("[INFO] Modifying instance %s: %#v", d.Id(), opts)
|
||||
if _, err := ec2conn.ModifyInstance(d.Id(), opts); err != nil {
|
||||
err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeRequest{
|
||||
InstanceID: aws.String(d.Id()),
|
||||
SourceDestCheck: &ec2.AttributeBooleanValue{
|
||||
Value: aws.Boolean(d.Get("source_dest_check").(bool)),
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -531,7 +597,10 @@ func resourceAwsInstanceDelete(d *schema.ResourceData, meta interface{}) error {
|
|||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
log.Printf("[INFO] Terminating instance: %s", d.Id())
|
||||
if _, err := ec2conn.TerminateInstances([]string{d.Id()}); err != nil {
|
||||
req := &ec2.TerminateInstancesRequest{
|
||||
InstanceIDs: []string{d.Id()},
|
||||
}
|
||||
if _, err := ec2conn.TerminateInstances(req); err != nil {
|
||||
return fmt.Errorf("Error terminating instance: %s", err)
|
||||
}
|
||||
|
||||
|
@ -563,9 +632,11 @@ func resourceAwsInstanceDelete(d *schema.ResourceData, meta interface{}) error {
|
|||
// an EC2 instance.
|
||||
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{
|
||||
InstanceIDs: []string{instanceID},
|
||||
})
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||
// Set this to nil as if we didn't find anything.
|
||||
resp = nil
|
||||
} else {
|
||||
|
@ -581,7 +652,7 @@ func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRe
|
|||
}
|
||||
|
||||
i := &resp.Reservations[0].Instances[0]
|
||||
return i, i.State.Name, nil
|
||||
return i, *i.State.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,24 +5,25 @@ import (
|
|||
"reflect"
|
||||
"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/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestAccAWSInstance_normal(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
if v.AvailZone != "us-west-2a" {
|
||||
return fmt.Errorf("bad availability zone: %#v", v.AvailZone)
|
||||
if *v.Placement.AvailabilityZone != "us-west-2a" {
|
||||
return fmt.Errorf("bad availability zone: %#v", *v.Placement.AvailabilityZone)
|
||||
}
|
||||
|
||||
if len(v.SecurityGroups) == 0 {
|
||||
return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
|
||||
}
|
||||
if v.SecurityGroups[0].Name != "tf_test_foo" {
|
||||
if *v.SecurityGroups[0].GroupName != "tf_test_foo" {
|
||||
return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
|
||||
}
|
||||
|
||||
|
@ -73,9 +74,9 @@ func TestAccAWSInstance_blockDevices(t *testing.T) {
|
|||
return func(*terraform.State) error {
|
||||
|
||||
// Map out the block devices by name, which should be unique.
|
||||
blockDevices := make(map[string]ec2.BlockDevice)
|
||||
for _, blockDevice := range v.BlockDevices {
|
||||
blockDevices[blockDevice.DeviceName] = blockDevice
|
||||
blockDevices := make(map[string]ec2.InstanceBlockDeviceMapping)
|
||||
for _, blockDevice := range v.BlockDeviceMappings {
|
||||
blockDevices[*blockDevice.DeviceName] = blockDevice
|
||||
}
|
||||
|
||||
// Check if the root block device exists.
|
||||
|
@ -147,8 +148,8 @@ func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
|
|||
|
||||
testCheck := func(enabled bool) resource.TestCheckFunc {
|
||||
return func(*terraform.State) error {
|
||||
if v.SourceDestCheck != enabled {
|
||||
return fmt.Errorf("bad source_dest_check: %#v", v.SourceDestCheck)
|
||||
if *v.SourceDestCheck != enabled {
|
||||
return fmt.Errorf("bad source_dest_check: %#v", *v.SourceDestCheck)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -206,7 +207,26 @@ func TestAccAWSInstance_vpc(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccInstance_tags(t *testing.T) {
|
||||
func TestAccInstance_NetworkInstanceSecurityGroups(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccInstanceNetworkInstanceSecurityGroups,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInstanceExists(
|
||||
"aws_instance.foo_instance", &v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSInstance_tags(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
|
@ -236,13 +256,13 @@ func TestAccInstance_tags(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccInstance_privateIP(t *testing.T) {
|
||||
func TestAccAWSInstance_privateIP(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
testCheckPrivateIP := func() resource.TestCheckFunc {
|
||||
return func(*terraform.State) error {
|
||||
if v.PrivateIpAddress != "10.1.1.42" {
|
||||
return fmt.Errorf("bad private IP: %s", v.PrivateIpAddress)
|
||||
if *v.PrivateIPAddress != "10.1.1.42" {
|
||||
return fmt.Errorf("bad private IP: %s", *v.PrivateIPAddress)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -265,13 +285,13 @@ func TestAccInstance_privateIP(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccInstance_associatePublicIPAndPrivateIP(t *testing.T) {
|
||||
func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
testCheckPrivateIP := func() resource.TestCheckFunc {
|
||||
return func(*terraform.State) error {
|
||||
if v.PrivateIpAddress != "10.1.1.42" {
|
||||
return fmt.Errorf("bad private IP: %s", v.PrivateIpAddress)
|
||||
if *v.PrivateIPAddress != "10.1.1.42" {
|
||||
return fmt.Errorf("bad private IP: %s", *v.PrivateIPAddress)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -303,8 +323,9 @@ func testAccCheckInstanceDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Try to find the resource
|
||||
resp, err := conn.Instances(
|
||||
[]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{
|
||||
InstanceIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err == nil {
|
||||
if len(resp.Reservations) > 0 {
|
||||
return fmt.Errorf("still exist.")
|
||||
|
@ -314,7 +335,7 @@ func testAccCheckInstanceDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Verify the error is what we want
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -338,8 +359,9 @@ func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFun
|
|||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.Instances(
|
||||
[]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{
|
||||
InstanceIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -389,7 +411,7 @@ resource "aws_instance" "foo" {
|
|||
|
||||
instance_type = "m1.small"
|
||||
security_groups = ["${aws_security_group.tf_test_foo.name}"]
|
||||
user_data = "foo"
|
||||
user_data = "foo:-with-character's"
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -530,3 +552,49 @@ resource "aws_instance" "foo" {
|
|||
private_ip = "10.1.1.42"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccInstanceNetworkInstanceSecurityGroups = `
|
||||
resource "aws_internet_gateway" "gw" {
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
}
|
||||
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
tags {
|
||||
Name = "tf-network-test"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_security_group" "tf_test_foo" {
|
||||
name = "tf_test_foo"
|
||||
description = "foo"
|
||||
vpc_id="${aws_vpc.foo.id}"
|
||||
|
||||
ingress {
|
||||
protocol = "icmp"
|
||||
from_port = -1
|
||||
to_port = -1
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "foo" {
|
||||
cidr_block = "10.1.1.0/24"
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo_instance" {
|
||||
ami = "ami-21f78e11"
|
||||
instance_type = "t1.micro"
|
||||
security_groups = ["${aws_security_group.tf_test_foo.id}"]
|
||||
subnet_id = "${aws_subnet.foo.id}"
|
||||
associate_public_ip_address = true
|
||||
depends_on = ["aws_internet_gateway.gw"]
|
||||
}
|
||||
|
||||
resource "aws_eip" "foo_eip" {
|
||||
instance = "${aws_instance.foo_instance.id}"
|
||||
vpc = true
|
||||
depends_on = ["aws_internet_gateway.gw"]
|
||||
}
|
||||
`
|
||||
|
|
|
@ -29,7 +29,7 @@ func resourceAwsInternetGateway() *schema.Resource {
|
|||
}
|
||||
|
||||
func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Create the gateway
|
||||
log.Printf("[DEBUG] Creating internet gateway")
|
||||
|
@ -43,12 +43,17 @@ func resourceAwsInternetGatewayCreate(d *schema.ResourceData, meta interface{})
|
|||
d.SetId(*ig.InternetGatewayID)
|
||||
log.Printf("[INFO] InternetGateway ID: %s", d.Id())
|
||||
|
||||
err = setTags(ec2conn, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attach the new gateway to the correct vpc
|
||||
return resourceAwsInternetGatewayAttach(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
igRaw, _, err := IGStateRefreshFunc(ec2conn, d.Id())()
|
||||
if err != nil {
|
||||
|
@ -68,7 +73,7 @@ func resourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) er
|
|||
d.Set("vpc_id", ig.Attachments[0].VPCID)
|
||||
}
|
||||
|
||||
d.Set("tags", tagsToMapSDK(ig.Tags))
|
||||
d.Set("tags", tagsToMap(ig.Tags))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -86,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
|
||||
}
|
||||
|
||||
|
@ -98,7 +103,7 @@ func resourceAwsInternetGatewayUpdate(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
|
||||
func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Detach if it is attached
|
||||
if err := resourceAwsInternetGatewayDetach(d, meta); err != nil {
|
||||
|
@ -132,7 +137,7 @@ func resourceAwsInternetGatewayDelete(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
|
||||
func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
if d.Get("vpc_id").(string) == "" {
|
||||
log.Printf(
|
||||
|
@ -177,7 +182,7 @@ func resourceAwsInternetGatewayAttach(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
|
||||
func resourceAwsInternetGatewayDetach(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Get the old VPC ID to detach from
|
||||
vpcID, _ := d.GetChange("vpc_id")
|
||||
|
|
|
@ -98,6 +98,7 @@ func TestAccInternetGateway_tags(t *testing.T) {
|
|||
Config: testAccCheckInternetGatewayConfigTags,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInternetGatewayExists("aws_internet_gateway.foo", &v),
|
||||
testAccCheckTags(&v.Tags, "foo", "bar"),
|
||||
),
|
||||
},
|
||||
|
||||
|
@ -105,8 +106,8 @@ func TestAccInternetGateway_tags(t *testing.T) {
|
|||
Config: testAccCheckInternetGatewayConfigTagsUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInternetGatewayExists("aws_internet_gateway.foo", &v),
|
||||
testAccCheckTagsSDK(&v.Tags, "foo", ""),
|
||||
testAccCheckTagsSDK(&v.Tags, "bar", "baz"),
|
||||
testAccCheckTags(&v.Tags, "foo", ""),
|
||||
testAccCheckTags(&v.Tags, "bar", "baz"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -114,7 +115,7 @@ func TestAccInternetGateway_tags(t *testing.T) {
|
|||
}
|
||||
|
||||
func testAccCheckInternetGatewayDestroy(s *terraform.State) error {
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_internet_gateway" {
|
||||
|
@ -157,7 +158,7 @@ func testAccCheckInternetGatewayExists(n string, ig *ec2.InternetGateway) resour
|
|||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := ec2conn.DescribeInternetGateways(&ec2.DescribeInternetGatewaysRequest{
|
||||
InternetGatewayIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
|
|
|
@ -37,7 +37,7 @@ func resourceAwsKeyPair() *schema.Resource {
|
|||
}
|
||||
|
||||
func resourceAwsKeyPairCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
keyName := d.Get("key_name").(string)
|
||||
publicKey := d.Get("public_key").(string)
|
||||
|
@ -55,7 +55,7 @@ func resourceAwsKeyPairCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsKeyPairRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
req := &ec2.DescribeKeyPairsRequest{
|
||||
KeyNames: []string{d.Id()},
|
||||
|
@ -77,7 +77,7 @@ func resourceAwsKeyPairRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsKeyPairDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
err := ec2conn.DeleteKeyPair(&ec2.DeleteKeyPairRequest{
|
||||
KeyName: aws.String(d.Id()),
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestAccAWSKeyPair_normal(t *testing.T) {
|
|||
}
|
||||
|
||||
func testAccCheckAWSKeyPairDestroy(s *terraform.State) error {
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_key_pair" {
|
||||
|
@ -81,7 +81,7 @@ func testAccCheckAWSKeyPairExists(n string, res *ec2.KeyPairInfo) resource.TestC
|
|||
return fmt.Errorf("No KeyPair name is set")
|
||||
}
|
||||
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
resp, err := ec2conn.DescribeKeyPairs(&ec2.DescribeKeyPairsRequest{
|
||||
KeyNames: []string{rs.Primary.ID},
|
||||
|
|
|
@ -4,8 +4,9 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsMainRouteTableAssociation() *schema.Resource {
|
||||
|
@ -50,16 +51,16 @@ func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta int
|
|||
return err
|
||||
}
|
||||
|
||||
resp, err := ec2conn.ReassociateRouteTable(
|
||||
mainAssociation.AssociationId,
|
||||
routeTableId,
|
||||
)
|
||||
resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{
|
||||
AssociationID: mainAssociation.RouteTableAssociationID,
|
||||
RouteTableID: aws.String(routeTableId),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("original_route_table_id", mainAssociation.RouteTableId)
|
||||
d.SetId(resp.AssociationId)
|
||||
d.Set("original_route_table_id", mainAssociation.RouteTableID)
|
||||
d.SetId(*resp.NewAssociationID)
|
||||
log.Printf("[INFO] New main route table association ID: %s", d.Id())
|
||||
|
||||
return nil
|
||||
|
@ -75,7 +76,7 @@ func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta inter
|
|||
return err
|
||||
}
|
||||
|
||||
if mainAssociation.AssociationId != d.Id() {
|
||||
if *mainAssociation.RouteTableAssociationID != d.Id() {
|
||||
// It seems it doesn't exist anymore, so clear the ID
|
||||
d.SetId("")
|
||||
}
|
||||
|
@ -93,12 +94,15 @@ func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta int
|
|||
|
||||
log.Printf("[INFO] Updating main route table association: %s => %s", vpcId, routeTableId)
|
||||
|
||||
resp, err := ec2conn.ReassociateRouteTable(d.Id(), routeTableId)
|
||||
resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{
|
||||
AssociationID: aws.String(d.Id()),
|
||||
RouteTableID: aws.String(routeTableId),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(resp.AssociationId)
|
||||
d.SetId(*resp.NewAssociationID)
|
||||
log.Printf("[INFO] New main route table association ID: %s", d.Id())
|
||||
|
||||
return nil
|
||||
|
@ -113,12 +117,15 @@ func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta int
|
|||
vpcId,
|
||||
originalRouteTableId)
|
||||
|
||||
resp, err := ec2conn.ReassociateRouteTable(d.Id(), originalRouteTableId)
|
||||
resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{
|
||||
AssociationID: aws.String(d.Id()),
|
||||
RouteTableID: aws.String(originalRouteTableId),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Resulting Association ID: %s", resp.AssociationId)
|
||||
log.Printf("[INFO] Resulting Association ID: %s", *resp.NewAssociationID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -130,7 +137,7 @@ func findMainRouteTableAssociation(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTa
|
|||
}
|
||||
|
||||
for _, a := range mainRouteTable.Associations {
|
||||
if a.Main {
|
||||
if *a.Main {
|
||||
return &a, nil
|
||||
}
|
||||
}
|
||||
|
@ -138,10 +145,17 @@ func findMainRouteTableAssociation(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTa
|
|||
}
|
||||
|
||||
func findMainRouteTable(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTable, error) {
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("association.main", "true")
|
||||
filter.Add("vpc-id", vpcId)
|
||||
routeResp, err := ec2conn.DescribeRouteTables(nil, filter)
|
||||
mainFilter := ec2.Filter{
|
||||
aws.String("association.main"),
|
||||
[]string{"true"},
|
||||
}
|
||||
vpcFilter := ec2.Filter{
|
||||
aws.String("vpc-id"),
|
||||
[]string{vpcId},
|
||||
}
|
||||
routeResp, err := ec2conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
Filters: []ec2.Filter{mainFilter, vpcFilter},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(routeResp.RouteTables) != 1 {
|
||||
|
|
|
@ -71,9 +71,9 @@ func testAccCheckMainRouteTableAssociation(
|
|||
return err
|
||||
}
|
||||
|
||||
if mainAssociation.AssociationId != rs.Primary.ID {
|
||||
if *mainAssociation.RouteTableAssociationID != rs.Primary.ID {
|
||||
return fmt.Errorf("Found wrong main association: %s",
|
||||
mainAssociation.AssociationId)
|
||||
*mainAssociation.RouteTableAssociationID)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -6,10 +6,11 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsNetworkAcl() *schema.Resource {
|
||||
|
@ -111,20 +112,20 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error
|
|||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Create the Network Acl
|
||||
createOpts := &ec2.CreateNetworkAcl{
|
||||
VpcId: d.Get("vpc_id").(string),
|
||||
createOpts := &ec2.CreateNetworkACLRequest{
|
||||
VPCID: aws.String(d.Get("vpc_id").(string)),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Network Acl create config: %#v", createOpts)
|
||||
resp, err := ec2conn.CreateNetworkAcl(createOpts)
|
||||
resp, err := ec2conn.CreateNetworkACL(createOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating network acl: %s", err)
|
||||
}
|
||||
|
||||
// Get the ID and store it
|
||||
networkAcl := &resp.NetworkAcl
|
||||
d.SetId(networkAcl.NetworkAclId)
|
||||
log.Printf("[INFO] Network Acl ID: %s", networkAcl.NetworkAclId)
|
||||
networkAcl := resp.NetworkACL
|
||||
d.SetId(*networkAcl.NetworkACLID)
|
||||
log.Printf("[INFO] Network Acl ID: %s", *networkAcl.NetworkACLID)
|
||||
|
||||
// Update rules and subnet association once acl is created
|
||||
return resourceAwsNetworkAclUpdate(d, meta)
|
||||
|
@ -133,7 +134,9 @@ func resourceAwsNetworkAclCreate(d *schema.ResourceData, meta interface{}) error
|
|||
func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
resp, err := ec2conn.NetworkAcls([]string{d.Id()}, ec2.NewFilter())
|
||||
resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{d.Id()},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -142,20 +145,20 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
networkAcl := &resp.NetworkAcls[0]
|
||||
var ingressEntries []ec2.NetworkAclEntry
|
||||
var egressEntries []ec2.NetworkAclEntry
|
||||
networkAcl := &resp.NetworkACLs[0]
|
||||
var ingressEntries []ec2.NetworkACLEntry
|
||||
var egressEntries []ec2.NetworkACLEntry
|
||||
|
||||
// separate the ingress and egress rules
|
||||
for _, e := range networkAcl.EntrySet {
|
||||
if e.Egress == true {
|
||||
for _, e := range networkAcl.Entries {
|
||||
if *e.Egress == true {
|
||||
egressEntries = append(egressEntries, e)
|
||||
} else {
|
||||
ingressEntries = append(ingressEntries, e)
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("vpc_id", networkAcl.VpcId)
|
||||
d.Set("vpc_id", networkAcl.VPCID)
|
||||
d.Set("ingress", ingressEntries)
|
||||
d.Set("egress", egressEntries)
|
||||
d.Set("tags", tagsToMap(networkAcl.Tags))
|
||||
|
@ -190,7 +193,10 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed to update acl %s with subnet %s: %s", d.Id(), newSubnet, err)
|
||||
}
|
||||
_, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, d.Id())
|
||||
_, err = ec2conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationRequest{
|
||||
AssociationID: association.NetworkACLAssociationID,
|
||||
NetworkACLID: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -226,7 +232,11 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *
|
|||
}
|
||||
for _, remove := range toBeDeleted {
|
||||
// Delete old Acl
|
||||
_, err := ec2conn.DeleteNetworkAclEntry(d.Id(), remove.RuleNumber, remove.Egress)
|
||||
err := ec2conn.DeleteNetworkACLEntry(&ec2.DeleteNetworkACLEntryRequest{
|
||||
NetworkACLID: aws.String(d.Id()),
|
||||
RuleNumber: remove.RuleNumber,
|
||||
Egress: remove.Egress,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting %s entry: %s", entryType, err)
|
||||
}
|
||||
|
@ -238,7 +248,15 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *
|
|||
}
|
||||
for _, add := range toBeCreated {
|
||||
// Add new Acl entry
|
||||
_, err := ec2conn.CreateNetworkAclEntry(d.Id(), &add)
|
||||
err := ec2conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryRequest{
|
||||
NetworkACLID: aws.String(d.Id()),
|
||||
CIDRBlock: add.CIDRBlock,
|
||||
Egress: add.Egress,
|
||||
PortRange: add.PortRange,
|
||||
Protocol: add.Protocol,
|
||||
RuleAction: add.RuleAction,
|
||||
RuleNumber: add.RuleNumber,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating %s entry: %s", entryType, err)
|
||||
}
|
||||
|
@ -251,8 +269,11 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error
|
|||
|
||||
log.Printf("[INFO] Deleting Network Acl: %s", d.Id())
|
||||
return resource.Retry(5*time.Minute, func() error {
|
||||
if _, err := ec2conn.DeleteNetworkAcl(d.Id()); err != nil {
|
||||
ec2err := err.(*ec2.Error)
|
||||
err := ec2conn.DeleteNetworkACL(&ec2.DeleteNetworkACLRequest{
|
||||
NetworkACLID: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
ec2err := err.(aws.APIError)
|
||||
switch ec2err.Code {
|
||||
case "InvalidNetworkAclID.NotFound":
|
||||
return nil
|
||||
|
@ -267,7 +288,10 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error
|
|||
if err != nil {
|
||||
return fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)
|
||||
}
|
||||
_, err = ec2conn.ReplaceNetworkAclAssociation(association.NetworkAclAssociationId, defaultAcl.NetworkAclId)
|
||||
_, err = ec2conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationRequest{
|
||||
AssociationID: association.NetworkACLAssociationID,
|
||||
NetworkACLID: defaultAcl.NetworkACLID,
|
||||
})
|
||||
return resource.RetryError{Err: err}
|
||||
default:
|
||||
// Any other error, we want to quit the retry loop immediately
|
||||
|
@ -296,30 +320,43 @@ func resourceAwsNetworkAclEntryHash(v interface{}) int {
|
|||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2) (defaultAcl *ec2.NetworkAcl, err error) {
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("default", "true")
|
||||
filter.Add("vpc-id", vpc_id)
|
||||
|
||||
resp, err := ec2conn.NetworkAcls([]string{}, filter)
|
||||
func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2) (defaultAcl *ec2.NetworkACL, err error) {
|
||||
resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{},
|
||||
Filters: []ec2.Filter{
|
||||
ec2.Filter{
|
||||
Name: aws.String("default"),
|
||||
Values: []string{"true"},
|
||||
},
|
||||
ec2.Filter{
|
||||
Name: aws.String("vpc-id"),
|
||||
Values: []string{vpc_id},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp.NetworkAcls[0], nil
|
||||
return &resp.NetworkACLs[0], nil
|
||||
}
|
||||
|
||||
func findNetworkAclAssociation(subnetId string, ec2conn *ec2.EC2) (networkAclAssociation *ec2.NetworkAclAssociation, err error) {
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("association.subnet-id", subnetId)
|
||||
|
||||
resp, err := ec2conn.NetworkAcls([]string{}, filter)
|
||||
func findNetworkAclAssociation(subnetId string, ec2conn *ec2.EC2) (networkAclAssociation *ec2.NetworkACLAssociation, err error) {
|
||||
resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{},
|
||||
Filters: []ec2.Filter{
|
||||
ec2.Filter{
|
||||
Name: aws.String("association.subnet-id"),
|
||||
Values: []string{subnetId},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, association := range resp.NetworkAcls[0].AssociationSet {
|
||||
if association.SubnetId == subnetId {
|
||||
for _, association := range resp.NetworkACLs[0].Associations {
|
||||
if *association.SubnetID == subnetId {
|
||||
return &association, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,16 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
// "github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
// "github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) {
|
||||
var networkAcl ec2.NetworkAcl
|
||||
var networkAcl ec2.NetworkACL
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -24,29 +25,29 @@ func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.protocol", "tcp"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.rule_no", "1"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.from_port", "80"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.from_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.to_port", "80"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.to_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.action", "allow"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.action", "allow"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.580214135.cidr_block", "10.3.10.3/18"),
|
||||
"aws_network_acl.bar", "ingress.3409203205.cidr_block", "10.3.10.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.protocol", "tcp"),
|
||||
"aws_network_acl.bar", "egress.2579689292.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.rule_no", "2"),
|
||||
"aws_network_acl.bar", "egress.2579689292.rule_no", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.from_port", "443"),
|
||||
"aws_network_acl.bar", "egress.2579689292.from_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.to_port", "443"),
|
||||
"aws_network_acl.bar", "egress.2579689292.to_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.cidr_block", "10.3.2.3/18"),
|
||||
"aws_network_acl.bar", "egress.2579689292.cidr_block", "10.3.2.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.1730430240.action", "allow"),
|
||||
"aws_network_acl.bar", "egress.2579689292.action", "allow"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -54,7 +55,7 @@ func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) {
|
||||
var networkAcl ec2.NetworkAcl
|
||||
var networkAcl ec2.NetworkACL
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -67,17 +68,17 @@ func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
// testAccCheckSubnetAssociation("aws_network_acl.foos", "aws_subnet.blob"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.cidr_block", "10.2.2.3/18"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -85,7 +86,7 @@ func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
||||
var networkAcl ec2.NetworkAcl
|
||||
var networkAcl ec2.NetworkACL
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -98,21 +99,21 @@ func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
testIngressRuleLength(&networkAcl, 2),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.37211640.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
"aws_network_acl.foos", "ingress.37211640.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
"aws_network_acl.foos", "ingress.37211640.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
"aws_network_acl.foos", "ingress.37211640.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.37211640.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.37211640.cidr_block", "10.2.2.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.2438803013.from_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.from_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.2438803013.rule_no", "2"),
|
||||
"aws_network_acl.foos", "ingress.2750166237.rule_no", "2"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
|
@ -121,17 +122,17 @@ func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
testIngressRuleLength(&networkAcl, 1),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.37211640.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
"aws_network_acl.foos", "ingress.37211640.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
"aws_network_acl.foos", "ingress.37211640.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
"aws_network_acl.foos", "ingress.37211640.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.37211640.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.37211640.cidr_block", "10.2.2.3/18"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -139,7 +140,7 @@ func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSNetworkAclsOnlyEgressRules(t *testing.T) {
|
||||
var networkAcl ec2.NetworkAcl
|
||||
var networkAcl ec2.NetworkACL
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -157,7 +158,7 @@ func TestAccAWSNetworkAclsOnlyEgressRules(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccNetworkAcl_SubnetChange(t *testing.T) {
|
||||
func TestAccAWSNetworkAcl_SubnetChange(t *testing.T) {
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -191,16 +192,18 @@ func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Retrieve the network acl
|
||||
resp, err := conn.NetworkAcls([]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err == nil {
|
||||
if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID {
|
||||
if len(resp.NetworkACLs) > 0 && *resp.NetworkACLs[0].NetworkACLID == rs.Primary.ID {
|
||||
return fmt.Errorf("Network Acl (%s) still exists.", rs.Primary.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -213,7 +216,7 @@ func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resource.TestCheckFunc {
|
||||
func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkACL) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
|
@ -225,13 +228,15 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resou
|
|||
}
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
resp, err := conn.NetworkAcls([]string{rs.Primary.ID}, nil)
|
||||
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.NetworkAcls) > 0 && resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID {
|
||||
*networkAcl = resp.NetworkAcls[0]
|
||||
if len(resp.NetworkACLs) > 0 && *resp.NetworkACLs[0].NetworkACLID == rs.Primary.ID {
|
||||
*networkAcl = resp.NetworkACLs[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -239,11 +244,11 @@ func testAccCheckAWSNetworkAclExists(n string, networkAcl *ec2.NetworkAcl) resou
|
|||
}
|
||||
}
|
||||
|
||||
func testIngressRuleLength(networkAcl *ec2.NetworkAcl, length int) resource.TestCheckFunc {
|
||||
func testIngressRuleLength(networkAcl *ec2.NetworkACL, length int) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
var ingressEntries []ec2.NetworkAclEntry
|
||||
for _, e := range networkAcl.EntrySet {
|
||||
if e.Egress == false {
|
||||
var ingressEntries []ec2.NetworkACLEntry
|
||||
for _, e := range networkAcl.Entries {
|
||||
if *e.Egress == false {
|
||||
ingressEntries = append(ingressEntries, e)
|
||||
}
|
||||
}
|
||||
|
@ -262,20 +267,25 @@ func testAccCheckSubnetIsAssociatedWithAcl(acl string, sub string) resource.Test
|
|||
subnet := s.RootModule().Resources[sub]
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("association.subnet-id", subnet.Primary.ID)
|
||||
resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter)
|
||||
|
||||
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{networkAcl.Primary.ID},
|
||||
Filters: []ec2.Filter{
|
||||
ec2.Filter{
|
||||
Name: aws.String("association.subnet-id"),
|
||||
Values: []string{subnet.Primary.ID},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.NetworkAcls) > 0 {
|
||||
if len(resp.NetworkACLs) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, _ := conn.NetworkAcls([]string{}, ec2.NewFilter())
|
||||
fmt.Printf("\n\nall acls\n %#v\n\n", r.NetworkAcls)
|
||||
conn.NetworkAcls([]string{}, filter)
|
||||
// r, _ := conn.NetworkACLs([]string{}, ec2.NewFilter())
|
||||
// fmt.Printf("\n\nall acls\n %#v\n\n", r.NetworkAcls)
|
||||
// conn.NetworkAcls([]string{}, filter)
|
||||
|
||||
return fmt.Errorf("Network Acl %s is not associated with subnet %s", acl, sub)
|
||||
}
|
||||
|
@ -287,14 +297,20 @@ func testAccCheckSubnetIsNotAssociatedWithAcl(acl string, subnet string) resourc
|
|||
subnet := s.RootModule().Resources[subnet]
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("association.subnet-id", subnet.Primary.ID)
|
||||
resp, err := conn.NetworkAcls([]string{networkAcl.Primary.ID}, filter)
|
||||
resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{
|
||||
NetworkACLIDs: []string{networkAcl.Primary.ID},
|
||||
Filters: []ec2.Filter{
|
||||
ec2.Filter{
|
||||
Name: aws.String("association.subnet-id"),
|
||||
Values: []string{subnet.Primary.ID},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.NetworkAcls) > 0 {
|
||||
if len(resp.NetworkACLs) > 0 {
|
||||
return fmt.Errorf("Network Acl %s is still associated with subnet %s", acl, subnet)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -138,7 +138,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er
|
|||
Delay: 30 * time.Second,
|
||||
Pending: []string{"PENDING"},
|
||||
Target: "INSYNC",
|
||||
Timeout: 10 * time.Minute,
|
||||
Timeout: 30 * time.Minute,
|
||||
MinTimeout: 5 * time.Second,
|
||||
Refresh: func() (result interface{}, state string, err error) {
|
||||
changeRequest := &route53.GetChangeRequest{
|
||||
|
|
|
@ -6,10 +6,11 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsRouteTable() *schema.Resource {
|
||||
|
@ -64,8 +65,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
|
|||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Create the routing table
|
||||
createOpts := &ec2.CreateRouteTable{
|
||||
VpcId: d.Get("vpc_id").(string),
|
||||
createOpts := &ec2.CreateRouteTableRequest{
|
||||
VPCID: aws.String(d.Get("vpc_id").(string)),
|
||||
}
|
||||
log.Printf("[DEBUG] RouteTable create config: %#v", createOpts)
|
||||
|
||||
|
@ -75,8 +76,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
|
||||
// Get the ID and store it
|
||||
rt := &resp.RouteTable
|
||||
d.SetId(rt.RouteTableId)
|
||||
rt := resp.RouteTable
|
||||
d.SetId(*rt.RouteTableID)
|
||||
log.Printf("[INFO] Route Table ID: %s", d.Id())
|
||||
|
||||
// Wait for the route table to become available
|
||||
|
@ -110,27 +111,35 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
rt := rtRaw.(*ec2.RouteTable)
|
||||
d.Set("vpc_id", rt.VpcId)
|
||||
d.Set("vpc_id", rt.VPCID)
|
||||
|
||||
// Create an empty schema.Set to hold all routes
|
||||
route := &schema.Set{F: resourceAwsRouteTableHash}
|
||||
|
||||
// Loop through the routes and add them to the set
|
||||
for _, r := range rt.Routes {
|
||||
if r.GatewayId == "local" {
|
||||
if r.GatewayID != nil && *r.GatewayID == "local" {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.Origin == "EnableVgwRoutePropagation" {
|
||||
if r.Origin != nil && *r.Origin == "EnableVgwRoutePropagation" {
|
||||
continue
|
||||
}
|
||||
|
||||
m := make(map[string]interface{})
|
||||
m["cidr_block"] = r.DestinationCidrBlock
|
||||
|
||||
m["gateway_id"] = r.GatewayId
|
||||
m["instance_id"] = r.InstanceId
|
||||
m["vpc_peering_connection_id"] = r.VpcPeeringConnectionId
|
||||
if r.DestinationCIDRBlock != nil {
|
||||
m["cidr_block"] = *r.DestinationCIDRBlock
|
||||
}
|
||||
if r.GatewayID != nil {
|
||||
m["gateway_id"] = *r.GatewayID
|
||||
}
|
||||
if r.InstanceID != nil {
|
||||
m["instance_id"] = *r.InstanceID
|
||||
}
|
||||
if r.VPCPeeringConnectionID != nil {
|
||||
m["vpc_peering_connection_id"] = *r.VPCPeeringConnectionID
|
||||
}
|
||||
|
||||
route.Add(m)
|
||||
}
|
||||
|
@ -159,8 +168,10 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
log.Printf(
|
||||
"[INFO] Deleting route from %s: %s",
|
||||
d.Id(), m["cidr_block"].(string))
|
||||
_, err := ec2conn.DeleteRoute(
|
||||
d.Id(), m["cidr_block"].(string))
|
||||
err := ec2conn.DeleteRoute(&ec2.DeleteRouteRequest{
|
||||
RouteTableID: aws.String(d.Id()),
|
||||
DestinationCIDRBlock: aws.String(m["cidr_block"].(string)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -174,17 +185,16 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
for _, route := range nrs.List() {
|
||||
m := route.(map[string]interface{})
|
||||
|
||||
opts := ec2.CreateRoute{
|
||||
RouteTableId: d.Id(),
|
||||
DestinationCidrBlock: m["cidr_block"].(string),
|
||||
GatewayId: m["gateway_id"].(string),
|
||||
InstanceId: m["instance_id"].(string),
|
||||
VpcPeeringConnectionId: m["vpc_peering_connection_id"].(string),
|
||||
opts := ec2.CreateRouteRequest{
|
||||
RouteTableID: aws.String(d.Id()),
|
||||
DestinationCIDRBlock: aws.String(m["cidr_block"].(string)),
|
||||
GatewayID: aws.String(m["gateway_id"].(string)),
|
||||
InstanceID: aws.String(m["instance_id"].(string)),
|
||||
VPCPeeringConnectionID: aws.String(m["vpc_peering_connection_id"].(string)),
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts)
|
||||
_, err := ec2conn.CreateRoute(&opts)
|
||||
if err != nil {
|
||||
if err := ec2conn.CreateRoute(&opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -218,16 +228,22 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error
|
|||
|
||||
// Do all the disassociations
|
||||
for _, a := range rt.Associations {
|
||||
log.Printf("[INFO] Disassociating association: %s", a.AssociationId)
|
||||
if _, err := ec2conn.DisassociateRouteTable(a.AssociationId); err != nil {
|
||||
log.Printf("[INFO] Disassociating association: %s", *a.RouteTableAssociationID)
|
||||
err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{
|
||||
AssociationID: a.RouteTableAssociationID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the route table
|
||||
log.Printf("[INFO] Deleting Route Table: %s", d.Id())
|
||||
if _, err := ec2conn.DeleteRouteTable(d.Id()); err != nil {
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
err = ec2conn.DeleteRouteTable(&ec2.DeleteRouteTableRequest{
|
||||
RouteTableID: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
|
@ -279,9 +295,11 @@ func resourceAwsRouteTableHash(v interface{}) int {
|
|||
// a RouteTable.
|
||||
func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
RouteTableIDs: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
|
||||
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("Error on RouteTableStateRefresh: %s", err)
|
||||
|
|
|
@ -4,8 +4,9 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsRouteTableAssociation() *schema.Resource {
|
||||
|
@ -38,16 +39,17 @@ func resourceAwsRouteTableAssociationCreate(d *schema.ResourceData, meta interfa
|
|||
d.Get("subnet_id").(string),
|
||||
d.Get("route_table_id").(string))
|
||||
|
||||
resp, err := ec2conn.AssociateRouteTable(
|
||||
d.Get("route_table_id").(string),
|
||||
d.Get("subnet_id").(string))
|
||||
resp, err := ec2conn.AssociateRouteTable(&ec2.AssociateRouteTableRequest{
|
||||
RouteTableID: aws.String(d.Get("route_table_id").(string)),
|
||||
SubnetID: aws.String(d.Get("subnet_id").(string)),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the ID and return
|
||||
d.SetId(resp.AssociationId)
|
||||
d.SetId(*resp.AssociationID)
|
||||
log.Printf("[INFO] Association ID: %s", d.Id())
|
||||
|
||||
return nil
|
||||
|
@ -70,9 +72,9 @@ func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface
|
|||
// Inspect that the association exists
|
||||
found := false
|
||||
for _, a := range rt.Associations {
|
||||
if a.AssociationId == d.Id() {
|
||||
if *a.RouteTableAssociationID == d.Id() {
|
||||
found = true
|
||||
d.Set("subnet_id", a.SubnetId)
|
||||
d.Set("subnet_id", *a.SubnetID)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -93,12 +95,14 @@ func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interfa
|
|||
d.Get("subnet_id").(string),
|
||||
d.Get("route_table_id").(string))
|
||||
|
||||
resp, err := ec2conn.ReassociateRouteTable(
|
||||
d.Id(),
|
||||
d.Get("route_table_id").(string))
|
||||
req := &ec2.ReplaceRouteTableAssociationRequest{
|
||||
AssociationID: aws.String(d.Id()),
|
||||
RouteTableID: aws.String(d.Get("route_table_id").(string)),
|
||||
}
|
||||
resp, err := ec2conn.ReplaceRouteTableAssociation(req)
|
||||
|
||||
if err != nil {
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if ok && ec2err.Code == "InvalidAssociationID.NotFound" {
|
||||
// Not found, so just create a new one
|
||||
return resourceAwsRouteTableAssociationCreate(d, meta)
|
||||
|
@ -108,7 +112,7 @@ func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interfa
|
|||
}
|
||||
|
||||
// Update the ID
|
||||
d.SetId(resp.AssociationId)
|
||||
d.SetId(*resp.NewAssociationID)
|
||||
log.Printf("[INFO] Association ID: %s", d.Id())
|
||||
|
||||
return nil
|
||||
|
@ -118,8 +122,11 @@ func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interfa
|
|||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
log.Printf("[INFO] Deleting route table association: %s", d.Id())
|
||||
if _, err := ec2conn.DisassociateRouteTable(d.Id()); err != nil {
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{
|
||||
AssociationID: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if ok && ec2err.Code == "InvalidAssociationID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestAccAWSRouteTableAssociation(t *testing.T) {
|
||||
|
@ -45,11 +46,12 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Try to find the resource
|
||||
resp, err := conn.DescribeRouteTables(
|
||||
[]string{rs.Primary.Attributes["route_table_Id"]}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
RouteTableIDs: []string{rs.Primary.Attributes["route_table_id"]},
|
||||
})
|
||||
if err != nil {
|
||||
// Verify the error is what we want
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -62,7 +64,7 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error {
|
|||
rt := resp.RouteTables[0]
|
||||
if len(rt.Associations) > 0 {
|
||||
return fmt.Errorf(
|
||||
"route table %s has associations", rt.RouteTableId)
|
||||
"route table %s has associations", *rt.RouteTableID)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +84,9 @@ func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTable) resour
|
|||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.DescribeRouteTables(
|
||||
[]string{rs.Primary.Attributes["route_table_id"]}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
RouteTableIDs: []string{rs.Primary.Attributes["route_table_id"]},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestAccAWSRouteTable_normal(t *testing.T) {
|
||||
|
@ -19,7 +20,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) {
|
|||
|
||||
routes := make(map[string]ec2.Route)
|
||||
for _, r := range v.Routes {
|
||||
routes[r.DestinationCidrBlock] = r
|
||||
routes[*r.DestinationCIDRBlock] = r
|
||||
}
|
||||
|
||||
if _, ok := routes["10.1.0.0/16"]; !ok {
|
||||
|
@ -39,7 +40,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) {
|
|||
|
||||
routes := make(map[string]ec2.Route)
|
||||
for _, r := range v.Routes {
|
||||
routes[r.DestinationCidrBlock] = r
|
||||
routes[*r.DestinationCIDRBlock] = r
|
||||
}
|
||||
|
||||
if _, ok := routes["10.1.0.0/16"]; !ok {
|
||||
|
@ -91,7 +92,7 @@ func TestAccAWSRouteTable_instance(t *testing.T) {
|
|||
|
||||
routes := make(map[string]ec2.Route)
|
||||
for _, r := range v.Routes {
|
||||
routes[r.DestinationCidrBlock] = r
|
||||
routes[*r.DestinationCIDRBlock] = r
|
||||
}
|
||||
|
||||
if _, ok := routes["10.1.0.0/16"]; !ok {
|
||||
|
@ -158,8 +159,9 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Try to find the resource
|
||||
resp, err := conn.DescribeRouteTables(
|
||||
[]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
RouteTableIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err == nil {
|
||||
if len(resp.RouteTables) > 0 {
|
||||
return fmt.Errorf("still exist.")
|
||||
|
@ -169,7 +171,7 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Verify the error is what we want
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -193,8 +195,9 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
|
|||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.DescribeRouteTables(
|
||||
[]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
|
||||
RouteTableIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -208,7 +211,10 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
|
|||
}
|
||||
}
|
||||
|
||||
func TestAccAWSRouteTable_vpcPeering(t *testing.T) {
|
||||
// TODO: re-enable this test.
|
||||
// VPC Peering connections are prefixed with pcx
|
||||
// Right now there is no VPC Peering resource
|
||||
func _TestAccAWSRouteTable_vpcPeering(t *testing.T) {
|
||||
var v ec2.RouteTable
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
|
@ -218,7 +224,7 @@ func TestAccAWSRouteTable_vpcPeering(t *testing.T) {
|
|||
|
||||
routes := make(map[string]ec2.Route)
|
||||
for _, r := range v.Routes {
|
||||
routes[r.DestinationCidrBlock] = r
|
||||
routes[*r.DestinationCIDRBlock] = r
|
||||
}
|
||||
|
||||
if _, ok := routes["10.1.0.0/16"]; !ok {
|
||||
|
@ -345,6 +351,9 @@ resource "aws_route_table" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
// TODO: re-enable this test.
|
||||
// VPC Peering connections are prefixed with pcx
|
||||
// Right now there is no VPC Peering resource
|
||||
const testAccRouteTableVpcPeeringConfig = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
|
@ -359,7 +368,7 @@ resource "aws_route_table" "foo" {
|
|||
|
||||
route {
|
||||
cidr_block = "10.2.0.0/16"
|
||||
vpc_peering_connection_id = "vpc-12345"
|
||||
vpc_peering_connection_id = "pcx-12345"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -7,10 +7,11 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsSecurityGroup() *schema.Resource {
|
||||
|
@ -143,16 +144,16 @@ func resourceAwsSecurityGroup() *schema.Resource {
|
|||
func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
securityGroupOpts := ec2.SecurityGroup{
|
||||
Name: d.Get("name").(string),
|
||||
securityGroupOpts := &ec2.CreateSecurityGroupRequest{
|
||||
GroupName: aws.String(d.Get("name").(string)),
|
||||
}
|
||||
|
||||
if v := d.Get("vpc_id"); v != nil {
|
||||
securityGroupOpts.VpcId = v.(string)
|
||||
securityGroupOpts.VPCID = aws.String(v.(string))
|
||||
}
|
||||
|
||||
if v := d.Get("description"); v != nil {
|
||||
securityGroupOpts.Description = v.(string)
|
||||
securityGroupOpts.Description = aws.String(v.(string))
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
|
@ -162,7 +163,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er
|
|||
return fmt.Errorf("Error creating Security Group: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(createResp.Id)
|
||||
d.SetId(*createResp.GroupID)
|
||||
|
||||
log.Printf("[INFO] Security Group ID: %s", d.Id())
|
||||
|
||||
|
@ -197,19 +198,18 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
sg := sgRaw.(*ec2.SecurityGroupInfo)
|
||||
sg := sgRaw.(ec2.SecurityGroup)
|
||||
|
||||
ingressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPerms)
|
||||
egressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermsEgress)
|
||||
ingressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermissions)
|
||||
egressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermissionsEgress)
|
||||
|
||||
d.Set("description", sg.Description)
|
||||
d.Set("name", sg.Name)
|
||||
d.Set("vpc_id", sg.VpcId)
|
||||
d.Set("owner_id", sg.OwnerId)
|
||||
d.Set("name", sg.GroupName)
|
||||
d.Set("vpc_id", sg.VPCID)
|
||||
d.Set("owner_id", sg.OwnerID)
|
||||
d.Set("ingress", ingressRules)
|
||||
d.Set("egress", egressRules)
|
||||
d.Set("tags", tagsToMap(sg.Tags))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,8 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er
|
|||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
group := sgRaw.(*ec2.SecurityGroupInfo).SecurityGroup
|
||||
|
||||
group := sgRaw.(ec2.SecurityGroup)
|
||||
|
||||
err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group)
|
||||
if err != nil {
|
||||
|
@ -253,9 +254,11 @@ func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er
|
|||
log.Printf("[DEBUG] Security Group destroy: %v", d.Id())
|
||||
|
||||
return resource.Retry(5*time.Minute, func() error {
|
||||
_, err := ec2conn.DeleteSecurityGroup(ec2.SecurityGroup{Id: d.Id()})
|
||||
err := ec2conn.DeleteSecurityGroup(&ec2.DeleteSecurityGroupRequest{
|
||||
GroupID: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -313,34 +316,45 @@ func resourceAwsSecurityGroupRuleHash(v interface{}) int {
|
|||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []ec2.IPPerm) []map[string]interface{} {
|
||||
func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []ec2.IPPermission) []map[string]interface{} {
|
||||
ruleMap := make(map[string]map[string]interface{})
|
||||
for _, perm := range permissions {
|
||||
k := fmt.Sprintf("%s-%d-%d", perm.Protocol, perm.FromPort, perm.ToPort)
|
||||
var fromPort, toPort int
|
||||
if v := perm.FromPort; v != nil {
|
||||
fromPort = *v
|
||||
}
|
||||
if v := perm.ToPort; v != nil {
|
||||
toPort = *v
|
||||
}
|
||||
|
||||
k := fmt.Sprintf("%s-%d-%d", *perm.IPProtocol, fromPort, toPort)
|
||||
m, ok := ruleMap[k]
|
||||
if !ok {
|
||||
m = make(map[string]interface{})
|
||||
ruleMap[k] = m
|
||||
}
|
||||
|
||||
m["from_port"] = perm.FromPort
|
||||
m["to_port"] = perm.ToPort
|
||||
m["protocol"] = perm.Protocol
|
||||
m["from_port"] = fromPort
|
||||
m["to_port"] = toPort
|
||||
m["protocol"] = *perm.IPProtocol
|
||||
|
||||
if len(perm.SourceIPs) > 0 {
|
||||
if len(perm.IPRanges) > 0 {
|
||||
raw, ok := m["cidr_blocks"]
|
||||
if !ok {
|
||||
raw = make([]string, 0, len(perm.SourceIPs))
|
||||
raw = make([]string, 0, len(perm.IPRanges))
|
||||
}
|
||||
list := raw.([]string)
|
||||
|
||||
list = append(list, perm.SourceIPs...)
|
||||
for _, ip := range perm.IPRanges {
|
||||
list = append(list, *ip.CIDRIP)
|
||||
}
|
||||
|
||||
m["cidr_blocks"] = list
|
||||
}
|
||||
|
||||
var groups []string
|
||||
if len(perm.SourceGroups) > 0 {
|
||||
groups = flattenSecurityGroups(perm.SourceGroups)
|
||||
if len(perm.UserIDGroupPairs) > 0 {
|
||||
groups = flattenSecurityGroups(perm.UserIDGroupPairs)
|
||||
}
|
||||
for i, id := range groups {
|
||||
if id == d.Id() {
|
||||
|
@ -364,7 +378,6 @@ func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []
|
|||
for _, m := range ruleMap {
|
||||
rules = append(rules, m)
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
|
@ -398,32 +411,51 @@ func resourceAwsSecurityGroupUpdateRules(
|
|||
if len(remove) > 0 || len(add) > 0 {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
var err error
|
||||
if len(remove) > 0 {
|
||||
// Revoke the old rules
|
||||
revoke := ec2conn.RevokeSecurityGroup
|
||||
log.Printf("[DEBUG] Revoking security group %#v %s rule: %#v",
|
||||
group, ruleset, remove)
|
||||
|
||||
if ruleset == "egress" {
|
||||
revoke = ec2conn.RevokeSecurityGroupEgress
|
||||
req := &ec2.RevokeSecurityGroupEgressRequest{
|
||||
GroupID: group.GroupID,
|
||||
IPPermissions: remove,
|
||||
}
|
||||
err = ec2conn.RevokeSecurityGroupEgress(req)
|
||||
} else {
|
||||
req := &ec2.RevokeSecurityGroupIngressRequest{
|
||||
GroupID: group.GroupID,
|
||||
IPPermissions: remove,
|
||||
}
|
||||
err = ec2conn.RevokeSecurityGroupIngress(req)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Revoking security group %s %s rule: %#v",
|
||||
group, ruleset, remove)
|
||||
if _, err := revoke(group, remove); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error revoking security group %s rules: %s",
|
||||
"Error authorizing security group %s rules: %s",
|
||||
ruleset, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(add) > 0 {
|
||||
log.Printf("[DEBUG] Authorizing security group %#v %s rule: %#v",
|
||||
group, ruleset, add)
|
||||
// Authorize the new rules
|
||||
authorize := ec2conn.AuthorizeSecurityGroup
|
||||
if ruleset == "egress" {
|
||||
authorize = ec2conn.AuthorizeSecurityGroupEgress
|
||||
req := &ec2.AuthorizeSecurityGroupEgressRequest{
|
||||
GroupID: group.GroupID,
|
||||
IPPermissions: add,
|
||||
}
|
||||
err = ec2conn.AuthorizeSecurityGroupEgress(req)
|
||||
} else {
|
||||
req := &ec2.AuthorizeSecurityGroupIngressRequest{
|
||||
GroupID: group.GroupID,
|
||||
IPPermissions: add,
|
||||
}
|
||||
err = ec2conn.AuthorizeSecurityGroupIngress(req)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Authorizing security group %s %s rule: %#v",
|
||||
group, ruleset, add)
|
||||
if _, err := authorize(group, add); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error authorizing security group %s rules: %s",
|
||||
ruleset, err)
|
||||
|
@ -431,7 +463,6 @@ func resourceAwsSecurityGroupUpdateRules(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -439,10 +470,12 @@ func resourceAwsSecurityGroupUpdateRules(
|
|||
// a security group.
|
||||
func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}}
|
||||
resp, err := conn.SecurityGroups(sgs, nil)
|
||||
req := &ec2.DescribeSecurityGroupsRequest{
|
||||
GroupIDs: []string{id},
|
||||
}
|
||||
resp, err := conn.DescribeSecurityGroups(req)
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(*ec2.Error); ok {
|
||||
if ec2err, ok := err.(aws.APIError); ok {
|
||||
if ec2err.Code == "InvalidSecurityGroupID.NotFound" ||
|
||||
ec2err.Code == "InvalidGroup.NotFound" {
|
||||
resp = nil
|
||||
|
@ -460,7 +493,7 @@ func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
|||
return nil, "", nil
|
||||
}
|
||||
|
||||
group := &resp.Groups[0]
|
||||
group := resp.SecurityGroups[0]
|
||||
return group, "exists", nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,18 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestAccAWSSecurityGroup_normal(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -44,7 +46,7 @@ func TestAccAWSSecurityGroup_normal(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSSecurityGroup_self(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
checkSelf := func(s *terraform.State) (err error) {
|
||||
defer func() {
|
||||
|
@ -53,7 +55,7 @@ func TestAccAWSSecurityGroup_self(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
if group.IPPerms[0].SourceGroups[0].Id != group.Id {
|
||||
if *group.IPPermissions[0].UserIDGroupPairs[0].GroupID != *group.GroupID {
|
||||
return fmt.Errorf("bad: %#v", group)
|
||||
}
|
||||
|
||||
|
@ -89,10 +91,10 @@ func TestAccAWSSecurityGroup_self(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSSecurityGroup_vpc(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
if group.VpcId == "" {
|
||||
if *group.VPCID == "" {
|
||||
return fmt.Errorf("should have vpc ID")
|
||||
}
|
||||
|
||||
|
@ -141,7 +143,7 @@ func TestAccAWSSecurityGroup_vpc(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSSecurityGroup_MultiIngress(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -159,7 +161,7 @@ func TestAccAWSSecurityGroup_MultiIngress(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccAWSSecurityGroup_Change(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -191,23 +193,20 @@ func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error {
|
|||
continue
|
||||
}
|
||||
|
||||
sgs := []ec2.SecurityGroup{
|
||||
ec2.SecurityGroup{
|
||||
Id: rs.Primary.ID,
|
||||
},
|
||||
}
|
||||
|
||||
// Retrieve our group
|
||||
resp, err := conn.SecurityGroups(sgs, nil)
|
||||
req := &ec2.DescribeSecurityGroupsRequest{
|
||||
GroupIDs: []string{rs.Primary.ID},
|
||||
}
|
||||
resp, err := conn.DescribeSecurityGroups(req)
|
||||
if err == nil {
|
||||
if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID {
|
||||
if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupID == rs.Primary.ID {
|
||||
return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -220,7 +219,7 @@ func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) resource.TestCheckFunc {
|
||||
func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroup) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
|
@ -232,19 +231,18 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo)
|
|||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
sgs := []ec2.SecurityGroup{
|
||||
ec2.SecurityGroup{
|
||||
Id: rs.Primary.ID,
|
||||
},
|
||||
req := &ec2.DescribeSecurityGroupsRequest{
|
||||
GroupIDs: []string{rs.Primary.ID},
|
||||
}
|
||||
resp, err := conn.SecurityGroups(sgs, nil)
|
||||
resp, err := conn.DescribeSecurityGroups(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID {
|
||||
if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupID == rs.Primary.ID {
|
||||
|
||||
*group = resp.Groups[0]
|
||||
log.Printf("\n==\n===\nfound group\n===\n==\n")
|
||||
*group = resp.SecurityGroups[0]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -253,32 +251,32 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo)
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroupInfo) resource.TestCheckFunc {
|
||||
func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroup) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
p := ec2.IPPerm{
|
||||
FromPort: 80,
|
||||
ToPort: 8000,
|
||||
Protocol: "tcp",
|
||||
SourceIPs: []string{"10.0.0.0/8"},
|
||||
p := ec2.IPPermission{
|
||||
FromPort: aws.Integer(80),
|
||||
ToPort: aws.Integer(8000),
|
||||
IPProtocol: aws.String("tcp"),
|
||||
IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("10.0.0.0/8")}},
|
||||
}
|
||||
|
||||
if group.Name != "terraform_acceptance_test_example" {
|
||||
return fmt.Errorf("Bad name: %s", group.Name)
|
||||
if *group.GroupName != "terraform_acceptance_test_example" {
|
||||
return fmt.Errorf("Bad name: %s", *group.GroupName)
|
||||
}
|
||||
|
||||
if group.Description != "Used in the terraform acceptance tests" {
|
||||
return fmt.Errorf("Bad description: %s", group.Description)
|
||||
if *group.Description != "Used in the terraform acceptance tests" {
|
||||
return fmt.Errorf("Bad description: %s", *group.Description)
|
||||
}
|
||||
|
||||
if len(group.IPPerms) == 0 {
|
||||
if len(group.IPPermissions) == 0 {
|
||||
return fmt.Errorf("No IPPerms")
|
||||
}
|
||||
|
||||
// Compare our ingress
|
||||
if !reflect.DeepEqual(group.IPPerms[0], p) {
|
||||
if !reflect.DeepEqual(group.IPPermissions[0], p) {
|
||||
return fmt.Errorf(
|
||||
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
|
||||
group.IPPerms[0],
|
||||
group.IPPermissions[0],
|
||||
p)
|
||||
}
|
||||
|
||||
|
@ -287,7 +285,7 @@ func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroupInfo) resour
|
|||
}
|
||||
|
||||
func TestAccAWSSecurityGroup_tags(t *testing.T) {
|
||||
var group ec2.SecurityGroupInfo
|
||||
var group ec2.SecurityGroup
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -314,48 +312,48 @@ func TestAccAWSSecurityGroup_tags(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func testAccCheckAWSSecurityGroupAttributesChanged(group *ec2.SecurityGroupInfo) resource.TestCheckFunc {
|
||||
func testAccCheckAWSSecurityGroupAttributesChanged(group *ec2.SecurityGroup) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
p := []ec2.IPPerm{
|
||||
ec2.IPPerm{
|
||||
FromPort: 80,
|
||||
ToPort: 9000,
|
||||
Protocol: "tcp",
|
||||
SourceIPs: []string{"10.0.0.0/8"},
|
||||
p := []ec2.IPPermission{
|
||||
ec2.IPPermission{
|
||||
FromPort: aws.Integer(80),
|
||||
ToPort: aws.Integer(9000),
|
||||
IPProtocol: aws.String("tcp"),
|
||||
IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("10.0.0.0/8")}},
|
||||
},
|
||||
ec2.IPPerm{
|
||||
FromPort: 80,
|
||||
ToPort: 8000,
|
||||
Protocol: "tcp",
|
||||
SourceIPs: []string{"0.0.0.0/0", "10.0.0.0/8"},
|
||||
ec2.IPPermission{
|
||||
FromPort: aws.Integer(80),
|
||||
ToPort: aws.Integer(8000),
|
||||
IPProtocol: aws.String("tcp"),
|
||||
IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("0.0.0.0/0")}, ec2.IPRange{aws.String("10.0.0.0/8")}},
|
||||
},
|
||||
}
|
||||
|
||||
if group.Name != "terraform_acceptance_test_example" {
|
||||
return fmt.Errorf("Bad name: %s", group.Name)
|
||||
if *group.GroupName != "terraform_acceptance_test_example" {
|
||||
return fmt.Errorf("Bad name: %s", *group.GroupName)
|
||||
}
|
||||
|
||||
if group.Description != "Used in the terraform acceptance tests" {
|
||||
return fmt.Errorf("Bad description: %s", group.Description)
|
||||
if *group.Description != "Used in the terraform acceptance tests" {
|
||||
return fmt.Errorf("Bad description: %s", *group.Description)
|
||||
}
|
||||
|
||||
// Compare our ingress
|
||||
if len(group.IPPerms) != 2 {
|
||||
if len(group.IPPermissions) != 2 {
|
||||
return fmt.Errorf(
|
||||
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
|
||||
group.IPPerms,
|
||||
group.IPPermissions,
|
||||
p)
|
||||
}
|
||||
|
||||
if group.IPPerms[0].ToPort == 8000 {
|
||||
group.IPPerms[1], group.IPPerms[0] =
|
||||
group.IPPerms[0], group.IPPerms[1]
|
||||
if *group.IPPermissions[0].ToPort == 8000 {
|
||||
group.IPPermissions[1], group.IPPermissions[0] =
|
||||
group.IPPermissions[0], group.IPPermissions[1]
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(group.IPPerms, p) {
|
||||
if !reflect.DeepEqual(group.IPPermissions, p) {
|
||||
return fmt.Errorf(
|
||||
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
|
||||
group.IPPerms,
|
||||
group.IPPermissions,
|
||||
p)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ func resourceAwsSubnet() *schema.Resource {
|
|||
}
|
||||
|
||||
func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
createOpts := &ec2.CreateSubnetRequest{
|
||||
AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
|
||||
|
@ -91,7 +91,7 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
|
||||
SubnetIDs: []string{d.Id()},
|
||||
|
@ -115,17 +115,17 @@ func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("availability_zone", subnet.AvailabilityZone)
|
||||
d.Set("cidr_block", subnet.CIDRBlock)
|
||||
d.Set("map_public_ip_on_launch", subnet.MapPublicIPOnLaunch)
|
||||
d.Set("tags", tagsToMapSDK(subnet.Tags))
|
||||
d.Set("tags", tagsToMap(subnet.Tags))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
d.Partial(true)
|
||||
|
||||
if err := setTagsSDK(ec2conn, d); err != nil {
|
||||
if err := setTags(ec2conn, d); err != nil {
|
||||
return err
|
||||
} else {
|
||||
d.SetPartial("tags")
|
||||
|
@ -154,7 +154,7 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
func resourceAwsSubnetDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).awsEC2conn
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
log.Printf("[INFO] Deleting subnet: %s", d.Id())
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestAccAWSSubnet(t *testing.T) {
|
|||
}
|
||||
|
||||
func testAccCheckSubnetDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_subnet" {
|
||||
|
@ -86,7 +86,7 @@ func testAccCheckSubnetExists(n string, v *ec2.Subnet) resource.TestCheckFunc {
|
|||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{
|
||||
SubnetIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsVpc() *schema.Resource {
|
||||
|
@ -64,22 +65,25 @@ func resourceAwsVpc() *schema.Resource {
|
|||
|
||||
func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Create the VPC
|
||||
createOpts := &ec2.CreateVpc{
|
||||
CidrBlock: d.Get("cidr_block").(string),
|
||||
InstanceTenancy: d.Get("instance_tenancy").(string),
|
||||
instance_tenancy := "default"
|
||||
if v, ok := d.GetOk("instance_tenancy"); ok {
|
||||
instance_tenancy = v.(string)
|
||||
}
|
||||
log.Printf("[DEBUG] VPC create config: %#v", createOpts)
|
||||
vpcResp, err := ec2conn.CreateVpc(createOpts)
|
||||
// Create the VPC
|
||||
createOpts := &ec2.CreateVPCRequest{
|
||||
CIDRBlock: aws.String(d.Get("cidr_block").(string)),
|
||||
InstanceTenancy: aws.String(instance_tenancy),
|
||||
}
|
||||
log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
|
||||
vpcResp, err := ec2conn.CreateVPC(createOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating VPC: %s", err)
|
||||
}
|
||||
|
||||
// Get the ID and store it
|
||||
vpc := &vpcResp.VPC
|
||||
log.Printf("[INFO] VPC ID: %s", vpc.VpcId)
|
||||
d.SetId(vpc.VpcId)
|
||||
vpc := vpcResp.VPC
|
||||
d.SetId(*vpc.VPCID)
|
||||
log.Printf("[INFO] VPC ID: %s", d.Id())
|
||||
|
||||
// Set partial mode and say that we setup the cidr block
|
||||
d.Partial(true)
|
||||
|
@ -120,34 +124,53 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
// VPC stuff
|
||||
vpc := vpcRaw.(*ec2.VPC)
|
||||
d.Set("cidr_block", vpc.CidrBlock)
|
||||
vpcid := d.Id()
|
||||
d.Set("cidr_block", vpc.CIDRBlock)
|
||||
|
||||
// Tags
|
||||
d.Set("tags", tagsToMap(vpc.Tags))
|
||||
|
||||
// Attributes
|
||||
resp, err := ec2conn.VpcAttribute(d.Id(), "enableDnsSupport")
|
||||
attribute := "enableDnsSupport"
|
||||
DescribeAttrOpts := &ec2.DescribeVPCAttributeRequest{
|
||||
Attribute: aws.String(attribute),
|
||||
VPCID: aws.String(vpcid),
|
||||
}
|
||||
resp, err := ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Set("enable_dns_support", resp.EnableDnsSupport)
|
||||
|
||||
resp, err = ec2conn.VpcAttribute(d.Id(), "enableDnsHostnames")
|
||||
d.Set("enable_dns_support", *resp.EnableDNSSupport)
|
||||
attribute = "enableDnsHostnames"
|
||||
DescribeAttrOpts = &ec2.DescribeVPCAttributeRequest{
|
||||
Attribute: &attribute,
|
||||
VPCID: &vpcid,
|
||||
}
|
||||
resp, err = ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Set("enable_dns_hostnames", resp.EnableDnsHostnames)
|
||||
d.Set("enable_dns_hostnames", *resp.EnableDNSHostnames)
|
||||
|
||||
// Get the main routing table for this VPC
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("association.main", "true")
|
||||
filter.Add("vpc-id", d.Id())
|
||||
routeResp, err := ec2conn.DescribeRouteTables(nil, filter)
|
||||
// Really Ugly need to make this better - rmenn
|
||||
filter1 := &ec2.Filter{
|
||||
Name: aws.String("association.main"),
|
||||
Values: []string{("true")},
|
||||
}
|
||||
filter2 := &ec2.Filter{
|
||||
Name: aws.String("vpc-id"),
|
||||
Values: []string{(d.Id())},
|
||||
}
|
||||
DescribeRouteOpts := &ec2.DescribeRouteTablesRequest{
|
||||
Filters: []ec2.Filter{*filter1, *filter2},
|
||||
}
|
||||
routeResp, err := ec2conn.DescribeRouteTables(DescribeRouteOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v := routeResp.RouteTables; len(v) > 0 {
|
||||
d.Set("main_route_table_id", v[0].RouteTableId)
|
||||
d.Set("main_route_table_id", *v[0].RouteTableID)
|
||||
}
|
||||
|
||||
resourceAwsVpcSetDefaultNetworkAcl(ec2conn, d)
|
||||
|
@ -161,16 +184,20 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
// Turn on partial mode
|
||||
d.Partial(true)
|
||||
|
||||
vpcid := d.Id()
|
||||
modifyOpts := &ec2.ModifyVPCAttributeRequest{
|
||||
VPCID: &vpcid,
|
||||
}
|
||||
if d.HasChange("enable_dns_hostnames") {
|
||||
options := new(ec2.ModifyVpcAttribute)
|
||||
options.EnableDnsHostnames = d.Get("enable_dns_hostnames").(bool)
|
||||
options.SetEnableDnsHostnames = true
|
||||
val := d.Get("enable_dns_hostnames").(bool)
|
||||
modifyOpts.EnableDNSHostnames = &ec2.AttributeBooleanValue{
|
||||
Value: &val,
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v",
|
||||
d.Id(), options)
|
||||
if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil {
|
||||
d.Id(), modifyOpts)
|
||||
if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -178,14 +205,15 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
if d.HasChange("enable_dns_support") {
|
||||
options := new(ec2.ModifyVpcAttribute)
|
||||
options.EnableDnsSupport = d.Get("enable_dns_support").(bool)
|
||||
options.SetEnableDnsSupport = true
|
||||
val := d.Get("enable_dns_hostnames").(bool)
|
||||
modifyOpts.EnableDNSSupport = &ec2.AttributeBooleanValue{
|
||||
Value: &val,
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
|
||||
d.Id(), options)
|
||||
if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil {
|
||||
d.Id(), modifyOpts)
|
||||
if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -204,10 +232,13 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
vpcID := d.Id()
|
||||
DeleteVpcOpts := &ec2.DeleteVPCRequest{
|
||||
VPCID: &vpcID,
|
||||
}
|
||||
log.Printf("[INFO] Deleting VPC: %s", d.Id())
|
||||
if _, err := ec2conn.DeleteVpc(d.Id()); err != nil {
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
if err := ec2conn.DeleteVPC(DeleteVpcOpts); err != nil {
|
||||
ec2err, ok := err.(*aws.APIError)
|
||||
if ok && ec2err.Code == "InvalidVpcID.NotFound" {
|
||||
return nil
|
||||
}
|
||||
|
@ -222,9 +253,12 @@ func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
|
|||
// a VPC.
|
||||
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.DescribeVpcs([]string{id}, ec2.NewFilter())
|
||||
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
|
||||
VPCIDs: []string{id},
|
||||
}
|
||||
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcID.NotFound" {
|
||||
if ec2err, ok := err.(*aws.APIError); ok && ec2err.Code == "InvalidVpcID.NotFound" {
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("Error on VPCStateRefresh: %s", err)
|
||||
|
@ -239,37 +273,53 @@ func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
|||
}
|
||||
|
||||
vpc := &resp.VPCs[0]
|
||||
return vpc, vpc.State, nil
|
||||
return vpc, *vpc.State, nil
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("default", "true")
|
||||
filter.Add("vpc-id", d.Id())
|
||||
networkAclResp, err := conn.NetworkAcls(nil, filter)
|
||||
filter1 := &ec2.Filter{
|
||||
Name: aws.String("default"),
|
||||
Values: []string{("true")},
|
||||
}
|
||||
filter2 := &ec2.Filter{
|
||||
Name: aws.String("vpc-id"),
|
||||
Values: []string{(d.Id())},
|
||||
}
|
||||
DescribeNetworkACLOpts := &ec2.DescribeNetworkACLsRequest{
|
||||
Filters: []ec2.Filter{*filter1, *filter2},
|
||||
}
|
||||
networkAclResp, err := conn.DescribeNetworkACLs(DescribeNetworkACLOpts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v := networkAclResp.NetworkAcls; len(v) > 0 {
|
||||
d.Set("default_network_acl_id", v[0].NetworkAclId)
|
||||
if v := networkAclResp.NetworkACLs; len(v) > 0 {
|
||||
d.Set("default_network_acl_id", v[0].NetworkACLID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
|
||||
filter := ec2.NewFilter()
|
||||
filter.Add("group-name", "default")
|
||||
filter.Add("vpc-id", d.Id())
|
||||
securityGroupResp, err := conn.SecurityGroups(nil, filter)
|
||||
filter1 := &ec2.Filter{
|
||||
Name: aws.String("group-name"),
|
||||
Values: []string{("default")},
|
||||
}
|
||||
filter2 := &ec2.Filter{
|
||||
Name: aws.String("vpc-id"),
|
||||
Values: []string{(d.Id())},
|
||||
}
|
||||
DescribeSgOpts := &ec2.DescribeSecurityGroupsRequest{
|
||||
Filters: []ec2.Filter{*filter1, *filter2},
|
||||
}
|
||||
securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v := securityGroupResp.Groups; len(v) > 0 {
|
||||
d.Set("default_security_group_id", v[0].Id)
|
||||
if v := securityGroupResp.SecurityGroups; len(v) > 0 {
|
||||
d.Set("default_security_group_id", v[0].GroupID)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func resourceAwsVpcPeeringConnection() *schema.Resource {
|
||||
|
@ -22,6 +23,7 @@ func resourceAwsVpcPeeringConnection() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("AWS_ACCOUNT_ID", nil),
|
||||
},
|
||||
"peer_vpc_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
|
@ -42,20 +44,20 @@ func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error
|
|||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
// Create the vpc peering connection
|
||||
createOpts := &ec2.CreateVpcPeeringConnection{
|
||||
PeerOwnerId: d.Get("peer_owner_id").(string),
|
||||
PeerVpcId: d.Get("peer_vpc_id").(string),
|
||||
VpcId: d.Get("vpc_id").(string),
|
||||
createOpts := &ec2.CreateVPCPeeringConnectionRequest{
|
||||
PeerOwnerID: aws.String(d.Get("peer_owner_id").(string)),
|
||||
PeerVPCID: aws.String(d.Get("peer_vpc_id").(string)),
|
||||
VPCID: aws.String(d.Get("vpc_id").(string)),
|
||||
}
|
||||
log.Printf("[DEBUG] VpcPeeringCreate create config: %#v", createOpts)
|
||||
resp, err := ec2conn.CreateVpcPeeringConnection(createOpts)
|
||||
resp, err := ec2conn.CreateVPCPeeringConnection(createOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating vpc peering connection: %s", err)
|
||||
}
|
||||
|
||||
// Get the ID and store it
|
||||
rt := &resp.VpcPeeringConnection
|
||||
d.SetId(rt.VpcPeeringConnectionId)
|
||||
rt := resp.VPCPeeringConnection
|
||||
d.SetId(*rt.VPCPeeringConnectionID)
|
||||
log.Printf("[INFO] Vpc Peering Connection ID: %s", d.Id())
|
||||
|
||||
// Wait for the vpc peering connection to become available
|
||||
|
@ -88,11 +90,11 @@ func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
pc := pcRaw.(*ec2.VpcPeeringConnection)
|
||||
pc := pcRaw.(*ec2.VPCPeeringConnection)
|
||||
|
||||
d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
|
||||
d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
|
||||
d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)
|
||||
d.Set("peer_owner_id", pc.AccepterVPCInfo.OwnerID)
|
||||
d.Set("peer_vpc_id", pc.AccepterVPCInfo.VPCID)
|
||||
d.Set("vpc_id", pc.RequesterVPCInfo.VPCID)
|
||||
d.Set("tags", tagsToMap(pc.Tags))
|
||||
|
||||
return nil
|
||||
|
@ -113,7 +115,10 @@ func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error
|
|||
func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
ec2conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
_, err := ec2conn.DeleteVpcPeeringConnection(d.Id())
|
||||
_, err := ec2conn.DeleteVPCPeeringConnection(
|
||||
&ec2.DeleteVPCPeeringConnectionRequest{
|
||||
VPCPeeringConnectionID: aws.String(d.Id()),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -122,9 +127,11 @@ func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error
|
|||
func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
|
||||
resp, err := conn.DescribeVpcPeeringConnection([]string{id}, ec2.NewFilter())
|
||||
resp, err := conn.DescribeVPCPeeringConnections(&ec2.DescribeVPCPeeringConnectionsRequest{
|
||||
VPCPeeringConnectionIDs: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" {
|
||||
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" {
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("Error on VpcPeeringConnectionStateRefresh: %s", err)
|
||||
|
@ -138,7 +145,7 @@ func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) r
|
|||
return nil, "", nil
|
||||
}
|
||||
|
||||
pc := &resp.VpcPeeringConnections[0]
|
||||
pc := &resp.VPCPeeringConnections[0]
|
||||
|
||||
return pc, "ready", nil
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestAccAWSVPCPeeringConnection_normal(t *testing.T) {
|
||||
|
@ -35,10 +35,13 @@ func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error {
|
|||
continue
|
||||
}
|
||||
|
||||
describe, err := conn.DescribeVpcPeeringConnection([]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
describe, err := conn.DescribeVPCPeeringConnections(
|
||||
&ec2.DescribeVPCPeeringConnectionsRequest{
|
||||
VPCPeeringConnectionIDs: []string{rs.Primary.ID},
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
if len(describe.VpcPeeringConnections) != 0 {
|
||||
if len(describe.VPCPeeringConnections) != 0 {
|
||||
return fmt.Errorf("vpc peering connection still exists")
|
||||
}
|
||||
}
|
||||
|
@ -68,11 +71,10 @@ resource "aws_vpc" "foo" {
|
|||
}
|
||||
|
||||
resource "aws_vpc" "bar" {
|
||||
cidr_block = "10.0.1.0/16"
|
||||
cidr_block = "10.1.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_vpc_peering_connection" "foo" {
|
||||
peer_owner_id = "12345"
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
peer_vpc_id = "${aws_vpc.bar.id}"
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccVpc_basic(t *testing.T) {
|
||||
|
@ -119,7 +119,10 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Try to find the VPC
|
||||
resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
|
||||
VPCIDs: []string{rs.Primary.ID},
|
||||
}
|
||||
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
|
||||
if err == nil {
|
||||
if len(resp.VPCs) > 0 {
|
||||
return fmt.Errorf("VPCs still exist.")
|
||||
|
@ -129,7 +132,7 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
|
|||
}
|
||||
|
||||
// Verify the error is what we want
|
||||
ec2err, ok := err.(*ec2.Error)
|
||||
ec2err, ok := err.(*aws.APIError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
@ -143,8 +146,9 @@ func testAccCheckVpcDestroy(s *terraform.State) error {
|
|||
|
||||
func testAccCheckVpcCidr(vpc *ec2.VPC, expected string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if vpc.CidrBlock != expected {
|
||||
return fmt.Errorf("Bad cidr: %s", vpc.CidrBlock)
|
||||
CIDRBlock := vpc.CIDRBlock
|
||||
if *CIDRBlock != expected {
|
||||
return fmt.Errorf("Bad cidr: %s", *vpc.CIDRBlock)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -163,7 +167,10 @@ func testAccCheckVpcExists(n string, vpc *ec2.VPC) resource.TestCheckFunc {
|
|||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.DescribeVpcs([]string{rs.Primary.ID}, ec2.NewFilter())
|
||||
DescribeVpcOpts := &ec2.DescribeVPCsRequest{
|
||||
VPCIDs: []string{rs.Primary.ID},
|
||||
}
|
||||
resp, err := conn.DescribeVPCs(DescribeVpcOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/elb"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/rds"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
// Takes the result of flatmap.Expand for an array of listeners and
|
||||
|
@ -16,7 +16,7 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) {
|
|||
listeners := make([]elb.Listener, 0, len(configured))
|
||||
|
||||
// Loop over our configured listeners and create
|
||||
// an array of goamz compatabile objects
|
||||
// an array of aws-sdk-go compatabile objects
|
||||
for _, lRaw := range configured {
|
||||
data := lRaw.(map[string]interface{})
|
||||
|
||||
|
@ -39,15 +39,15 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) {
|
|||
|
||||
// Takes the result of flatmap.Expand for an array of ingress/egress
|
||||
// security group rules and returns EC2 API compatible objects
|
||||
func expandIPPerms(id string, configured []interface{}) []ec2.IPPerm {
|
||||
perms := make([]ec2.IPPerm, len(configured))
|
||||
func expandIPPerms(id string, configured []interface{}) []ec2.IPPermission {
|
||||
perms := make([]ec2.IPPermission, len(configured))
|
||||
for i, mRaw := range configured {
|
||||
var perm ec2.IPPerm
|
||||
var perm ec2.IPPermission
|
||||
m := mRaw.(map[string]interface{})
|
||||
|
||||
perm.FromPort = m["from_port"].(int)
|
||||
perm.ToPort = m["to_port"].(int)
|
||||
perm.Protocol = m["protocol"].(string)
|
||||
perm.FromPort = aws.Integer(m["from_port"].(int))
|
||||
perm.ToPort = aws.Integer(m["to_port"].(int))
|
||||
perm.IPProtocol = aws.String(m["protocol"].(string))
|
||||
|
||||
var groups []string
|
||||
if raw, ok := m["security_groups"]; ok {
|
||||
|
@ -61,25 +61,25 @@ func expandIPPerms(id string, configured []interface{}) []ec2.IPPerm {
|
|||
}
|
||||
|
||||
if len(groups) > 0 {
|
||||
perm.SourceGroups = make([]ec2.UserSecurityGroup, len(groups))
|
||||
perm.UserIDGroupPairs = make([]ec2.UserIDGroupPair, len(groups))
|
||||
for i, name := range groups {
|
||||
ownerId, id := "", name
|
||||
if items := strings.Split(id, "/"); len(items) > 1 {
|
||||
ownerId, id = items[0], items[1]
|
||||
}
|
||||
|
||||
perm.SourceGroups[i] = ec2.UserSecurityGroup{
|
||||
Id: id,
|
||||
OwnerId: ownerId,
|
||||
perm.UserIDGroupPairs[i] = ec2.UserIDGroupPair{
|
||||
GroupID: aws.String(id),
|
||||
UserID: aws.String(ownerId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if raw, ok := m["cidr_blocks"]; ok {
|
||||
list := raw.([]interface{})
|
||||
perm.SourceIPs = make([]string, len(list))
|
||||
perm.IPRanges = make([]ec2.IPRange, len(list))
|
||||
for i, v := range list {
|
||||
perm.SourceIPs[i] = v.(string)
|
||||
perm.IPRanges[i] = ec2.IPRange{aws.String(v.(string))}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func expandParameters(configured []interface{}) ([]rds.Parameter, error) {
|
|||
parameters := make([]rds.Parameter, 0, len(configured))
|
||||
|
||||
// Loop over our configured parameters and create
|
||||
// an array of goamz compatabile objects
|
||||
// an array of aws-sdk-go compatabile objects
|
||||
for _, pRaw := range configured {
|
||||
data := pRaw.(map[string]interface{})
|
||||
|
||||
|
@ -111,31 +111,6 @@ func expandParameters(configured []interface{}) ([]rds.Parameter, error) {
|
|||
return parameters, nil
|
||||
}
|
||||
|
||||
// Flattens an array of ipPerms into a list of primitives that
|
||||
// flatmap.Flatten() can handle
|
||||
func flattenIPPerms(list []ec2.IPPerm) []map[string]interface{} {
|
||||
result := make([]map[string]interface{}, 0, len(list))
|
||||
|
||||
for _, perm := range list {
|
||||
n := make(map[string]interface{})
|
||||
n["from_port"] = perm.FromPort
|
||||
n["protocol"] = perm.Protocol
|
||||
n["to_port"] = perm.ToPort
|
||||
|
||||
if len(perm.SourceIPs) > 0 {
|
||||
n["cidr_blocks"] = perm.SourceIPs
|
||||
}
|
||||
|
||||
if v := flattenSecurityGroups(perm.SourceGroups); len(v) > 0 {
|
||||
n["security_groups"] = v
|
||||
}
|
||||
|
||||
result = append(result, n)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Flattens a health check into something that flatmap.Flatten()
|
||||
// can handle
|
||||
func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
|
||||
|
@ -154,10 +129,10 @@ func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
|
|||
}
|
||||
|
||||
// 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)
|
||||
result = append(result, *g.GroupID)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
ec2 "github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/elb"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/rds"
|
||||
"github.com/hashicorp/terraform/flatmap"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
// Returns test configuration
|
||||
|
@ -61,120 +61,58 @@ func TestExpandIPPerms(t *testing.T) {
|
|||
}
|
||||
perms := expandIPPerms("foo", expanded)
|
||||
|
||||
expected := []ec2.IPPerm{
|
||||
ec2.IPPerm{
|
||||
Protocol: "icmp",
|
||||
FromPort: 1,
|
||||
ToPort: -1,
|
||||
SourceIPs: []string{"0.0.0.0/0"},
|
||||
SourceGroups: []ec2.UserSecurityGroup{
|
||||
ec2.UserSecurityGroup{
|
||||
OwnerId: "foo",
|
||||
Id: "sg-22222",
|
||||
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{
|
||||
UserID: aws.String("foo"),
|
||||
GroupID: aws.String("sg-22222"),
|
||||
},
|
||||
ec2.UserSecurityGroup{
|
||||
Id: "sg-11111",
|
||||
ec2.UserIDGroupPair{
|
||||
GroupID: aws.String("sg-22222"),
|
||||
},
|
||||
},
|
||||
},
|
||||
ec2.IPPerm{
|
||||
Protocol: "icmp",
|
||||
FromPort: 1,
|
||||
ToPort: -1,
|
||||
SourceGroups: []ec2.UserSecurityGroup{
|
||||
ec2.UserSecurityGroup{
|
||||
Id: "foo",
|
||||
ec2.IPPermission{
|
||||
IPProtocol: aws.String("icmp"),
|
||||
FromPort: aws.Integer(1),
|
||||
ToPort: aws.Integer(-1),
|
||||
UserIDGroupPairs: []ec2.UserIDGroupPair{
|
||||
ec2.UserIDGroupPair{
|
||||
UserID: aws.String("foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(perms, expected) {
|
||||
exp := expected[0]
|
||||
perm := perms[0]
|
||||
|
||||
if *exp.FromPort != *perm.FromPort {
|
||||
t.Fatalf(
|
||||
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
|
||||
perms[0],
|
||||
expected)
|
||||
*perm.FromPort,
|
||||
*exp.FromPort)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestFlattenIPPerms(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input []ec2.IPPerm
|
||||
Output []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
Input: []ec2.IPPerm{
|
||||
ec2.IPPerm{
|
||||
Protocol: "icmp",
|
||||
FromPort: 1,
|
||||
ToPort: -1,
|
||||
SourceIPs: []string{"0.0.0.0/0"},
|
||||
SourceGroups: []ec2.UserSecurityGroup{
|
||||
ec2.UserSecurityGroup{
|
||||
Id: "sg-11111",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Output: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"protocol": "icmp",
|
||||
"from_port": 1,
|
||||
"to_port": -1,
|
||||
"cidr_blocks": []string{"0.0.0.0/0"},
|
||||
"security_groups": []string{"sg-11111"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Input: []ec2.IPPerm{
|
||||
ec2.IPPerm{
|
||||
Protocol: "icmp",
|
||||
FromPort: 1,
|
||||
ToPort: -1,
|
||||
SourceIPs: []string{"0.0.0.0/0"},
|
||||
SourceGroups: nil,
|
||||
},
|
||||
},
|
||||
|
||||
Output: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"protocol": "icmp",
|
||||
"from_port": 1,
|
||||
"to_port": -1,
|
||||
"cidr_blocks": []string{"0.0.0.0/0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Input: []ec2.IPPerm{
|
||||
ec2.IPPerm{
|
||||
Protocol: "icmp",
|
||||
FromPort: 1,
|
||||
ToPort: -1,
|
||||
SourceIPs: nil,
|
||||
},
|
||||
},
|
||||
|
||||
Output: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"protocol": "icmp",
|
||||
"from_port": 1,
|
||||
"to_port": -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
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)
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
output := flattenIPPerms(tc.Input)
|
||||
if !reflect.DeepEqual(output, tc.Output) {
|
||||
t.Fatalf("Input:\n\n%#v\n\nOutput:\n\n%#v", tc.Input, output)
|
||||
}
|
||||
if *exp.UserIDGroupPairs[0].UserID != *perm.UserIDGroupPairs[0].UserID {
|
||||
t.Fatalf(
|
||||
"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
|
||||
*perm.UserIDGroupPairs[0].UserID,
|
||||
*exp.UserIDGroupPairs[0].UserID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExpandListeners(t *testing.T) {
|
||||
|
|
|
@ -3,11 +3,13 @@ package aws
|
|||
import (
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
// tagsSchema returns the schema to use for tags.
|
||||
//
|
||||
func tagsSchema() *schema.Schema {
|
||||
return &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
|
@ -27,13 +29,21 @@ func setTags(conn *ec2.EC2, d *schema.ResourceData) error {
|
|||
// Set tags
|
||||
if len(remove) > 0 {
|
||||
log.Printf("[DEBUG] Removing tags: %#v", remove)
|
||||
if _, err := conn.DeleteTags([]string{d.Id()}, remove); err != nil {
|
||||
err := conn.DeleteTags(&ec2.DeleteTagsRequest{
|
||||
Resources: []string{d.Id()},
|
||||
Tags: remove,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(create) > 0 {
|
||||
log.Printf("[DEBUG] Creating tags: %#v", create)
|
||||
if _, err := conn.CreateTags([]string{d.Id()}, create); err != nil {
|
||||
err := conn.CreateTags(&ec2.CreateTagsRequest{
|
||||
Resources: []string{d.Id()},
|
||||
Tags: create,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -49,14 +59,14 @@ func diffTags(oldTags, newTags []ec2.Tag) ([]ec2.Tag, []ec2.Tag) {
|
|||
// First, we're creating everything we have
|
||||
create := make(map[string]interface{})
|
||||
for _, t := range newTags {
|
||||
create[t.Key] = t.Value
|
||||
create[*t.Key] = *t.Value
|
||||
}
|
||||
|
||||
// Build the list of what to remove
|
||||
var remove []ec2.Tag
|
||||
for _, t := range oldTags {
|
||||
old, ok := create[t.Key]
|
||||
if !ok || old != t.Value {
|
||||
old, ok := create[*t.Key]
|
||||
if !ok || old != *t.Value {
|
||||
// Delete it!
|
||||
remove = append(remove, t)
|
||||
}
|
||||
|
@ -70,8 +80,8 @@ func tagsFromMap(m map[string]interface{}) []ec2.Tag {
|
|||
result := make([]ec2.Tag, 0, len(m))
|
||||
for k, v := range m {
|
||||
result = append(result, ec2.Tag{
|
||||
Key: k,
|
||||
Value: v.(string),
|
||||
Key: aws.String(k),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -82,7 +92,7 @@ func tagsFromMap(m map[string]interface{}) []ec2.Tag {
|
|||
func tagsToMap(ts []ec2.Tag) map[string]string {
|
||||
result := make(map[string]string)
|
||||
for _, t := range ts {
|
||||
result[t.Key] = t.Value
|
||||
result[*t.Key] = *t.Value
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/gen/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
)
|
||||
|
||||
func TestDiffTags(t *testing.T) {
|
||||
|
|
|
@ -30,7 +30,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_TIMEOUT", 180),
|
||||
DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_TIMEOUT", 300),
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -46,6 +46,9 @@ func Provider() terraform.ResourceProvider {
|
|||
"cloudstack_nic": resourceCloudStackNIC(),
|
||||
"cloudstack_port_forward": resourceCloudStackPortForward(),
|
||||
"cloudstack_vpc": resourceCloudStackVPC(),
|
||||
"cloudstack_vpn_connection": resourceCloudStackVPNConnection(),
|
||||
"cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(),
|
||||
"cloudstack_vpn_gateway": resourceCloudStackVPNGateway(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
|
|
@ -51,7 +51,8 @@ var CLOUDSTACK_NETWORK_1_OFFERING = ""
|
|||
var CLOUDSTACK_NETWORK_1_IPADDRESS = ""
|
||||
var CLOUDSTACK_NETWORK_2 = ""
|
||||
var CLOUDSTACK_NETWORK_2_IPADDRESS = ""
|
||||
var CLOUDSTACK_VPC_CIDR = ""
|
||||
var CLOUDSTACK_VPC_CIDR_1 = ""
|
||||
var CLOUDSTACK_VPC_CIDR_2 = ""
|
||||
var CLOUDSTACK_VPC_OFFERING = ""
|
||||
var CLOUDSTACK_VPC_NETWORK_CIDR = ""
|
||||
var CLOUDSTACK_VPC_NETWORK_OFFERING = ""
|
||||
|
|
|
@ -95,18 +95,18 @@ func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta interface{})
|
|||
return e.Error()
|
||||
}
|
||||
|
||||
// Retrieve the template UUID
|
||||
templateid, e := retrieveUUID(cs, "template", d.Get("template").(string))
|
||||
if e != nil {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// Retrieve the zone object
|
||||
zone, _, err := cs.Zone.GetZoneByName(d.Get("zone").(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieve the template UUID
|
||||
templateid, e := retrieveTemplateUUID(cs, zone.Id, d.Get("template").(string))
|
||||
if e != nil {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VirtualMachine.NewDeployVirtualMachineParams(serviceofferingid, templateid, zone.Id)
|
||||
|
||||
|
|
|
@ -132,6 +132,6 @@ resource "cloudstack_vpc" "foobar" {
|
|||
resource "cloudstack_ipaddress" "foo" {
|
||||
vpc = "${cloudstack_vpc.foobar.name}"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
|
|
@ -196,7 +196,7 @@ resource "cloudstack_network_acl_rule" "foo" {
|
|||
traffic_type = "ingress"
|
||||
}
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
||||
|
@ -233,6 +233,6 @@ resource "cloudstack_network_acl_rule" "foo" {
|
|||
traffic_type = "egress"
|
||||
}
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
|
|
@ -112,6 +112,6 @@ resource "cloudstack_network_acl" "foo" {
|
|||
description = "terraform-acl-text"
|
||||
vpc = "${cloudstack_vpc.foobar.name}"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
|
|
@ -186,7 +186,7 @@ resource "cloudstack_network" "foo" {
|
|||
aclid = "${cloudstack_network_acl.foo.id}"
|
||||
zone = "${cloudstack_vpc.foobar.zone}"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE,
|
||||
CLOUDSTACK_VPC_NETWORK_CIDR,
|
||||
|
|
|
@ -72,8 +72,8 @@ func testAccCheckCloudStackVPCAttributes(
|
|||
return fmt.Errorf("Bad display text: %s", vpc.Displaytext)
|
||||
}
|
||||
|
||||
if vpc.Cidr != CLOUDSTACK_VPC_CIDR {
|
||||
return fmt.Errorf("Bad VPC offering: %s", vpc.Cidr)
|
||||
if vpc.Cidr != CLOUDSTACK_VPC_CIDR_1 {
|
||||
return fmt.Errorf("Bad VPC CIDR: %s", vpc.Cidr)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -113,6 +113,6 @@ resource "cloudstack_vpc" "foo" {
|
|||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func resourceCloudStackVPNConnection() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceCloudStackVPNConnectionCreate,
|
||||
Read: resourceCloudStackVPNConnectionRead,
|
||||
Delete: resourceCloudStackVPNConnectionDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"customergatewayid": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"vpngatewayid": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNConnectionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewCreateVpnConnectionParams(
|
||||
d.Get("customergatewayid").(string),
|
||||
d.Get("vpngatewayid").(string),
|
||||
)
|
||||
|
||||
// Create the new VPN Connection
|
||||
v, err := cs.VPN.CreateVpnConnection(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating VPN Connection: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(v.Id)
|
||||
|
||||
return resourceCloudStackVPNConnectionRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNConnectionRead(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Get the VPN Connection details
|
||||
v, count, err := cs.VPN.GetVpnConnectionByID(d.Id())
|
||||
if err != nil {
|
||||
if count == 0 {
|
||||
log.Printf("[DEBUG] VPN Connection does no longer exist")
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("customergatewayid", v.S2scustomergatewayid)
|
||||
d.Set("vpngatewayid", v.S2svpngatewayid)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNConnectionDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewDeleteVpnConnectionParams(d.Id())
|
||||
|
||||
// Delete the VPN Connection
|
||||
_, err := cs.VPN.DeleteVpnConnection(p)
|
||||
if err != nil {
|
||||
// This is a very poor way to be told the UUID does no longer exist :(
|
||||
if strings.Contains(err.Error(), fmt.Sprintf(
|
||||
"Invalid parameter id value=%s due to incorrect long value format, "+
|
||||
"or entity does not exist", d.Id())) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error deleting VPN Connection: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func TestAccCloudStackVPNConnection_basic(t *testing.T) {
|
||||
var vpnConnection cloudstack.VpnConnection
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckCloudStackVPNConnectionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCloudStackVPNConnection_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudStackVPNConnectionExists(
|
||||
"cloudstack_vpn_connection.foo-bar", &vpnConnection),
|
||||
testAccCheckCloudStackVPNConnectionExists(
|
||||
"cloudstack_vpn_connection.bar-foo", &vpnConnection),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNConnectionExists(
|
||||
n string, vpnConnection *cloudstack.VpnConnection) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN Connection ID is set")
|
||||
}
|
||||
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
v, _, err := cs.VPN.GetVpnConnectionByID(rs.Primary.ID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v.Id != rs.Primary.ID {
|
||||
return fmt.Errorf("VPN Connection not found")
|
||||
}
|
||||
|
||||
*vpnConnection = *v
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNConnectionDestroy(s *terraform.State) error {
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "cloudstack_vpn_connection" {
|
||||
continue
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN Connection ID is set")
|
||||
}
|
||||
|
||||
p := cs.VPN.NewDeleteVpnConnectionParams(rs.Primary.ID)
|
||||
_, err := cs.VPN.DeleteVpnConnection(p)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error deleting VPN Connection (%s): %s",
|
||||
rs.Primary.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccCloudStackVPNConnection_basic = fmt.Sprintf(`
|
||||
resource "cloudstack_vpc" "foo" {
|
||||
name = "terraform-vpc-foo"
|
||||
cidr = "%s"
|
||||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpc" "bar" {
|
||||
name = "terraform-vpc-bar"
|
||||
cidr = "%s"
|
||||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_gateway" "foo" {
|
||||
vpc = "${cloudstack_vpc.foo.name}"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_gateway" "bar" {
|
||||
vpc = "${cloudstack_vpc.bar.name}"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_customer_gateway" "foo" {
|
||||
name = "terraform-foo"
|
||||
cidr = "${cloudstack_vpc.foo.cidr}"
|
||||
esp_policy = "aes256-sha1"
|
||||
gateway = "${cloudstack_vpn_gateway.foo.public_ip}"
|
||||
ike_policy = "aes256-sha1"
|
||||
ipsec_psk = "terraform"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_customer_gateway" "bar" {
|
||||
name = "terraform-bar"
|
||||
cidr = "${cloudstack_vpc.bar.cidr}"
|
||||
esp_policy = "aes256-sha1"
|
||||
gateway = "${cloudstack_vpn_gateway.bar.public_ip}"
|
||||
ike_policy = "aes256-sha1"
|
||||
ipsec_psk = "terraform"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_connection" "foo-bar" {
|
||||
customergatewayid = "${cloudstack_vpn_customer_gateway.foo.id}"
|
||||
vpngatewayid = "${cloudstack_vpn_gateway.bar.id}"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_connection" "bar-foo" {
|
||||
customergatewayid = "${cloudstack_vpn_customer_gateway.bar.id}"
|
||||
vpngatewayid = "${cloudstack_vpn_gateway.foo.id}"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE,
|
||||
CLOUDSTACK_VPC_CIDR_2,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
|
@ -0,0 +1,193 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func resourceCloudStackVPNCustomerGateway() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceCloudStackVPNCustomerGatewayCreate,
|
||||
Read: resourceCloudStackVPNCustomerGatewayRead,
|
||||
Update: resourceCloudStackVPNCustomerGatewayUpdate,
|
||||
Delete: resourceCloudStackVPNCustomerGatewayDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"cidr": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"esp_policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"gateway": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"ike_policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"ipsec_psk": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"dpd": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"esp_lifetime": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"ike_lifetime": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewCreateVpnCustomerGatewayParams(
|
||||
d.Get("cidr").(string),
|
||||
d.Get("esp_policy").(string),
|
||||
d.Get("gateway").(string),
|
||||
d.Get("ike_policy").(string),
|
||||
d.Get("ipsec_psk").(string),
|
||||
)
|
||||
|
||||
p.SetName(d.Get("name").(string))
|
||||
|
||||
if dpd, ok := d.GetOk("dpd"); ok {
|
||||
p.SetDpd(dpd.(bool))
|
||||
}
|
||||
|
||||
if esplifetime, ok := d.GetOk("esp_lifetime"); ok {
|
||||
p.SetEsplifetime(esplifetime.(int))
|
||||
}
|
||||
|
||||
if ikelifetime, ok := d.GetOk("ike_lifetime"); ok {
|
||||
p.SetIkelifetime(ikelifetime.(int))
|
||||
}
|
||||
|
||||
// Create the new VPN Customer Gateway
|
||||
v, err := cs.VPN.CreateVpnCustomerGateway(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating VPN Customer Gateway %s: %s", d.Get("name").(string), err)
|
||||
}
|
||||
|
||||
d.SetId(v.Id)
|
||||
|
||||
return resourceCloudStackVPNCustomerGatewayRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Get the VPN Customer Gateway details
|
||||
v, count, err := cs.VPN.GetVpnCustomerGatewayByID(d.Id())
|
||||
if err != nil {
|
||||
if count == 0 {
|
||||
log.Printf(
|
||||
"[DEBUG] VPN Customer Gateway %s does no longer exist", d.Get("name").(string))
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("name", v.Name)
|
||||
d.Set("cidr", v.Cidrlist)
|
||||
d.Set("esp_policy", v.Esppolicy)
|
||||
d.Set("gateway", v.Gateway)
|
||||
d.Set("ike_policy", v.Ikepolicy)
|
||||
d.Set("ipsec_psk", v.Ipsecpsk)
|
||||
d.Set("dpd", v.Dpd)
|
||||
d.Set("esp_lifetime", v.Esplifetime)
|
||||
d.Set("ike_lifetime", v.Ikelifetime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNCustomerGatewayUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewUpdateVpnCustomerGatewayParams(
|
||||
d.Get("cidr").(string),
|
||||
d.Get("esp_policy").(string),
|
||||
d.Get("gateway").(string),
|
||||
d.Id(),
|
||||
d.Get("ike_policy").(string),
|
||||
d.Get("ipsec_psk").(string),
|
||||
)
|
||||
|
||||
p.SetName(d.Get("name").(string))
|
||||
|
||||
if dpd, ok := d.GetOk("dpd"); ok {
|
||||
p.SetDpd(dpd.(bool))
|
||||
}
|
||||
|
||||
if esplifetime, ok := d.GetOk("esp_lifetime"); ok {
|
||||
p.SetEsplifetime(esplifetime.(int))
|
||||
}
|
||||
|
||||
if ikelifetime, ok := d.GetOk("ike_lifetime"); ok {
|
||||
p.SetIkelifetime(ikelifetime.(int))
|
||||
}
|
||||
|
||||
// Update the VPN Customer Gateway
|
||||
_, err := cs.VPN.UpdateVpnCustomerGateway(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating VPN Customer Gateway %s: %s", d.Get("name").(string), err)
|
||||
}
|
||||
|
||||
return resourceCloudStackVPNCustomerGatewayRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNCustomerGatewayDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewDeleteVpnCustomerGatewayParams(d.Id())
|
||||
|
||||
// Delete the VPN Customer Gateway
|
||||
_, err := cs.VPN.DeleteVpnCustomerGateway(p)
|
||||
if err != nil {
|
||||
// This is a very poor way to be told the UUID does no longer exist :(
|
||||
if strings.Contains(err.Error(), fmt.Sprintf(
|
||||
"Invalid parameter id value=%s due to incorrect long value format, "+
|
||||
"or entity does not exist", d.Id())) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error deleting VPN Customer Gateway %s: %s", d.Get("name").(string), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func TestAccCloudStackVPNCustomerGateway_basic(t *testing.T) {
|
||||
var vpnCustomerGateway cloudstack.VpnCustomerGateway
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckCloudStackVPNCustomerGatewayDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCloudStackVPNCustomerGateway_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudStackVPNCustomerGatewayExists(
|
||||
"cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway),
|
||||
testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "ike_policy", "aes256-sha1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "esp_policy", "aes256-sha1"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccCloudStackVPNCustomerGateway_update(t *testing.T) {
|
||||
var vpnCustomerGateway cloudstack.VpnCustomerGateway
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckCloudStackVPNCustomerGatewayDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCloudStackVPNCustomerGateway_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudStackVPNCustomerGatewayExists(
|
||||
"cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway),
|
||||
testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "ike_policy", "aes256-sha1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "esp_policy", "aes256-sha1"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccCloudStackVPNCustomerGateway_update,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudStackVPNCustomerGatewayExists(
|
||||
"cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway),
|
||||
testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo-bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar-foo"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.foo", "ike_policy", "3des-md5"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_customer_gateway.bar", "esp_policy", "3des-md5"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNCustomerGatewayExists(
|
||||
n string, vpnCustomerGateway *cloudstack.VpnCustomerGateway) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN CustomerGateway ID is set")
|
||||
}
|
||||
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
v, _, err := cs.VPN.GetVpnCustomerGatewayByID(rs.Primary.ID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v.Id != rs.Primary.ID {
|
||||
return fmt.Errorf("VPN CustomerGateway not found")
|
||||
}
|
||||
|
||||
*vpnCustomerGateway = *v
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNCustomerGatewayAttributes(
|
||||
vpnCustomerGateway *cloudstack.VpnCustomerGateway) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if vpnCustomerGateway.Esppolicy != "aes256-sha1" {
|
||||
return fmt.Errorf("Bad ESP policy: %s", vpnCustomerGateway.Esppolicy)
|
||||
}
|
||||
|
||||
if vpnCustomerGateway.Ikepolicy != "aes256-sha1" {
|
||||
return fmt.Errorf("Bad IKE policy: %s", vpnCustomerGateway.Ikepolicy)
|
||||
}
|
||||
|
||||
if vpnCustomerGateway.Ipsecpsk != "terraform" {
|
||||
return fmt.Errorf("Bad IPSEC pre-shared key: %s", vpnCustomerGateway.Ipsecpsk)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNCustomerGatewayDestroy(s *terraform.State) error {
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "cloudstack_vpn_customer_gateway" {
|
||||
continue
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN Customer Gateway ID is set")
|
||||
}
|
||||
|
||||
p := cs.VPN.NewDeleteVpnCustomerGatewayParams(rs.Primary.ID)
|
||||
_, err := cs.VPN.DeleteVpnCustomerGateway(p)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error deleting VPN Customer Gateway (%s): %s",
|
||||
rs.Primary.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccCloudStackVPNCustomerGateway_basic = fmt.Sprintf(`
|
||||
resource "cloudstack_vpc" "foo" {
|
||||
name = "terraform-vpc-foo"
|
||||
cidr = "%s"
|
||||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpc" "bar" {
|
||||
name = "terraform-vpc-bar"
|
||||
cidr = "%s"
|
||||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_gateway" "foo" {
|
||||
vpc = "${cloudstack_vpc.foo.name}"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_gateway" "bar" {
|
||||
vpc = "${cloudstack_vpc.bar.name}"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_customer_gateway" "foo" {
|
||||
name = "terraform-foo"
|
||||
cidr = "${cloudstack_vpc.foo.cidr}"
|
||||
esp_policy = "aes256-sha1"
|
||||
gateway = "${cloudstack_vpn_gateway.foo.public_ip}"
|
||||
ike_policy = "aes256-sha1"
|
||||
ipsec_psk = "terraform"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_customer_gateway" "bar" {
|
||||
name = "terraform-bar"
|
||||
cidr = "${cloudstack_vpc.bar.cidr}"
|
||||
esp_policy = "aes256-sha1"
|
||||
gateway = "${cloudstack_vpn_gateway.bar.public_ip}"
|
||||
ike_policy = "aes256-sha1"
|
||||
ipsec_psk = "terraform"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE,
|
||||
CLOUDSTACK_VPC_CIDR_2,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
||||
|
||||
var testAccCloudStackVPNCustomerGateway_update = fmt.Sprintf(`
|
||||
resource "cloudstack_vpn_customer_gateway" "foo" {
|
||||
name = "terraform-foo-bar"
|
||||
cidr = "${cloudstack_vpc.foo.cidr}"
|
||||
esp_policy = "3des-md5"
|
||||
gateway = "${cloudstack_vpn_gateway.foo.public_ip}"
|
||||
ike_policy = "3des-md5"
|
||||
ipsec_psk = "terraform"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_customer_gateway" "bar" {
|
||||
name = "terraform-bar-foo"
|
||||
cidr = "${cloudstack_vpc.bar.cidr}"
|
||||
esp_policy = "3des-md5"
|
||||
gateway = "${cloudstack_vpn_gateway.bar.public_ip}"
|
||||
ike_policy = "3des-md5"
|
||||
ipsec_psk = "terraform"
|
||||
}`)
|
|
@ -0,0 +1,97 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func resourceCloudStackVPNGateway() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceCloudStackVPNGatewayCreate,
|
||||
Read: resourceCloudStackVPNGatewayRead,
|
||||
Delete: resourceCloudStackVPNGatewayDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"vpc": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"public_ip": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNGatewayCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Retrieve the VPC UUID
|
||||
vpcid, e := retrieveUUID(cs, "vpc", d.Get("vpc").(string))
|
||||
if e != nil {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewCreateVpnGatewayParams(vpcid)
|
||||
|
||||
// Create the new VPN Gateway
|
||||
v, err := cs.VPN.CreateVpnGateway(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating VPN Gateway for VPC %s: %s", d.Get("vpc").(string), err)
|
||||
}
|
||||
|
||||
d.SetId(v.Id)
|
||||
|
||||
return resourceCloudStackVPNGatewayRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNGatewayRead(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Get the VPN Gateway details
|
||||
v, count, err := cs.VPN.GetVpnGatewayByID(d.Id())
|
||||
if err != nil {
|
||||
if count == 0 {
|
||||
log.Printf(
|
||||
"[DEBUG] VPN Gateway for VPC %s does no longer exist", d.Get("vpc").(string))
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("public_ip", v.Publicip)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceCloudStackVPNGatewayDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
cs := meta.(*cloudstack.CloudStackClient)
|
||||
|
||||
// Create a new parameter struct
|
||||
p := cs.VPN.NewDeleteVpnGatewayParams(d.Id())
|
||||
|
||||
// Delete the VPN Gateway
|
||||
_, err := cs.VPN.DeleteVpnGateway(p)
|
||||
if err != nil {
|
||||
// This is a very poor way to be told the UUID does no longer exist :(
|
||||
if strings.Contains(err.Error(), fmt.Sprintf(
|
||||
"Invalid parameter id value=%s due to incorrect long value format, "+
|
||||
"or entity does not exist", d.Id())) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error deleting VPN Gateway for VPC %s: %s", d.Get("vpc").(string), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package cloudstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||
)
|
||||
|
||||
func TestAccCloudStackVPNGateway_basic(t *testing.T) {
|
||||
var vpnGateway cloudstack.VpnGateway
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckCloudStackVPNGatewayDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCloudStackVPNGateway_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudStackVPNGatewayExists(
|
||||
"cloudstack_vpn_gateway.foo", &vpnGateway),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_vpn_gateway.foo", "vpc", "terraform-vpc"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNGatewayExists(
|
||||
n string, vpnGateway *cloudstack.VpnGateway) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN Gateway ID is set")
|
||||
}
|
||||
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
v, _, err := cs.VPN.GetVpnGatewayByID(rs.Primary.ID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v.Id != rs.Primary.ID {
|
||||
return fmt.Errorf("VPN Gateway not found")
|
||||
}
|
||||
|
||||
*vpnGateway = *v
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckCloudStackVPNGatewayDestroy(s *terraform.State) error {
|
||||
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "cloudstack_vpn_gateway" {
|
||||
continue
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No VPN Gateway ID is set")
|
||||
}
|
||||
|
||||
p := cs.VPN.NewDeleteVpnGatewayParams(rs.Primary.ID)
|
||||
_, err := cs.VPN.DeleteVpnGateway(p)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error deleting VPN Gateway (%s): %s",
|
||||
rs.Primary.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccCloudStackVPNGateway_basic = fmt.Sprintf(`
|
||||
resource "cloudstack_vpc" "foo" {
|
||||
name = "terraform-vpc"
|
||||
display_text = "terraform-vpc-text"
|
||||
cidr = "%s"
|
||||
vpc_offering = "%s"
|
||||
zone = "%s"
|
||||
}
|
||||
|
||||
resource "cloudstack_vpn_gateway" "foo" {
|
||||
vpc = "${cloudstack_vpc.foo.name}"
|
||||
}`,
|
||||
CLOUDSTACK_VPC_CIDR_1,
|
||||
CLOUDSTACK_VPC_OFFERING,
|
||||
CLOUDSTACK_ZONE)
|
|
@ -40,8 +40,6 @@ func retrieveUUID(cs *cloudstack.CloudStackClient, name, value string) (uuid str
|
|||
uuid, err = cs.VPC.GetVPCOfferingID(value)
|
||||
case "vpc":
|
||||
uuid, err = cs.VPC.GetVPCID(value)
|
||||
case "template":
|
||||
uuid, err = cs.Template.GetTemplateID(value, "executable")
|
||||
case "network":
|
||||
uuid, err = cs.Network.GetNetworkID(value)
|
||||
case "zone":
|
||||
|
@ -71,6 +69,22 @@ func retrieveUUID(cs *cloudstack.CloudStackClient, name, value string) (uuid str
|
|||
return uuid, nil
|
||||
}
|
||||
|
||||
func retrieveTemplateUUID(cs *cloudstack.CloudStackClient, zoneid, value string) (uuid string, e *retrieveError) {
|
||||
// If the supplied value isn't a UUID, try to retrieve the UUID ourselves
|
||||
if isUUID(value) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Retrieving UUID of template: %s", value)
|
||||
|
||||
uuid, err := cs.Template.GetTemplateID(value, "executable", zoneid)
|
||||
if err != nil {
|
||||
return uuid, &retrieveError{name: "template", value: value, err: err}
|
||||
}
|
||||
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func isUUID(s string) bool {
|
||||
re := regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
|
||||
return re.MatchString(s)
|
||||
|
|
|
@ -21,6 +21,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"digitalocean_domain": resourceDigitalOceanDomain(),
|
||||
"digitalocean_droplet": resourceDigitalOceanDroplet(),
|
||||
"digitalocean_record": resourceDigitalOceanRecord(),
|
||||
"digitalocean_ssh_key": resourceDigitalOceanSSHKey(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
package digitalocean
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/pearkes/digitalocean"
|
||||
)
|
||||
|
||||
func resourceDigitalOceanSSHKey() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDigitalOceanSSHKeyCreate,
|
||||
Read: resourceDigitalOceanSSHKeyRead,
|
||||
Update: resourceDigitalOceanSSHKeyUpdate,
|
||||
Delete: resourceDigitalOceanSSHKeyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"public_key": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"fingerprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*digitalocean.Client)
|
||||
|
||||
// Build up our creation options
|
||||
opts := &digitalocean.CreateSSHKey{
|
||||
Name: d.Get("name").(string),
|
||||
PublicKey: d.Get("public_key").(string),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] SSH Key create configuration: %#v", opts)
|
||||
id, err := client.CreateSSHKey(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating SSH Key: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(id)
|
||||
log.Printf("[INFO] SSH Key: %s", id)
|
||||
|
||||
return resourceDigitalOceanSSHKeyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceDigitalOceanSSHKeyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*digitalocean.Client)
|
||||
|
||||
key, err := client.RetrieveSSHKey(d.Id())
|
||||
if err != nil {
|
||||
// If the key is somehow already destroyed, mark as
|
||||
// succesfully gone
|
||||
if strings.Contains(err.Error(), "404 Not Found") {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error retrieving SSH key: %s", err)
|
||||
}
|
||||
|
||||
d.Set("name", key.Name)
|
||||
d.Set("fingerprint", key.Fingerprint)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceDigitalOceanSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*digitalocean.Client)
|
||||
|
||||
var newName string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
newName = v.(string)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] SSH key update name: %#v", newName)
|
||||
err := client.RenameSSHKey(d.Id(), newName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update SSH key: %s", err)
|
||||
}
|
||||
|
||||
return resourceDigitalOceanSSHKeyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceDigitalOceanSSHKeyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*digitalocean.Client)
|
||||
|
||||
log.Printf("[INFO] Deleting SSH key: %s", d.Id())
|
||||
err := client.DestroySSHKey(d.Id())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting SSH key: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package digitalocean
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/pearkes/digitalocean"
|
||||
)
|
||||
|
||||
func TestAccDigitalOceanSSHKey_Basic(t *testing.T) {
|
||||
var key digitalocean.SSHKey
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDigitalOceanSSHKeyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckDigitalOceanSSHKeyConfig_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanSSHKeyExists("digitalocean_ssh_key.foobar", &key),
|
||||
testAccCheckDigitalOceanSSHKeyAttributes(&key),
|
||||
resource.TestCheckResourceAttr(
|
||||
"digitalocean_ssh_key.foobar", "name", "foobar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"digitalocean_ssh_key.foobar", "public_key", "abcdef"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDigitalOceanSSHKeyDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*digitalocean.Client)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "digitalocean_ssh_key" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to find the key
|
||||
_, err := client.RetrieveSSHKey(rs.Primary.ID)
|
||||
|
||||
if err == nil {
|
||||
fmt.Errorf("SSH key still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDigitalOceanSSHKeyAttributes(key *digitalocean.SSHKey) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if key.Name != "foobar" {
|
||||
return fmt.Errorf("Bad name: %s", key.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckDigitalOceanSSHKeyExists(n string, key *digitalocean.SSHKey) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Record ID is set")
|
||||
}
|
||||
|
||||
client := testAccProvider.Meta().(*digitalocean.Client)
|
||||
|
||||
foundKey, err := client.RetrieveSSHKey(rs.Primary.ID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if foundKey.Name != rs.Primary.ID {
|
||||
return fmt.Errorf("Record not found")
|
||||
}
|
||||
|
||||
*key = foundKey
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckDigitalOceanSSHKeyConfig_basic = `
|
||||
resource "digitalocean_ssh_key" "foobar" {
|
||||
name = "foobar"
|
||||
public_key = "abcdef"
|
||||
}`
|
|
@ -3,6 +3,7 @@ package schema
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
@ -24,6 +25,31 @@ type Resource struct {
|
|||
// resource.
|
||||
Schema map[string]*Schema
|
||||
|
||||
// SchemaVersion is the version number for this resource's Schema
|
||||
// definition. The current SchemaVersion stored in the state for each
|
||||
// resource. Provider authors can increment this version number
|
||||
// when Schema semantics change. If the State's SchemaVersion is less than
|
||||
// the current SchemaVersion, the InstanceState is yielded to the
|
||||
// MigrateState callback, where the provider can make whatever changes it
|
||||
// needs to update the state to be compatible to the latest version of the
|
||||
// Schema.
|
||||
//
|
||||
// When unset, SchemaVersion defaults to 0, so provider authors can start
|
||||
// their Versioning at any integer >= 1
|
||||
SchemaVersion int
|
||||
|
||||
// MigrateState is responsible for updating an InstanceState with an old
|
||||
// version to the format expected by the current version of the Schema.
|
||||
//
|
||||
// It is called during Refresh if the State's stored SchemaVersion is less
|
||||
// than the current SchemaVersion of the Resource.
|
||||
//
|
||||
// The function is yielded the state's stored SchemaVersion and a pointer to
|
||||
// the InstanceState that needs updating, as well as the configured
|
||||
// provider's configured meta interface{}, in case the migration process
|
||||
// needs to make any remote API calls.
|
||||
MigrateState StateMigrateFunc
|
||||
|
||||
// The functions below are the CRUD operations for this resource.
|
||||
//
|
||||
// The only optional operation is Update. If Update is not implemented,
|
||||
|
@ -69,6 +95,10 @@ type DeleteFunc func(*ResourceData, interface{}) error
|
|||
// See Resource documentation.
|
||||
type ExistsFunc func(*ResourceData, interface{}) (bool, error)
|
||||
|
||||
// See Resource documentation.
|
||||
type StateMigrateFunc func(
|
||||
int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error)
|
||||
|
||||
// Apply creates, updates, and/or deletes a resource.
|
||||
func (r *Resource) Apply(
|
||||
s *terraform.InstanceState,
|
||||
|
@ -158,6 +188,14 @@ func (r *Resource) Refresh(
|
|||
}
|
||||
}
|
||||
|
||||
needsMigration, stateSchemaVersion := r.checkSchemaVersion(s)
|
||||
if needsMigration && r.MigrateState != nil {
|
||||
s, err := r.MigrateState(stateSchemaVersion, s, meta)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
}
|
||||
|
||||
data, err := schemaMap(r.Schema).Data(s, nil)
|
||||
if err != nil {
|
||||
return s, err
|
||||
|
@ -169,6 +207,13 @@ func (r *Resource) Refresh(
|
|||
state = nil
|
||||
}
|
||||
|
||||
if state != nil && r.SchemaVersion > 0 {
|
||||
if state.Meta == nil {
|
||||
state.Meta = make(map[string]string)
|
||||
}
|
||||
state.Meta["schema_version"] = strconv.Itoa(r.SchemaVersion)
|
||||
}
|
||||
|
||||
return state, err
|
||||
}
|
||||
|
||||
|
@ -189,3 +234,10 @@ func (r *Resource) InternalValidate() error {
|
|||
|
||||
return schemaMap(r.Schema).InternalValidate()
|
||||
}
|
||||
|
||||
// Determines if a given InstanceState needs to be migrated by checking the
|
||||
// stored version number with the current SchemaVersion
|
||||
func (r *Resource) checkSchemaVersion(is *terraform.InstanceState) (bool, int) {
|
||||
stateSchemaVersion, _ := strconv.Atoi(is.Meta["schema_version"])
|
||||
return stateSchemaVersion < r.SchemaVersion, stateSchemaVersion
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package schema
|
|||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -478,3 +479,218 @@ func TestResourceRefresh_noExists(t *testing.T) {
|
|||
t.Fatalf("should have no state")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceRefresh_needsMigration(t *testing.T) {
|
||||
// Schema v2 it deals only in newfoo, which tracks foo as an int
|
||||
r := &Resource{
|
||||
SchemaVersion: 2,
|
||||
Schema: map[string]*Schema{
|
||||
"newfoo": &Schema{
|
||||
Type: TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
r.Read = func(d *ResourceData, m interface{}) error {
|
||||
return d.Set("newfoo", d.Get("newfoo").(int)+1)
|
||||
}
|
||||
|
||||
r.MigrateState = func(
|
||||
v int,
|
||||
s *terraform.InstanceState,
|
||||
meta interface{}) (*terraform.InstanceState, error) {
|
||||
// Real state migration functions will probably switch on this value,
|
||||
// but we'll just assert on it for now.
|
||||
if v != 1 {
|
||||
t.Fatalf("Expected StateSchemaVersion to be 1, got %d", v)
|
||||
}
|
||||
|
||||
if meta != 42 {
|
||||
t.Fatal("Expected meta to be passed through to the migration function")
|
||||
}
|
||||
|
||||
oldfoo, err := strconv.ParseFloat(s.Attributes["oldfoo"], 64)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %#v", err)
|
||||
}
|
||||
s.Attributes["newfoo"] = strconv.Itoa((int(oldfoo * 10)))
|
||||
delete(s.Attributes, "oldfoo")
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// State is v1 and deals in oldfoo, which tracked foo as a float at 1/10th
|
||||
// the scale of newfoo
|
||||
s := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"oldfoo": "1.2",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"schema_version": "1",
|
||||
},
|
||||
}
|
||||
|
||||
actual, err := r.Refresh(s, 42)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"id": "bar",
|
||||
"newfoo": "13",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"schema_version": "2",
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceRefresh_noMigrationNeeded(t *testing.T) {
|
||||
r := &Resource{
|
||||
SchemaVersion: 2,
|
||||
Schema: map[string]*Schema{
|
||||
"newfoo": &Schema{
|
||||
Type: TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
r.Read = func(d *ResourceData, m interface{}) error {
|
||||
return d.Set("newfoo", d.Get("newfoo").(int)+1)
|
||||
}
|
||||
|
||||
r.MigrateState = func(
|
||||
v int,
|
||||
s *terraform.InstanceState,
|
||||
meta interface{}) (*terraform.InstanceState, error) {
|
||||
t.Fatal("Migrate function shouldn't be called!")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
s := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"newfoo": "12",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"schema_version": "2",
|
||||
},
|
||||
}
|
||||
|
||||
actual, err := r.Refresh(s, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"id": "bar",
|
||||
"newfoo": "13",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"schema_version": "2",
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceRefresh_stateSchemaVersionUnset(t *testing.T) {
|
||||
r := &Resource{
|
||||
// Version 1 > Version 0
|
||||
SchemaVersion: 1,
|
||||
Schema: map[string]*Schema{
|
||||
"newfoo": &Schema{
|
||||
Type: TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
r.Read = func(d *ResourceData, m interface{}) error {
|
||||
return d.Set("newfoo", d.Get("newfoo").(int)+1)
|
||||
}
|
||||
|
||||
r.MigrateState = func(
|
||||
v int,
|
||||
s *terraform.InstanceState,
|
||||
meta interface{}) (*terraform.InstanceState, error) {
|
||||
s.Attributes["newfoo"] = s.Attributes["oldfoo"]
|
||||
return s, nil
|
||||
}
|
||||
|
||||
s := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"oldfoo": "12",
|
||||
},
|
||||
}
|
||||
|
||||
actual, err := r.Refresh(s, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"id": "bar",
|
||||
"newfoo": "13",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"schema_version": "1",
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad:\n\nexpected: %#v\ngot: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceRefresh_migrateStateErr(t *testing.T) {
|
||||
r := &Resource{
|
||||
SchemaVersion: 2,
|
||||
Schema: map[string]*Schema{
|
||||
"newfoo": &Schema{
|
||||
Type: TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
r.Read = func(d *ResourceData, m interface{}) error {
|
||||
t.Fatal("Read should never be called!")
|
||||
return nil
|
||||
}
|
||||
|
||||
r.MigrateState = func(
|
||||
v int,
|
||||
s *terraform.InstanceState,
|
||||
meta interface{}) (*terraform.InstanceState, error) {
|
||||
return s, fmt.Errorf("triggering an error")
|
||||
}
|
||||
|
||||
s := &terraform.InstanceState{
|
||||
ID: "bar",
|
||||
Attributes: map[string]string{
|
||||
"oldfoo": "12",
|
||||
},
|
||||
}
|
||||
|
||||
_, err := r.Refresh(s, nil)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, but got none!")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// RemoteCmd represents a remote command being prepared or run.
|
||||
|
|
|
@ -4,7 +4,7 @@ package ssh
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ssh
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"log"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ssh
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
|
|
@ -19,9 +19,11 @@ GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true)
|
|||
XC_ARCH=${XC_ARCH:-"386 amd64 arm"}
|
||||
XC_OS=${XC_OS:-linux darwin windows freebsd openbsd}
|
||||
|
||||
# Install dependencies
|
||||
echo "==> Getting dependencies..."
|
||||
go get ./...
|
||||
# Install dependencies unless running in quick mode
|
||||
if [ "${TF_QUICKDEV}x" == "x" ]; then
|
||||
echo "==> Getting dependencies..."
|
||||
go get ./...
|
||||
fi
|
||||
|
||||
# Delete the old dir
|
||||
echo "==> Removing old directory..."
|
||||
|
|
|
@ -832,6 +832,11 @@ type InstanceState struct {
|
|||
// that is necessary for the Terraform run to complete, but is not
|
||||
// persisted to a state file.
|
||||
Ephemeral EphemeralState `json:"-"`
|
||||
|
||||
// Meta is a simple K/V map that is persisted to the State but otherwise
|
||||
// ignored by Terraform core. It's meant to be used for accounting by
|
||||
// external client code.
|
||||
Meta map[string]string `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
func (i *InstanceState) init() {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'middleman-hashicorp', github: 'hashicorp/middleman-hashicorp'
|
||||
gem 'middleman-hashicorp', git: 'https://github.com/hashicorp/middleman-hashicorp'
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
GIT
|
||||
remote: git://github.com/hashicorp/middleman-hashicorp.git
|
||||
revision: 30c15f93fb501041cff97c490b60ddc96c8314c9
|
||||
remote: https://github.com/hashicorp/middleman-hashicorp
|
||||
revision: 783fe9517dd02badb85e5ddfeda4d8e35bbd05a8
|
||||
specs:
|
||||
middleman-hashicorp (0.1.0)
|
||||
bootstrap-sass (~> 3.2)
|
||||
bootstrap-sass (~> 3.3)
|
||||
builder (~> 3.2)
|
||||
less (~> 2.6)
|
||||
middleman (~> 3.3)
|
||||
middleman-livereload (~> 3.3)
|
||||
middleman-livereload (~> 3.4)
|
||||
middleman-minify-html (~> 3.4)
|
||||
middleman-syntax (~> 2.0)
|
||||
rack-contrib (~> 1.1)
|
||||
rack-contrib (~> 1.2)
|
||||
rack-rewrite (~> 1.5)
|
||||
rack-ssl-enforcer (~> 0.2)
|
||||
redcarpet (~> 3.1)
|
||||
redcarpet (~> 3.2)
|
||||
therubyracer (~> 0.12)
|
||||
thin (~> 1.6)
|
||||
|
||||
|
@ -26,7 +26,7 @@ GEM
|
|||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
autoprefixer-rails (5.0.0.2)
|
||||
autoprefixer-rails (5.1.7)
|
||||
execjs
|
||||
json
|
||||
bootstrap-sass (3.3.3)
|
||||
|
@ -35,11 +35,11 @@ GEM
|
|||
builder (3.2.2)
|
||||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
chunky_png (1.3.3)
|
||||
chunky_png (1.3.4)
|
||||
coffee-script (2.3.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.8.0)
|
||||
coffee-script-source (1.9.1)
|
||||
commonjs (0.2.7)
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
|
@ -58,8 +58,8 @@ GEM
|
|||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.4)
|
||||
execjs (2.2.2)
|
||||
eventmachine (1.0.7)
|
||||
execjs (2.4.0)
|
||||
ffi (1.9.6)
|
||||
haml (4.0.6)
|
||||
tilt
|
||||
|
@ -69,9 +69,9 @@ GEM
|
|||
uber (~> 0.0.4)
|
||||
htmlcompressor (0.1.2)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.6.11)
|
||||
i18n (0.7.0)
|
||||
json (1.8.2)
|
||||
kramdown (1.5.0)
|
||||
kramdown (1.6.0)
|
||||
less (2.6.0)
|
||||
commonjs (~> 0.2.7)
|
||||
libv8 (3.16.14.7)
|
||||
|
@ -79,23 +79,23 @@ GEM
|
|||
celluloid (>= 0.15.2)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
middleman (3.3.7)
|
||||
middleman (3.3.10)
|
||||
coffee-script (~> 2.2)
|
||||
compass (>= 1.0.0, < 2.0.0)
|
||||
compass-import-once (= 1.0.5)
|
||||
execjs (~> 2.0)
|
||||
haml (>= 4.0.5)
|
||||
kramdown (~> 1.2)
|
||||
middleman-core (= 3.3.7)
|
||||
middleman-core (= 3.3.10)
|
||||
middleman-sprockets (>= 3.1.2)
|
||||
sass (>= 3.4.0, < 4.0)
|
||||
uglifier (~> 2.5)
|
||||
middleman-core (3.3.7)
|
||||
middleman-core (3.3.10)
|
||||
activesupport (~> 4.1.0)
|
||||
bundler (~> 1.1)
|
||||
erubis
|
||||
hooks (~> 0.3)
|
||||
i18n (~> 0.6.9)
|
||||
i18n (~> 0.7.0)
|
||||
listen (>= 2.7.9, < 3.0)
|
||||
padrino-helpers (~> 0.12.3)
|
||||
rack (>= 1.4.5, < 2.0)
|
||||
|
@ -109,7 +109,7 @@ GEM
|
|||
middleman-minify-html (3.4.0)
|
||||
htmlcompressor (~> 0.1.0)
|
||||
middleman-core (>= 3.2)
|
||||
middleman-sprockets (3.4.1)
|
||||
middleman-sprockets (3.4.2)
|
||||
middleman-core (>= 3.3)
|
||||
sprockets (~> 2.12.1)
|
||||
sprockets-helpers (~> 1.1.0)
|
||||
|
@ -118,12 +118,12 @@ GEM
|
|||
middleman-core (~> 3.2)
|
||||
rouge (~> 1.0)
|
||||
minitest (5.5.1)
|
||||
multi_json (1.10.1)
|
||||
padrino-helpers (0.12.4)
|
||||
multi_json (1.11.0)
|
||||
padrino-helpers (0.12.5)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
padrino-support (= 0.12.4)
|
||||
padrino-support (= 0.12.5)
|
||||
tilt (~> 1.4.1)
|
||||
padrino-support (0.12.4)
|
||||
padrino-support (0.12.5)
|
||||
activesupport (>= 3.1)
|
||||
rack (1.6.0)
|
||||
rack-contrib (1.2.0)
|
||||
|
@ -139,8 +139,8 @@ GEM
|
|||
ffi (>= 0.5.0)
|
||||
redcarpet (3.2.2)
|
||||
ref (1.0.5)
|
||||
rouge (1.7.7)
|
||||
sass (3.4.10)
|
||||
rouge (1.8.0)
|
||||
sass (3.4.13)
|
||||
sprockets (2.12.3)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
|
@ -166,7 +166,7 @@ GEM
|
|||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.0.13)
|
||||
uglifier (2.7.0)
|
||||
uglifier (2.7.1)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ Terraform will automatically fetch the latest state from the remote
|
|||
server when necessary and if any updates are made, the newest state
|
||||
is persisted back to the remote server.
|
||||
In this mode, users do not need to durably store the state using version
|
||||
control or shared storaged.
|
||||
control or shared storage.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ The following arguments are supported:
|
|||
Only used for [DB Instances on the _EC2-Classic_ Platform](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html#USER_VPC.FindDefaultVPC).
|
||||
* `db_subnet_group_name` - (Optional) Name of DB subnet group
|
||||
* `parameter_group_name` - (Optional) Name of the DB parameter group to associate.
|
||||
* `storage_encrypted` - (Optional) Specifies whether the DB instance is encrypted. The Default is `false` if not specified.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
|
@ -82,4 +83,5 @@ The following attributes are exported:
|
|||
* `port` - The database port
|
||||
* `status` - The RDS instance status
|
||||
* `username` - The master username for the database
|
||||
* `storage_encrypted` - Specifies whether the DB instance is encrypted
|
||||
|
||||
|
|
|
@ -29,6 +29,18 @@ The following arguments are supported:
|
|||
* `vpc_id` - (Required) The VPC ID to create in.
|
||||
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||
|
||||
-> **Note:** It's recommended to denote that the AWS Instance or Elastic IP depends on the Internet Gateway. For example:
|
||||
|
||||
|
||||
resource "aws_internet_gateway" "gw" {
|
||||
vpc_id = "${aws_vpc.main.id}"
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo" {
|
||||
depends_on = ["aws_internet_gateway.gw"]
|
||||
}
|
||||
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
|
|
@ -56,4 +56,4 @@ The following attributes are exported:
|
|||
|
||||
|
||||
## Notes
|
||||
You still have to accept the peering with the aws console, aws-cli or goamz
|
||||
You still have to accept the peering with the aws console, aws-cli or aws-sdk-go.
|
||||
|
|
|
@ -58,4 +58,4 @@ The `rule` block supports:
|
|||
|
||||
The following attributes are exported:
|
||||
|
||||
* `ID` - The network ID for which the egress firewall rules are created.
|
||||
* `id` - The network ID for which the egress firewall rules are created.
|
||||
|
|
|
@ -58,4 +58,4 @@ The `rule` block supports:
|
|||
|
||||
The following attributes are exported:
|
||||
|
||||
* `ID` - The IP address ID for which the firewall rules are created.
|
||||
* `id` - The IP address ID for which the firewall rules are created.
|
||||
|
|
|
@ -66,4 +66,4 @@ The `rule` block supports:
|
|||
|
||||
The following attributes are exported:
|
||||
|
||||
* `ID` - The ACL ID for which the rules are created.
|
||||
* `id` - The ACL ID for which the rules are created.
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
layout: "cloudstack"
|
||||
page_title: "CloudStack: cloudstack_vpn_connection"
|
||||
sidebar_current: "docs-cloudstack-resource-vpn-connection"
|
||||
description: |-
|
||||
Creates a site to site VPN connection.
|
||||
---
|
||||
|
||||
# cloudstack\_vpn\_connection
|
||||
|
||||
Creates a site to site VPN connection.
|
||||
|
||||
## Example Usage
|
||||
|
||||
Basic usage:
|
||||
|
||||
```
|
||||
resource "cloudstack_vpn_connection" "default" {
|
||||
customergatewayid = "xxx"
|
||||
vpngatewayid = "xxx"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `customergatewayid` - (Required) The Customer Gateway ID to connect.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
* `vpngatewayid` - (Required) The VPN Gateway ID to connect.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the VPN Connection.
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
layout: "cloudstack"
|
||||
page_title: "CloudStack: cloudstack_vpn_customer_gateway"
|
||||
sidebar_current: "docs-cloudstack-resource-vpn-customer-gateway"
|
||||
description: |-
|
||||
Creates a site to site VPN local customer gateway.
|
||||
---
|
||||
|
||||
# cloudstack\_vpn\_customer\_gateway
|
||||
|
||||
Creates a site to site VPN local customer gateway.
|
||||
|
||||
## Example Usage
|
||||
|
||||
Basic usage:
|
||||
|
||||
```
|
||||
resource "cloudstack_vpn_customer_gateway" "default" {
|
||||
name = "test-vpc"
|
||||
cidr = "10.0.0.0/8"
|
||||
esp_policy = "aes256-sha1"
|
||||
gateway = "192.168.0.1"
|
||||
ike_policy = "aes256-sha1"
|
||||
ipsec_psk = "terraform"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the VPN Customer Gateway.
|
||||
|
||||
* `cidr` - (Required) The CIDR block that needs to be routed through this gateway.
|
||||
|
||||
* `esp_policy` - (Required) The ESP policy to use for this VPN Customer Gateway.
|
||||
|
||||
* `gateway` - (Required) The public IP address of the related VPN Gateway.
|
||||
|
||||
* `ike_policy` - (Required) The IKE policy to use for this VPN Customer Gateway.
|
||||
|
||||
* `ipsec_psk` - (Required) The IPSEC pre-shared key used for this gateway.
|
||||
|
||||
* `dpd` - (Optional) If DPD is enabled for the related VPN connection (defaults false)
|
||||
|
||||
* `esp_lifetime` - (Optional) The ESP lifetime of phase 2 VPN connection to this
|
||||
VPN Customer Gateway in seconds (defaults 86400)
|
||||
|
||||
* `ike_lifetime` - (Optional) The IKE lifetime of phase 2 VPN connection to this
|
||||
VPN Customer Gateway in seconds (defaults 86400)
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the VPN Customer Gateway.
|
||||
* `dpd` - Enable or disable DPD is enabled for the related VPN connection.
|
||||
* `esp_lifetime` - The ESP lifetime of phase 2 VPN connection to this VPN Customer Gateway.
|
||||
* `ike_lifetime` - The IKE lifetime of phase 2 VPN connection to this VPN Customer Gateway.
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
layout: "cloudstack"
|
||||
page_title: "CloudStack: cloudstack_vpn_gateway"
|
||||
sidebar_current: "docs-cloudstack-resource-vpn-gateway"
|
||||
description: |-
|
||||
Creates a site to site VPN local gateway.
|
||||
---
|
||||
|
||||
# cloudstack\_vpn\_gateway
|
||||
|
||||
Creates a site to site VPN local gateway.
|
||||
|
||||
## Example Usage
|
||||
|
||||
Basic usage:
|
||||
|
||||
```
|
||||
resource "cloudstack_vpn_gateway" "default" {
|
||||
vpc = "test-vpc"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `vpc` - (Required) The name of the VPC for which to create the VPN Gateway.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the VPN Gateway.
|
||||
* `public_ip` - The public IP address associated with the VPN Gateway.
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
layout: "digitalocean"
|
||||
page_title: "DigitalOcean: digitalocean_ssh_key"
|
||||
sidebar_current: "docs-do-resource-ssh-key"
|
||||
description: |-
|
||||
Provides a DigitalOcean SSH key resource.
|
||||
---
|
||||
|
||||
# digitalocean\_ssh_key
|
||||
|
||||
Provides a DigitalOcean SSH key resource to allow you manage SSH
|
||||
keys for Droplet access. Keys created with this resource
|
||||
can be referenced in your droplet configuration via their ID or
|
||||
fingerprint.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Create a new SSH key
|
||||
resource "digitalocean_ssh_key" "default" {
|
||||
name = "Terraform Example"
|
||||
public_key = "${file("/Users/terraform/.ssh/id_rsa.pub")}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the SSH key for identification
|
||||
* `public_key` - (Required) The public key. If this is a file, it
|
||||
can be read using the file interpolation function
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The unique ID of the key
|
||||
* `name` - The name of the SSH key
|
||||
* `public_key` - The text of the public key
|
||||
* `fingerprint` - The fingerprint of the SSH key
|
|
@ -56,6 +56,18 @@
|
|||
<li<%= sidebar_current("docs-cloudstack-resource-vpc") %>>
|
||||
<a href="/docs/providers/cloudstack/r/vpc.html">cloudstack_vpc</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-cloudstack-resource-vpn-gateway") %>>
|
||||
<a href="/docs/providers/cloudstack/r/vpn_gateway.html">cloudstack_vpn_gateway</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-cloudstack-resource-vpn-customer-gateway") %>>
|
||||
<a href="/docs/providers/cloudstack/r/vpn_customer_gateway.html">cloudstack_vpn_customer_gateway</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-cloudstack-resource-vpn-connection") %>>
|
||||
<a href="/docs/providers/cloudstack/r/vpn_connection.html">cloudstack_vpn_connection</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -63,4 +75,4 @@
|
|||
<% end %>
|
||||
|
||||
<%= yield %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
|
||||
<li<%= sidebar_current("docs-do-resource-record") %>>
|
||||
<a href="/docs/providers/do/r/record.html">digitalocean_record</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-do-resource-ssh-key") %>>
|
||||
<a href="/docs/providers/do/r/ssh_key.html">digitalocean_ssh_key</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue