2014-06-27 18:47:19 +02:00
|
|
|
package aws
|
|
|
|
|
|
|
|
import (
|
2014-10-10 08:58:48 +02:00
|
|
|
"bytes"
|
2014-06-27 18:47:19 +02:00
|
|
|
"fmt"
|
|
|
|
"log"
|
2015-06-25 12:00:15 +02:00
|
|
|
"regexp"
|
2015-06-05 17:12:32 +02:00
|
|
|
"strings"
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2015-06-03 20:36:57 +02:00
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
|
|
"github.com/aws/aws-sdk-go/service/elb"
|
2014-10-10 08:58:48 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/hashcode"
|
2015-06-30 14:01:07 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/resource"
|
2014-10-10 08:58:48 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
2014-06-27 18:47:19 +02:00
|
|
|
)
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
func resourceAwsElb() *schema.Resource {
|
|
|
|
return &schema.Resource{
|
|
|
|
Create: resourceAwsElbCreate,
|
|
|
|
Read: resourceAwsElbRead,
|
|
|
|
Update: resourceAwsElbUpdate,
|
|
|
|
Delete: resourceAwsElbDelete,
|
|
|
|
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"name": &schema.Schema{
|
2015-09-21 23:00:51 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
ForceNew: true,
|
|
|
|
ValidateFunc: validateElbName,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"internal": &schema.Schema{
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
2014-10-10 09:17:35 +02:00
|
|
|
Computed: true,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-12-10 07:07:08 +01:00
|
|
|
"cross_zone_load_balancing": &schema.Schema{
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"availability_zones": &schema.Schema{
|
2014-12-16 13:13:59 +01:00
|
|
|
Type: schema.TypeSet,
|
2014-10-10 08:58:48 +02:00
|
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
2014-12-25 23:12:54 +01:00
|
|
|
Computed: true,
|
2015-04-09 15:38:16 +02:00
|
|
|
Set: schema.HashString,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-07-03 00:55:28 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"instances": &schema.Schema{
|
|
|
|
Type: schema.TypeSet,
|
|
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
|
|
Optional: true,
|
2014-10-17 03:24:58 +02:00
|
|
|
Computed: true,
|
2015-04-09 15:38:16 +02:00
|
|
|
Set: schema.HashString,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"security_groups": &schema.Schema{
|
2014-12-17 23:53:01 +01:00
|
|
|
Type: schema.TypeSet,
|
2014-10-10 08:58:48 +02:00
|
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
|
|
Optional: true,
|
2014-10-10 09:17:35 +02:00
|
|
|
Computed: true,
|
2015-04-09 15:38:16 +02:00
|
|
|
Set: schema.HashString,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-07-28 03:20:03 +02:00
|
|
|
|
2015-04-28 16:40:19 +02:00
|
|
|
"source_security_group": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"subnets": &schema.Schema{
|
2014-10-20 22:34:14 +02:00
|
|
|
Type: schema.TypeSet,
|
2014-10-10 08:58:48 +02:00
|
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
|
|
Optional: true,
|
2015-02-19 01:15:04 +01:00
|
|
|
ForceNew: true,
|
2014-10-10 09:17:35 +02:00
|
|
|
Computed: true,
|
2015-04-09 15:38:16 +02:00
|
|
|
Set: schema.HashString,
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-09-17 23:56:27 +02:00
|
|
|
|
2015-04-13 22:14:26 +02:00
|
|
|
"idle_timeout": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
2015-04-23 11:46:52 +02:00
|
|
|
Default: 60,
|
2015-04-13 22:14:26 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
"connection_draining": &schema.Schema{
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
Default: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
"connection_draining_timeout": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
Default: 300,
|
|
|
|
},
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"listener": &schema.Schema{
|
|
|
|
Type: schema.TypeSet,
|
|
|
|
Required: true,
|
|
|
|
Elem: &schema.Resource{
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"instance_port": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"instance_protocol": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"lb_port": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"lb_protocol": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"ssl_certificate_id": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Set: resourceAwsElbListenerHash,
|
|
|
|
},
|
2014-08-08 02:14:48 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
"health_check": &schema.Schema{
|
|
|
|
Type: schema.TypeSet,
|
|
|
|
Optional: true,
|
2014-10-10 09:17:35 +02:00
|
|
|
Computed: true,
|
2014-10-10 08:58:48 +02:00
|
|
|
Elem: &schema.Resource{
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"healthy_threshold": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"unhealthy_threshold": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"target": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"interval": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"timeout": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Set: resourceAwsElbHealthCheckHash,
|
|
|
|
},
|
|
|
|
|
|
|
|
"dns_name": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
2015-03-24 19:37:42 +01:00
|
|
|
|
2015-04-30 23:58:09 +02:00
|
|
|
"zone_id": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
|
2015-03-24 19:37:42 +01:00
|
|
|
"tags": tagsSchema(),
|
2014-10-10 08:58:48 +02:00
|
|
|
},
|
2014-08-08 02:14:48 +02:00
|
|
|
}
|
2014-10-10 08:58:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
|
2014-11-21 17:58:34 +01:00
|
|
|
elbconn := meta.(*AWSClient).elbconn
|
2014-07-01 20:56:04 +02:00
|
|
|
|
2015-04-14 23:41:36 +02:00
|
|
|
// Expand the "listener" set to aws-sdk-go compat []*elb.Listener
|
2015-04-16 22:28:18 +02:00
|
|
|
listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
|
2014-07-01 20:56:04 +02:00
|
|
|
if err != nil {
|
2014-10-10 08:58:48 +02:00
|
|
|
return err
|
2014-07-01 20:56:04 +02:00
|
|
|
}
|
|
|
|
|
2015-06-30 14:01:07 +02:00
|
|
|
var elbName string
|
|
|
|
if v, ok := d.GetOk("name"); ok {
|
|
|
|
elbName = v.(string)
|
|
|
|
} else {
|
|
|
|
elbName = resource.PrefixedUniqueId("tf-lb-")
|
|
|
|
d.Set("name", elbName)
|
|
|
|
}
|
|
|
|
|
2015-03-24 19:37:42 +01:00
|
|
|
tags := tagsFromMapELB(d.Get("tags").(map[string]interface{}))
|
2014-10-10 08:58:48 +02:00
|
|
|
// Provision the elb
|
2015-04-14 23:41:36 +02:00
|
|
|
elbOpts := &elb.CreateLoadBalancerInput{
|
2015-06-30 14:01:07 +02:00
|
|
|
LoadBalancerName: aws.String(elbName),
|
2014-10-10 08:58:48 +02:00
|
|
|
Listeners: listeners,
|
2015-03-24 19:37:42 +01:00
|
|
|
Tags: tags,
|
2015-03-02 16:44:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) {
|
|
|
|
elbOpts.Scheme = aws.String("internal")
|
2014-10-10 08:58:48 +02:00
|
|
|
}
|
2014-07-01 20:56:04 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
if v, ok := d.GetOk("availability_zones"); ok {
|
2015-04-16 22:28:18 +02:00
|
|
|
elbOpts.AvailabilityZones = expandStringList(v.(*schema.Set).List())
|
2014-10-10 08:58:48 +02:00
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
if v, ok := d.GetOk("security_groups"); ok {
|
2015-04-16 22:28:18 +02:00
|
|
|
elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List())
|
2014-10-10 08:58:48 +02:00
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
if v, ok := d.GetOk("subnets"); ok {
|
2015-04-16 22:28:18 +02:00
|
|
|
elbOpts.Subnets = expandStringList(v.(*schema.Set).List())
|
2014-10-10 08:58:48 +02:00
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
|
|
|
|
if _, err := elbconn.CreateLoadBalancer(elbOpts); err != nil {
|
|
|
|
return fmt.Errorf("Error creating ELB: %s", err)
|
2014-07-05 01:03:01 +02:00
|
|
|
}
|
2014-07-30 16:15:22 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
// Assign the elb's unique identifier for use later
|
2015-06-30 14:01:07 +02:00
|
|
|
d.SetId(elbName)
|
2014-10-10 08:58:48 +02:00
|
|
|
log.Printf("[INFO] ELB ID: %s", d.Id())
|
|
|
|
|
|
|
|
// Enable partial mode and record what we set
|
|
|
|
d.Partial(true)
|
|
|
|
d.SetPartial("name")
|
|
|
|
d.SetPartial("internal")
|
|
|
|
d.SetPartial("availability_zones")
|
2014-10-17 03:02:03 +02:00
|
|
|
d.SetPartial("listener")
|
2014-10-10 08:58:48 +02:00
|
|
|
d.SetPartial("security_groups")
|
|
|
|
d.SetPartial("subnets")
|
|
|
|
|
2015-03-24 19:37:42 +01:00
|
|
|
d.Set("tags", tagsToMapELB(tags))
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
return resourceAwsElbUpdate(d, meta)
|
2014-06-27 18:47:19 +02:00
|
|
|
}
|
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
elbconn := meta.(*AWSClient).elbconn
|
2015-04-13 22:14:26 +02:00
|
|
|
elbName := d.Id()
|
2014-11-21 17:58:34 +01:00
|
|
|
|
|
|
|
// Retrieve the ELB properties for updating the state
|
2015-04-14 23:41:36 +02:00
|
|
|
describeElbOpts := &elb.DescribeLoadBalancersInput{
|
2015-04-22 08:38:19 +02:00
|
|
|
LoadBalancerNames: []*string{aws.String(elbName)},
|
2014-11-21 17:58:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
|
|
|
|
if err != nil {
|
2015-04-29 18:31:23 +02:00
|
|
|
if isLoadBalancerNotFound(err) {
|
2014-11-21 17:58:34 +01:00
|
|
|
// The ELB is gone now, so just remove it from the state
|
|
|
|
d.SetId("")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Error retrieving ELB: %s", err)
|
|
|
|
}
|
2015-03-02 16:44:06 +01:00
|
|
|
if len(describeResp.LoadBalancerDescriptions) != 1 {
|
|
|
|
return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancerDescriptions)
|
2014-11-21 17:58:34 +01:00
|
|
|
}
|
|
|
|
|
2015-04-13 22:14:26 +02:00
|
|
|
describeAttrsOpts := &elb.DescribeLoadBalancerAttributesInput{
|
|
|
|
LoadBalancerName: aws.String(elbName),
|
|
|
|
}
|
|
|
|
describeAttrsResp, err := elbconn.DescribeLoadBalancerAttributes(describeAttrsOpts)
|
|
|
|
if err != nil {
|
2015-04-29 18:31:23 +02:00
|
|
|
if isLoadBalancerNotFound(err) {
|
2015-04-13 22:14:26 +02:00
|
|
|
// The ELB is gone now, so just remove it from the state
|
|
|
|
d.SetId("")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Error retrieving ELB: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
lbAttrs := describeAttrsResp.LoadBalancerAttributes
|
|
|
|
|
2015-03-02 16:44:06 +01:00
|
|
|
lb := describeResp.LoadBalancerDescriptions[0]
|
2014-11-21 17:58:34 +01:00
|
|
|
|
2015-03-02 16:44:06 +01:00
|
|
|
d.Set("name", *lb.LoadBalancerName)
|
|
|
|
d.Set("dns_name", *lb.DNSName)
|
2015-04-30 23:58:09 +02:00
|
|
|
d.Set("zone_id", *lb.CanonicalHostedZoneNameID)
|
2015-03-02 16:44:06 +01:00
|
|
|
d.Set("internal", *lb.Scheme == "internal")
|
2014-12-16 15:21:25 +01:00
|
|
|
d.Set("availability_zones", lb.AvailabilityZones)
|
2015-04-16 22:28:18 +02:00
|
|
|
d.Set("instances", flattenInstances(lb.Instances))
|
|
|
|
d.Set("listener", flattenListeners(lb.ListenerDescriptions))
|
2014-11-21 17:58:34 +01:00
|
|
|
d.Set("security_groups", lb.SecurityGroups)
|
2015-04-28 16:40:19 +02:00
|
|
|
if lb.SourceSecurityGroup != nil {
|
|
|
|
d.Set("source_security_group", lb.SourceSecurityGroup.GroupName)
|
|
|
|
}
|
2014-11-21 17:58:34 +01:00
|
|
|
d.Set("subnets", lb.Subnets)
|
2015-04-13 22:14:26 +02:00
|
|
|
d.Set("idle_timeout", lbAttrs.ConnectionSettings.IdleTimeout)
|
|
|
|
d.Set("connection_draining", lbAttrs.ConnectionDraining.Enabled)
|
|
|
|
d.Set("connection_draining_timeout", lbAttrs.ConnectionDraining.Timeout)
|
2014-11-21 17:58:34 +01:00
|
|
|
|
2015-03-24 19:37:42 +01:00
|
|
|
resp, err := elbconn.DescribeTags(&elb.DescribeTagsInput{
|
2015-04-14 23:41:36 +02:00
|
|
|
LoadBalancerNames: []*string{lb.LoadBalancerName},
|
2015-03-24 19:37:42 +01:00
|
|
|
})
|
|
|
|
|
2015-04-14 23:41:36 +02:00
|
|
|
var et []*elb.Tag
|
2015-03-24 19:37:42 +01:00
|
|
|
if len(resp.TagDescriptions) > 0 {
|
|
|
|
et = resp.TagDescriptions[0].Tags
|
|
|
|
}
|
|
|
|
d.Set("tags", tagsToMapELB(et))
|
2014-11-21 17:58:34 +01:00
|
|
|
// There's only one health check, so save that to state as we
|
|
|
|
// currently can
|
2015-03-02 16:44:06 +01:00
|
|
|
if *lb.HealthCheck.Target != "" {
|
2015-04-16 22:28:18 +02:00
|
|
|
d.Set("health_check", flattenHealthCheck(lb.HealthCheck))
|
2014-11-21 17:58:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
2014-11-21 17:58:34 +01:00
|
|
|
elbconn := meta.(*AWSClient).elbconn
|
2014-07-03 07:40:55 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
d.Partial(true)
|
2014-07-07 20:03:29 +02:00
|
|
|
|
2015-04-22 00:17:17 +02:00
|
|
|
if d.HasChange("listener") {
|
|
|
|
o, n := d.GetChange("listener")
|
|
|
|
os := o.(*schema.Set)
|
|
|
|
ns := n.(*schema.Set)
|
|
|
|
|
|
|
|
remove, _ := expandListeners(os.Difference(ns).List())
|
|
|
|
add, _ := expandListeners(ns.Difference(os).List())
|
|
|
|
|
|
|
|
if len(remove) > 0 {
|
|
|
|
ports := make([]*int64, 0, len(remove))
|
|
|
|
for _, listener := range remove {
|
|
|
|
ports = append(ports, listener.LoadBalancerPort)
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteListenersOpts := &elb.DeleteLoadBalancerListenersInput{
|
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
|
|
|
LoadBalancerPorts: ports,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.DeleteLoadBalancerListeners(deleteListenersOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure removing outdated ELB listeners: %s", err)
|
2015-04-22 00:17:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(add) > 0 {
|
|
|
|
createListenersOpts := &elb.CreateLoadBalancerListenersInput{
|
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
|
|
|
Listeners: add,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.CreateLoadBalancerListeners(createListenersOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure adding new or updated ELB listeners: %s", err)
|
2015-04-22 00:17:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d.SetPartial("listener")
|
|
|
|
}
|
|
|
|
|
2014-07-16 23:02:47 +02:00
|
|
|
// If we currently have instances, or did have instances,
|
|
|
|
// we want to figure out what to add and remove from the load
|
|
|
|
// balancer
|
2014-10-10 08:58:48 +02:00
|
|
|
if d.HasChange("instances") {
|
|
|
|
o, n := d.GetChange("instances")
|
|
|
|
os := o.(*schema.Set)
|
|
|
|
ns := n.(*schema.Set)
|
2015-04-16 22:28:18 +02:00
|
|
|
remove := expandInstanceString(os.Difference(ns).List())
|
|
|
|
add := expandInstanceString(ns.Difference(os).List())
|
2014-10-10 08:58:48 +02:00
|
|
|
|
|
|
|
if len(add) > 0 {
|
2015-04-14 23:41:36 +02:00
|
|
|
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancerInput{
|
2015-03-02 16:44:06 +01:00
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
2014-10-10 08:58:48 +02:00
|
|
|
Instances: add,
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
2014-07-07 20:03:29 +02:00
|
|
|
|
2014-07-16 23:02:47 +02:00
|
|
|
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure registering instances with ELB: %s", err)
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
2014-10-10 08:58:48 +02:00
|
|
|
if len(remove) > 0 {
|
2015-04-14 23:41:36 +02:00
|
|
|
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancerInput{
|
2015-03-02 16:44:06 +01:00
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
2014-10-10 08:58:48 +02:00
|
|
|
Instances: remove,
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure deregistering instances from ELB: %s", err)
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
2014-12-16 13:13:59 +01:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
d.SetPartial("instances")
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
|
|
|
|
2015-05-06 20:46:51 +02:00
|
|
|
if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") {
|
2015-03-02 16:44:06 +01:00
|
|
|
attrs := elb.ModifyLoadBalancerAttributesInput{
|
|
|
|
LoadBalancerName: aws.String(d.Get("name").(string)),
|
|
|
|
LoadBalancerAttributes: &elb.LoadBalancerAttributes{
|
|
|
|
CrossZoneLoadBalancing: &elb.CrossZoneLoadBalancing{
|
2015-07-28 22:29:46 +02:00
|
|
|
Enabled: aws.Bool(d.Get("cross_zone_load_balancing").(bool)),
|
2015-03-02 16:44:06 +01:00
|
|
|
},
|
2015-04-13 22:14:26 +02:00
|
|
|
ConnectionSettings: &elb.ConnectionSettings{
|
2015-07-28 22:29:46 +02:00
|
|
|
IdleTimeout: aws.Int64(int64(d.Get("idle_timeout").(int))),
|
2015-04-13 22:14:26 +02:00
|
|
|
},
|
2014-12-16 13:13:59 +01:00
|
|
|
},
|
|
|
|
}
|
2015-05-06 20:42:59 +02:00
|
|
|
|
2014-12-16 13:13:59 +01:00
|
|
|
_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure configuring ELB attributes: %s", err)
|
2014-12-10 07:07:08 +01:00
|
|
|
}
|
2015-05-06 20:42:59 +02:00
|
|
|
|
2014-12-16 13:13:59 +01:00
|
|
|
d.SetPartial("cross_zone_load_balancing")
|
2015-04-13 22:14:26 +02:00
|
|
|
d.SetPartial("idle_timeout")
|
|
|
|
d.SetPartial("connection_draining_timeout")
|
2014-12-16 13:13:59 +01:00
|
|
|
}
|
2014-12-10 07:07:08 +01:00
|
|
|
|
2015-05-06 20:46:51 +02:00
|
|
|
// We have to do these changes separately from everything else since
|
|
|
|
// they have some weird undocumented rules. You can't set the timeout
|
|
|
|
// without having connection draining to true, so we set that to true,
|
|
|
|
// set the timeout, then reset it to false if requested.
|
2015-05-06 20:42:59 +02:00
|
|
|
if d.HasChange("connection_draining") || d.HasChange("connection_draining_timeout") {
|
2015-05-06 20:46:51 +02:00
|
|
|
// We do timeout changes first since they require us to set draining
|
|
|
|
// to true for a hot second.
|
|
|
|
if d.HasChange("connection_draining_timeout") {
|
|
|
|
attrs := elb.ModifyLoadBalancerAttributesInput{
|
|
|
|
LoadBalancerName: aws.String(d.Get("name").(string)),
|
|
|
|
LoadBalancerAttributes: &elb.LoadBalancerAttributes{
|
|
|
|
ConnectionDraining: &elb.ConnectionDraining{
|
2015-07-28 22:29:46 +02:00
|
|
|
Enabled: aws.Bool(true),
|
|
|
|
Timeout: aws.Int64(int64(d.Get("connection_draining_timeout").(int))),
|
2015-05-06 20:46:51 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure configuring ELB attributes: %s", err)
|
2015-05-06 20:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
d.SetPartial("connection_draining_timeout")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then we always set connection draining even if there is no change.
|
|
|
|
// This lets us reset to "false" if requested even with a timeout
|
|
|
|
// change.
|
2015-05-06 20:42:59 +02:00
|
|
|
attrs := elb.ModifyLoadBalancerAttributesInput{
|
|
|
|
LoadBalancerName: aws.String(d.Get("name").(string)),
|
|
|
|
LoadBalancerAttributes: &elb.LoadBalancerAttributes{
|
|
|
|
ConnectionDraining: &elb.ConnectionDraining{
|
2015-07-28 22:29:46 +02:00
|
|
|
Enabled: aws.Bool(d.Get("connection_draining").(bool)),
|
2015-05-06 20:42:59 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure configuring ELB attributes: %s", err)
|
2015-05-06 20:42:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
d.SetPartial("connection_draining")
|
|
|
|
}
|
|
|
|
|
2015-02-03 04:25:54 +01:00
|
|
|
if d.HasChange("health_check") {
|
|
|
|
vs := d.Get("health_check").(*schema.Set).List()
|
|
|
|
if len(vs) > 0 {
|
|
|
|
check := vs[0].(map[string]interface{})
|
2015-03-02 16:44:06 +01:00
|
|
|
configureHealthCheckOpts := elb.ConfigureHealthCheckInput{
|
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
|
|
|
HealthCheck: &elb.HealthCheck{
|
2015-07-28 22:29:46 +02:00
|
|
|
HealthyThreshold: aws.Int64(int64(check["healthy_threshold"].(int))),
|
|
|
|
UnhealthyThreshold: aws.Int64(int64(check["unhealthy_threshold"].(int))),
|
|
|
|
Interval: aws.Int64(int64(check["interval"].(int))),
|
2015-03-02 16:44:06 +01:00
|
|
|
Target: aws.String(check["target"].(string)),
|
2015-07-28 22:29:46 +02:00
|
|
|
Timeout: aws.Int64(int64(check["timeout"].(int))),
|
2015-02-03 04:25:54 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
_, err := elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure configuring health check for ELB: %s", err)
|
2015-02-03 04:25:54 +01:00
|
|
|
}
|
|
|
|
d.SetPartial("health_check")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-23 21:46:29 +02:00
|
|
|
if d.HasChange("security_groups") {
|
|
|
|
groups := d.Get("security_groups").(*schema.Set).List()
|
|
|
|
|
|
|
|
applySecurityGroupsOpts := elb.ApplySecurityGroupsToLoadBalancerInput{
|
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
|
|
|
SecurityGroups: expandStringList(groups),
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.ApplySecurityGroupsToLoadBalancer(&applySecurityGroupsOpts)
|
|
|
|
if err != nil {
|
2015-05-18 22:25:03 +02:00
|
|
|
return fmt.Errorf("Failure applying security groups to ELB: %s", err)
|
2015-04-23 21:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
d.SetPartial("security_groups")
|
|
|
|
}
|
|
|
|
|
2015-03-24 19:37:42 +01:00
|
|
|
if err := setTagsELB(elbconn, d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-13 22:14:26 +02:00
|
|
|
|
|
|
|
d.SetPartial("tags")
|
2014-10-10 08:58:48 +02:00
|
|
|
d.Partial(false)
|
2015-03-02 16:44:06 +01:00
|
|
|
|
2014-10-10 22:50:08 +02:00
|
|
|
return resourceAwsElbRead(d, meta)
|
2014-07-03 07:40:55 +02:00
|
|
|
}
|
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
func resourceAwsElbDelete(d *schema.ResourceData, meta interface{}) error {
|
2014-11-21 17:58:34 +01:00
|
|
|
elbconn := meta.(*AWSClient).elbconn
|
2014-07-07 20:03:29 +02:00
|
|
|
|
2014-10-10 08:58:48 +02:00
|
|
|
log.Printf("[INFO] Deleting ELB: %s", d.Id())
|
2014-07-07 20:03:29 +02:00
|
|
|
|
|
|
|
// Destroy the load balancer
|
2015-04-14 23:41:36 +02:00
|
|
|
deleteElbOpts := elb.DeleteLoadBalancerInput{
|
2015-03-02 16:44:06 +01:00
|
|
|
LoadBalancerName: aws.String(d.Id()),
|
2014-07-07 20:03:29 +02:00
|
|
|
}
|
2014-10-10 08:58:48 +02:00
|
|
|
if _, err := elbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
|
2014-07-07 20:03:29 +02:00
|
|
|
return fmt.Errorf("Error deleting ELB: %s", err)
|
|
|
|
}
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
func resourceAwsElbHealthCheckHash(v interface{}) int {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["healthy_threshold"].(int)))
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["unhealthy_threshold"].(int)))
|
|
|
|
buf.WriteString(fmt.Sprintf("%s-", m["target"].(string)))
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int)))
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int)))
|
2014-07-30 16:15:22 +02:00
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
return hashcode.String(buf.String())
|
|
|
|
}
|
2014-08-08 02:14:48 +02:00
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
func resourceAwsElbListenerHash(v interface{}) int {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int)))
|
2015-06-05 17:12:32 +02:00
|
|
|
buf.WriteString(fmt.Sprintf("%s-",
|
|
|
|
strings.ToLower(m["instance_protocol"].(string))))
|
2014-11-21 17:58:34 +01:00
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int)))
|
2015-06-05 17:12:32 +02:00
|
|
|
buf.WriteString(fmt.Sprintf("%s-",
|
|
|
|
strings.ToLower(m["lb_protocol"].(string))))
|
2014-08-08 02:14:48 +02:00
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
if v, ok := m["ssl_certificate_id"]; ok {
|
|
|
|
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
|
2014-07-30 16:15:22 +02:00
|
|
|
}
|
|
|
|
|
2014-11-21 17:58:34 +01:00
|
|
|
return hashcode.String(buf.String())
|
2014-07-15 18:18:36 +02:00
|
|
|
}
|
2015-04-29 18:31:23 +02:00
|
|
|
|
|
|
|
func isLoadBalancerNotFound(err error) bool {
|
2015-05-20 13:21:23 +02:00
|
|
|
elberr, ok := err.(awserr.Error)
|
|
|
|
return ok && elberr.Code() == "LoadBalancerNotFound"
|
2015-04-29 18:31:23 +02:00
|
|
|
}
|
2015-09-21 23:00:51 +02:00
|
|
|
|
|
|
|
func validateElbName(v interface{}, k string) (ws []string, errors []error) {
|
|
|
|
value := v.(string)
|
|
|
|
if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
|
|
|
|
errors = append(errors, fmt.Errorf(
|
|
|
|
"only alphanumeric characters and hyphens allowed in %q: %q",
|
|
|
|
k, value))
|
|
|
|
}
|
|
|
|
if len(value) > 32 {
|
|
|
|
errors = append(errors, fmt.Errorf(
|
|
|
|
"%q cannot be longer than 32 characters: %q", k, value))
|
|
|
|
}
|
|
|
|
if regexp.MustCompile(`^-`).MatchString(value) {
|
|
|
|
errors = append(errors, fmt.Errorf(
|
|
|
|
"%q cannot begin with a hyphen: %q", k, value))
|
|
|
|
}
|
|
|
|
if regexp.MustCompile(`-$`).MatchString(value) {
|
|
|
|
errors = append(errors, fmt.Errorf(
|
|
|
|
"%q cannot end with a hyphen: %q", k, value))
|
|
|
|
}
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|