2014-06-27 18:47:19 +02:00
|
|
|
package aws
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
2014-07-30 13:46:51 +02:00
|
|
|
"strconv"
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-03 00:55:28 +02:00
|
|
|
"github.com/hashicorp/terraform/flatmap"
|
2014-07-15 18:18:36 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/config"
|
2014-06-27 18:47:19 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/diff"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
2014-06-27 18:55:24 +02:00
|
|
|
"github.com/mitchellh/goamz/elb"
|
2014-06-27 18:47:19 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func resource_aws_elb_create(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
2014-09-18 01:33:24 +02:00
|
|
|
d *terraform.InstanceDiff,
|
2014-09-17 02:44:42 +02:00
|
|
|
meta interface{}) (*terraform.InstanceState, error) {
|
2014-06-27 18:47:19 +02:00
|
|
|
p := meta.(*ResourceProvider)
|
|
|
|
elbconn := p.elbconn
|
|
|
|
|
|
|
|
// Merge the diff into the state so that we have all the attributes
|
|
|
|
// properly.
|
|
|
|
rs := s.MergeDiff(d)
|
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
// The name specified for the ELB. This is also our unique ID
|
2014-08-07 09:19:56 +02:00
|
|
|
// we save to state if the creation is successful (amazon verifies
|
2014-07-01 20:56:04 +02:00
|
|
|
// it is unique)
|
|
|
|
elbName := rs.Attributes["name"]
|
2014-07-03 00:55:28 +02:00
|
|
|
|
|
|
|
// Expand the "listener" array to goamz compat []elb.Listener
|
|
|
|
v := flatmap.Expand(rs.Attributes, "listener").([]interface{})
|
2014-07-25 00:50:18 +02:00
|
|
|
listeners, err := expandListeners(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
// Provision the elb
|
|
|
|
elbOpts := &elb.CreateLoadBalancer{
|
|
|
|
LoadBalancerName: elbName,
|
2014-07-03 00:55:28 +02:00
|
|
|
Listeners: listeners,
|
2014-07-28 03:20:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := rs.Attributes["availability_zones.#"]; ok {
|
|
|
|
v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{})
|
2014-08-08 02:14:48 +02:00
|
|
|
elbOpts.AvailZone = expandStringList(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := rs.Attributes["security_groups.#"]; ok {
|
|
|
|
v = flatmap.Expand(rs.Attributes, "security_groups").([]interface{})
|
|
|
|
elbOpts.SecurityGroups = expandStringList(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := rs.Attributes["subnets.#"]; ok {
|
|
|
|
v = flatmap.Expand(rs.Attributes, "subnets").([]interface{})
|
|
|
|
elbOpts.Subnets = expandStringList(v)
|
2014-07-01 20:56:04 +02:00
|
|
|
}
|
2014-07-02 21:03:58 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
|
|
|
|
|
2014-07-25 00:50:18 +02:00
|
|
|
_, err = elbconn.CreateLoadBalancer(elbOpts)
|
2014-07-01 20:56:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Error creating ELB: %s", err)
|
|
|
|
}
|
|
|
|
|
2014-08-07 09:19:56 +02:00
|
|
|
// Assign the elb's unique identifier for use later
|
2014-07-01 20:56:04 +02:00
|
|
|
rs.ID = elbName
|
|
|
|
log.Printf("[INFO] ELB ID: %s", elbName)
|
|
|
|
|
2014-07-28 03:20:03 +02:00
|
|
|
if _, ok := rs.Attributes["instances.#"]; ok {
|
|
|
|
// If we have any instances, we need to register them
|
|
|
|
v = flatmap.Expand(rs.Attributes, "instances").([]interface{})
|
|
|
|
instances := expandStringList(v)
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-07-28 03:20:03 +02:00
|
|
|
if len(instances) > 0 {
|
|
|
|
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
|
|
|
|
LoadBalancerName: elbName,
|
|
|
|
Instances: instances,
|
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-07-28 03:20:03 +02:00
|
|
|
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-07-28 03:20:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return rs, fmt.Errorf("Failure registering instances: %s", err)
|
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-30 16:15:22 +02:00
|
|
|
|
2014-07-30 13:46:51 +02:00
|
|
|
if _, ok := rs.Attributes["health_check.#"]; ok {
|
|
|
|
v := flatmap.Expand(rs.Attributes, "health_check").([]interface{})
|
|
|
|
health_check := v[0].(map[string]interface{})
|
|
|
|
healthyThreshold, err := strconv.ParseInt(health_check["healthy_threshold"].(string), 0, 0)
|
|
|
|
unhealthyThreshold, err := strconv.ParseInt(health_check["unhealthy_threshold"].(string), 0, 0)
|
|
|
|
interval, err := strconv.ParseInt(health_check["interval"].(string), 0, 0)
|
|
|
|
timeout, err := strconv.ParseInt(health_check["timeout"].(string), 0, 0)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
configureHealthCheckOpts := elb.ConfigureHealthCheck{
|
|
|
|
LoadBalancerName: elbName,
|
|
|
|
Check: elb.HealthCheck{
|
2014-07-30 16:15:22 +02:00
|
|
|
HealthyThreshold: healthyThreshold,
|
2014-07-30 13:46:51 +02:00
|
|
|
UnhealthyThreshold: unhealthyThreshold,
|
2014-07-30 16:15:22 +02:00
|
|
|
Interval: interval,
|
|
|
|
Target: health_check["target"].(string),
|
|
|
|
Timeout: timeout,
|
2014-07-30 13:46:51 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
|
|
|
|
if err != nil {
|
|
|
|
return rs, fmt.Errorf("Failure configuring health check: %s", err)
|
|
|
|
}
|
|
|
|
}
|
2014-07-05 01:03:01 +02:00
|
|
|
|
2014-07-07 23:31:27 +02:00
|
|
|
loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
|
2014-07-01 20:56:04 +02:00
|
|
|
if err != nil {
|
2014-07-07 23:38:35 +02:00
|
|
|
return rs, err
|
2014-07-01 20:56:04 +02:00
|
|
|
}
|
2014-07-03 07:40:55 +02:00
|
|
|
|
2014-07-07 23:31:27 +02:00
|
|
|
return resource_aws_elb_update_state(rs, loadBalancer)
|
2014-06-27 18:47:19 +02:00
|
|
|
}
|
|
|
|
|
2014-07-03 07:40:55 +02:00
|
|
|
func resource_aws_elb_update(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
2014-09-18 01:33:24 +02:00
|
|
|
d *terraform.InstanceDiff,
|
2014-09-17 02:44:42 +02:00
|
|
|
meta interface{}) (*terraform.InstanceState, error) {
|
2014-07-16 23:02:47 +02:00
|
|
|
p := meta.(*ResourceProvider)
|
|
|
|
elbconn := p.elbconn
|
2014-07-03 07:40:55 +02:00
|
|
|
|
2014-07-07 20:03:29 +02:00
|
|
|
rs := s.MergeDiff(d)
|
|
|
|
|
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
|
|
|
|
if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" {
|
|
|
|
// The new state of instances merged with the diff
|
|
|
|
mergedInstances := expandStringList(flatmap.Expand(
|
|
|
|
rs.Attributes, "instances").([]interface{}))
|
|
|
|
|
|
|
|
// The state before the diff merge
|
|
|
|
previousInstances := expandStringList(flatmap.Expand(
|
|
|
|
s.Attributes, "instances").([]interface{}))
|
|
|
|
|
|
|
|
// keep track of what instances we are removing, and which
|
|
|
|
// we are adding
|
|
|
|
var toRemove []string
|
|
|
|
var toAdd []string
|
|
|
|
|
|
|
|
for _, instanceId := range mergedInstances {
|
2014-07-17 01:41:01 +02:00
|
|
|
for _, prevId := range previousInstances {
|
2014-07-16 23:02:47 +02:00
|
|
|
// If the merged instance ID existed
|
|
|
|
// previously, we don't have to do anything
|
|
|
|
if instanceId == prevId {
|
|
|
|
continue
|
2014-07-17 01:41:01 +02:00
|
|
|
// Otherwise, we need to add it to the load balancer
|
2014-07-16 23:02:47 +02:00
|
|
|
} else {
|
|
|
|
toAdd = append(toAdd, instanceId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, instanceId := range toAdd {
|
2014-07-17 01:41:01 +02:00
|
|
|
for _, prevId := range previousInstances {
|
2014-07-16 23:02:47 +02:00
|
|
|
// If the instance ID we are adding existed
|
|
|
|
// previously, we want to not add it, but rather remove
|
|
|
|
// it
|
|
|
|
if instanceId == prevId {
|
|
|
|
toRemove = append(toRemove, instanceId)
|
|
|
|
toAdd = append(toAdd[:i], toAdd[i+1:]...)
|
2014-07-17 01:41:01 +02:00
|
|
|
// Otherwise, we continue adding it to the ELB
|
2014-07-16 23:02:47 +02:00
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-03 07:40:55 +02:00
|
|
|
|
2014-07-16 23:02:47 +02:00
|
|
|
if len(toAdd) > 0 {
|
|
|
|
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
|
|
|
|
LoadBalancerName: rs.ID,
|
|
|
|
Instances: toAdd,
|
|
|
|
}
|
2014-07-07 20:03:29 +02:00
|
|
|
|
2014-07-16 23:02:47 +02:00
|
|
|
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return s, fmt.Errorf("Failure registering instances: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(toRemove) > 0 {
|
|
|
|
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
|
|
|
|
LoadBalancerName: rs.ID,
|
|
|
|
Instances: toRemove,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return s, fmt.Errorf("Failure deregistering instances: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return s, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return resource_aws_elb_update_state(rs, loadBalancer)
|
2014-07-03 07:40:55 +02:00
|
|
|
}
|
|
|
|
|
2014-06-27 18:47:19 +02:00
|
|
|
func resource_aws_elb_destroy(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
2014-06-27 18:47:19 +02:00
|
|
|
meta interface{}) error {
|
2014-07-07 20:03:29 +02:00
|
|
|
p := meta.(*ResourceProvider)
|
|
|
|
elbconn := p.elbconn
|
|
|
|
|
|
|
|
log.Printf("[INFO] Deleting ELB: %s", s.ID)
|
|
|
|
|
|
|
|
// Destroy the load balancer
|
|
|
|
deleteElbOpts := elb.DeleteLoadBalancer{
|
|
|
|
LoadBalancerName: s.ID,
|
|
|
|
}
|
|
|
|
_, err := elbconn.DeleteLoadBalancer(&deleteElbOpts)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func resource_aws_elb_refresh(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
|
|
|
meta interface{}) (*terraform.InstanceState, error) {
|
2014-07-07 23:31:27 +02:00
|
|
|
p := meta.(*ResourceProvider)
|
|
|
|
elbconn := p.elbconn
|
2014-07-01 20:56:04 +02:00
|
|
|
|
2014-07-07 23:31:27 +02:00
|
|
|
loadBalancer, err := resource_aws_elb_retrieve_balancer(s.ID, elbconn)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
return resource_aws_elb_update_state(s, loadBalancer)
|
2014-06-27 18:47:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func resource_aws_elb_diff(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
2014-06-27 18:47:19 +02:00
|
|
|
c *terraform.ResourceConfig,
|
2014-09-18 01:33:24 +02:00
|
|
|
meta interface{}) (*terraform.InstanceDiff, error) {
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
b := &diff.ResourceBuilder{
|
2014-07-02 01:22:24 +02:00
|
|
|
Attrs: map[string]diff.AttrType{
|
2014-07-02 21:03:58 +02:00
|
|
|
"name": diff.AttrTypeCreate,
|
|
|
|
"availability_zone": diff.AttrTypeCreate,
|
2014-08-08 02:14:48 +02:00
|
|
|
"security_groups": diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
|
|
|
|
"subnets": diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
|
2014-07-03 00:55:28 +02:00
|
|
|
"listener": diff.AttrTypeCreate,
|
2014-07-03 07:40:55 +02:00
|
|
|
"instances": diff.AttrTypeUpdate,
|
2014-07-30 13:46:51 +02:00
|
|
|
"health_check": diff.AttrTypeCreate,
|
2014-07-01 20:56:04 +02:00
|
|
|
},
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-02 01:22:24 +02:00
|
|
|
ComputedAttrs: []string{
|
|
|
|
"dns_name",
|
2014-07-01 20:56:04 +02:00
|
|
|
},
|
|
|
|
}
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
return b.Diff(s, c)
|
|
|
|
}
|
2014-06-27 18:47:19 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
func resource_aws_elb_update_state(
|
2014-09-17 02:44:42 +02:00
|
|
|
s *terraform.InstanceState,
|
|
|
|
balancer *elb.LoadBalancer) (*terraform.InstanceState, error) {
|
2014-07-16 23:02:47 +02:00
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
s.Attributes["name"] = balancer.LoadBalancerName
|
|
|
|
s.Attributes["dns_name"] = balancer.DNSName
|
2014-07-16 23:02:47 +02:00
|
|
|
|
|
|
|
// Flatten our group values
|
|
|
|
toFlatten := make(map[string]interface{})
|
|
|
|
|
|
|
|
if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" {
|
|
|
|
toFlatten["instances"] = flattenInstances(balancer.Instances)
|
2014-07-30 16:15:22 +02:00
|
|
|
}
|
|
|
|
|
2014-08-08 02:14:48 +02:00
|
|
|
if len(balancer.SecurityGroups) > 0 && balancer.SecurityGroups[0] != "" {
|
|
|
|
toFlatten["security_groups"] = balancer.SecurityGroups
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(balancer.Subnets) > 0 && balancer.Subnets[0] != "" {
|
|
|
|
toFlatten["subnets"] = balancer.Subnets
|
|
|
|
}
|
|
|
|
|
2014-07-30 16:15:22 +02:00
|
|
|
// There's only one health check, so save that to state as we
|
|
|
|
// currently can
|
|
|
|
if balancer.HealthCheck.Target != "" {
|
|
|
|
toFlatten["health_check"] = flattenHealthCheck(balancer.HealthCheck)
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range flatmap.Flatten(toFlatten) {
|
|
|
|
s.Attributes[k] = v
|
2014-07-16 23:02:47 +02:00
|
|
|
}
|
|
|
|
|
2014-07-01 20:56:04 +02:00
|
|
|
return s, nil
|
2014-06-27 18:47:19 +02:00
|
|
|
}
|
2014-07-07 23:31:27 +02:00
|
|
|
|
2014-08-07 09:19:56 +02:00
|
|
|
// retrieves an ELB by its ID
|
2014-07-07 23:31:27 +02:00
|
|
|
func resource_aws_elb_retrieve_balancer(id string, elbconn *elb.ELB) (*elb.LoadBalancer, error) {
|
|
|
|
describeElbOpts := &elb.DescribeLoadBalancer{
|
|
|
|
Names: []string{id},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the ELB properties for updating the state
|
|
|
|
describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Error retrieving ELB: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
loadBalancer := describeResp.LoadBalancers[0]
|
|
|
|
|
|
|
|
// Verify AWS returned our ELB
|
|
|
|
if len(describeResp.LoadBalancers) != 1 ||
|
|
|
|
describeResp.LoadBalancers[0].LoadBalancerName != id {
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &loadBalancer, nil
|
|
|
|
}
|
2014-07-15 18:18:36 +02:00
|
|
|
|
|
|
|
func resource_aws_elb_validation() *config.Validator {
|
|
|
|
return &config.Validator{
|
|
|
|
Required: []string{
|
|
|
|
"name",
|
|
|
|
"listener.*",
|
|
|
|
"listener.*.instance_port",
|
|
|
|
"listener.*.instance_protocol",
|
|
|
|
"listener.*.lb_port",
|
|
|
|
"listener.*.lb_protocol",
|
|
|
|
},
|
|
|
|
Optional: []string{
|
2014-07-16 17:14:23 +02:00
|
|
|
"instances.*",
|
2014-07-28 03:20:03 +02:00
|
|
|
"availability_zones.*",
|
2014-08-08 02:14:48 +02:00
|
|
|
"security_groups.*",
|
|
|
|
"subnets.*",
|
2014-07-30 13:46:51 +02:00
|
|
|
"health_check.#",
|
|
|
|
"health_check.0.healthy_threshold",
|
|
|
|
"health_check.0.unhealthy_threshold",
|
|
|
|
"health_check.0.interval",
|
|
|
|
"health_check.0.target",
|
|
|
|
"health_check.0.timeout",
|
2014-07-15 18:18:36 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|