Add top-level ELB Attachment resource
Add an aws_elb_attachment resource so that the attment of instances to an ELB can be managed separately from an aws_elb and prevent dependency cycles.
This commit is contained in:
parent
f891ab81f4
commit
e4d8c6929f
|
@ -176,6 +176,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_elastic_beanstalk_environment": resourceAwsElasticBeanstalkEnvironment(),
|
||||
"aws_elasticsearch_domain": resourceAwsElasticSearchDomain(),
|
||||
"aws_elb": resourceAwsElb(),
|
||||
"aws_elb_attachment": resourceAwsElbAttachment(),
|
||||
"aws_flow_log": resourceAwsFlowLog(),
|
||||
"aws_glacier_vault": resourceAwsGlacierVault(),
|
||||
"aws_iam_access_key": resourceAwsIamAccessKey(),
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/elb"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsElbAttachment() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsElbAttachmentCreate,
|
||||
Read: resourceAwsElbAttachmentRead,
|
||||
Delete: resourceAwsElbAttachmentDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"elb": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"instance": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsElbAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
elbconn := meta.(*AWSClient).elbconn
|
||||
elbName := d.Get("elb").(string)
|
||||
|
||||
instance := d.Get("instance").(string)
|
||||
|
||||
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancerInput{
|
||||
LoadBalancerName: aws.String(elbName),
|
||||
Instances: []*elb.Instance{{InstanceId: aws.String(instance)}},
|
||||
}
|
||||
|
||||
log.Printf("[INFO] registering instance %s with ELB %s", instance, elbName)
|
||||
|
||||
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failure registering instances with ELB: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", elbName)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsElbAttachmentRead(d *schema.ResourceData, meta interface{}) error {
|
||||
elbconn := meta.(*AWSClient).elbconn
|
||||
elbName := d.Get("elb").(string)
|
||||
|
||||
// only add the instance that was previously defined for this resource
|
||||
expected := d.Get("instance").(string)
|
||||
|
||||
// Retrieve the ELB properties to get a list of attachments
|
||||
describeElbOpts := &elb.DescribeLoadBalancersInput{
|
||||
LoadBalancerNames: []*string{aws.String(elbName)},
|
||||
}
|
||||
|
||||
resp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
|
||||
if err != nil {
|
||||
if isLoadBalancerNotFound(err) {
|
||||
log.Printf("[ERROR] ELB %s not found", elbName)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error retrieving ELB: %s", err)
|
||||
}
|
||||
if len(resp.LoadBalancerDescriptions) != 1 {
|
||||
log.Printf("[ERROR] Unable to find ELB: %s", resp.LoadBalancerDescriptions)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// only set the instance Id that this resource manages
|
||||
found := false
|
||||
for _, i := range resp.LoadBalancerDescriptions[0].Instances {
|
||||
if expected == *i.InstanceId {
|
||||
d.Set("instance", expected)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
log.Printf("[WARN] instance %s not found in elb attachments", expected)
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsElbAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
elbconn := meta.(*AWSClient).elbconn
|
||||
elbName := d.Get("elb").(string)
|
||||
|
||||
instance := d.Get("instance").(string)
|
||||
|
||||
log.Printf("[INFO] Deleting Attachment %s from: %s", instance, elbName)
|
||||
|
||||
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancerInput{
|
||||
LoadBalancerName: aws.String(elbName),
|
||||
Instances: []*elb.Instance{{InstanceId: aws.String(instance)}},
|
||||
}
|
||||
|
||||
_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failure deregistering instances from ELB: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/elb"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSELBAttachment_basic(t *testing.T) {
|
||||
var conf elb.LoadBalancerDescription
|
||||
|
||||
testCheckInstanceAttached := func(count int) resource.TestCheckFunc {
|
||||
return func(*terraform.State) error {
|
||||
if len(conf.Instances) != count {
|
||||
return fmt.Errorf("instance count does not match")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_elb.bar",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSELBDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig1,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(1),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig2,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(2),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig3,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(2),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig4,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(0),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// remove and instance and check that it's correctly re-attached.
|
||||
func TestAccAWSELBAttachment_drift(t *testing.T) {
|
||||
var conf elb.LoadBalancerDescription
|
||||
|
||||
deregInstance := func() {
|
||||
conn := testAccProvider.Meta().(*AWSClient).elbconn
|
||||
|
||||
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancerInput{
|
||||
LoadBalancerName: conf.LoadBalancerName,
|
||||
Instances: conf.Instances,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] deregistering instance %s from ELB", conf.Instances[0].InstanceId)
|
||||
|
||||
_, err := conn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
||||
if err != nil {
|
||||
t.Fatalf("Failure deregistering instances from ELB: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
testCheckInstanceAttached := func(count int) resource.TestCheckFunc {
|
||||
return func(*terraform.State) error {
|
||||
if len(conf.Instances) != count {
|
||||
return fmt.Errorf("instance count does not match")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_elb.bar",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSELBDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig1,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(1),
|
||||
),
|
||||
},
|
||||
|
||||
// remove an instance from the ELB, and make sure it gets re-added
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAttachmentConfig1,
|
||||
PreConfig: deregInstance,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testCheckInstanceAttached(1),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// add one attachment
|
||||
const testAccAWSELBAttachmentConfig1 = `
|
||||
resource "aws_elb" "bar" {
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo1" {
|
||||
# us-west-2
|
||||
ami = "ami-043a5034"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "foo1" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = "${aws_instance.foo1.id}"
|
||||
}
|
||||
`
|
||||
|
||||
// add a second attachment
|
||||
const testAccAWSELBAttachmentConfig2 = `
|
||||
resource "aws_elb" "bar" {
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo1" {
|
||||
# us-west-2
|
||||
ami = "ami-043a5034"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo2" {
|
||||
# us-west-2
|
||||
ami = "ami-043a5034"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "foo1" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = "${aws_instance.foo1.id}"
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "foo2" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = "${aws_instance.foo2.id}"
|
||||
}
|
||||
`
|
||||
|
||||
// swap attachments between resources
|
||||
const testAccAWSELBAttachmentConfig3 = `
|
||||
resource "aws_elb" "bar" {
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo1" {
|
||||
# us-west-2
|
||||
ami = "ami-043a5034"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo2" {
|
||||
# us-west-2
|
||||
ami = "ami-043a5034"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "foo1" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = "${aws_instance.foo2.id}"
|
||||
}
|
||||
|
||||
resource "aws_elb_attachment" "foo2" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = "${aws_instance.foo1.id}"
|
||||
}
|
||||
`
|
||||
|
||||
// destroy attachments
|
||||
const testAccAWSELBAttachmentConfig4 = `
|
||||
resource "aws_elb" "bar" {
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
}
|
||||
`
|
|
@ -10,6 +10,12 @@ description: |-
|
|||
|
||||
Provides an Elastic Load Balancer resource.
|
||||
|
||||
~> **NOTE on ELB Instances and ELB Attachments:** Terraform currently
|
||||
provides both a standalone [ELB Attachment resource](elb_attachment.html)
|
||||
(describing an instance attached to an ELB), and an ELB resource with
|
||||
`instances` defined in-line. At this time you cannot use an ELB with in-line
|
||||
instaces in conjunction with a ELB Attachment resources. Doing so will cause a
|
||||
conflict and will overwrite attachments.
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_elb_attachment"
|
||||
sidebar_current: "docs-aws-resource-elb-attachment"
|
||||
description: |-
|
||||
Provides an Elastic Load Balancer Attachment resource.
|
||||
---
|
||||
|
||||
# aws\_elb\_attachment
|
||||
|
||||
Provides an Elastic Load Balancer Attachment resource.
|
||||
|
||||
~> **NOTE on ELB Instances and ELB Attachments:** Terraform currently provides
|
||||
both a standalone ELB Attachment resource (describing an instance attached to
|
||||
an ELB), and an [Elastic Load Balancer resource](elb.html) with
|
||||
`instances` defined in-line. At this time you cannot use an ELB with in-line
|
||||
instaces in conjunction with an ELB Attachment resource. Doing so will cause a
|
||||
conflict and will overwrite attachments.
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Create a new load balancer attachment
|
||||
resource "aws_elb_attachment" "baz" {
|
||||
elb = "${aws_elb.bar.id}"
|
||||
instance = ["${aws_instance.foo.id}"]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `elb` - (Required) The name of the ELB.
|
||||
* `instance` - (Required) Instance ID to place in the ELB pool.
|
Loading…
Reference in New Issue