Merge pull request #388 from hashicorp/f-elb-schema
aws_elb to helper/schema, fix issues in helper/schema around computed sets
This commit is contained in:
commit
1acb546d74
|
@ -43,6 +43,7 @@ func Provider() *schema.Provider {
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"aws_eip": resourceAwsEip(),
|
"aws_eip": resourceAwsEip(),
|
||||||
|
"aws_elb": resourceAwsElb(),
|
||||||
"aws_instance": resourceAwsInstance(),
|
"aws_instance": resourceAwsInstance(),
|
||||||
"aws_security_group": resourceAwsSecurityGroup(),
|
"aws_security_group": resourceAwsSecurityGroup(),
|
||||||
"aws_db_subnet_group": resourceAwsDbSubnetGroup(),
|
"aws_db_subnet_group": resourceAwsDbSubnetGroup(),
|
||||||
|
|
|
@ -1,369 +1,344 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/flatmap"
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
"github.com/hashicorp/terraform/helper/config"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"github.com/hashicorp/terraform/helper/diff"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
|
||||||
"github.com/mitchellh/goamz/elb"
|
"github.com/mitchellh/goamz/elb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resource_aws_elb_create(
|
func resourceAwsElb() *schema.Resource {
|
||||||
s *terraform.InstanceState,
|
return &schema.Resource{
|
||||||
d *terraform.InstanceDiff,
|
Create: resourceAwsElbCreate,
|
||||||
meta interface{}) (*terraform.InstanceState, error) {
|
Read: resourceAwsElbRead,
|
||||||
|
Update: resourceAwsElbUpdate,
|
||||||
|
Delete: resourceAwsElbDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"internal": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"availability_zones": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"instances": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Optional: true,
|
||||||
|
Set: func(v interface{}) int {
|
||||||
|
return hashcode.String(v.(string))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: could be not ForceNew
|
||||||
|
"security_groups": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: could be not ForceNew
|
||||||
|
"subnets": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: could be not ForceNew
|
||||||
|
"listener": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: 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,
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: could be not ForceNew
|
||||||
|
"health_check": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsElbListenerHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["instance_protocol"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["lb_protocol"].(string)))
|
||||||
|
|
||||||
|
if v, ok := m["ssl_certificate_id"]; ok {
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
p := meta.(*ResourceProvider)
|
p := meta.(*ResourceProvider)
|
||||||
elbconn := p.elbconn
|
elbconn := p.elbconn
|
||||||
|
|
||||||
// Merge the diff into the state so that we have all the attributes
|
// Expand the "listener" set to goamz compat []elb.Listener
|
||||||
// properly.
|
listeners, err := expandListeners(d.Get("listener").(*schema.Set).List())
|
||||||
rs := s.MergeDiff(d)
|
|
||||||
|
|
||||||
// The name specified for the ELB. This is also our unique ID
|
|
||||||
// we save to state if the creation is successful (amazon verifies
|
|
||||||
// it is unique)
|
|
||||||
elbName := rs.Attributes["name"]
|
|
||||||
|
|
||||||
// Expand the "listener" array to goamz compat []elb.Listener
|
|
||||||
v := flatmap.Expand(rs.Attributes, "listener").([]interface{})
|
|
||||||
listeners, err := expandListeners(v)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provision the elb
|
// Provision the elb
|
||||||
elbOpts := &elb.CreateLoadBalancer{
|
elbOpts := &elb.CreateLoadBalancer{
|
||||||
LoadBalancerName: elbName,
|
LoadBalancerName: d.Get("name").(string),
|
||||||
Listeners: listeners,
|
Listeners: listeners,
|
||||||
|
Internal: d.Get("internal").(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
if rs.Attributes["internal"] == "true" {
|
if v, ok := d.GetOk("availability_zones"); ok {
|
||||||
elbOpts.Internal = true
|
elbOpts.AvailZone = expandStringList(v.([]interface{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := rs.Attributes["availability_zones.#"]; ok {
|
if v, ok := d.GetOk("security_groups"); ok {
|
||||||
v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{})
|
elbOpts.SecurityGroups = expandStringList(v.([]interface{}))
|
||||||
elbOpts.AvailZone = expandStringList(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := rs.Attributes["security_groups.#"]; ok {
|
if v, ok := d.GetOk("subnets"); ok {
|
||||||
v = flatmap.Expand(rs.Attributes, "security_groups").([]interface{})
|
elbOpts.Subnets = expandStringList(v.([]interface{}))
|
||||||
elbOpts.SecurityGroups = expandStringList(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := rs.Attributes["subnets.#"]; ok {
|
|
||||||
v = flatmap.Expand(rs.Attributes, "subnets").([]interface{})
|
|
||||||
elbOpts.Subnets = expandStringList(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
|
log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
|
||||||
|
if _, err := elbconn.CreateLoadBalancer(elbOpts); err != nil {
|
||||||
_, err = elbconn.CreateLoadBalancer(elbOpts)
|
return fmt.Errorf("Error creating ELB: %s", err)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error creating ELB: %s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the elb's unique identifier for use later
|
// Assign the elb's unique identifier for use later
|
||||||
rs.ID = elbName
|
d.SetId(d.Get("name").(string))
|
||||||
log.Printf("[INFO] ELB ID: %s", elbName)
|
log.Printf("[INFO] ELB ID: %s", d.Id())
|
||||||
|
|
||||||
if _, ok := rs.Attributes["instances.#"]; ok {
|
// Enable partial mode and record what we set
|
||||||
// If we have any instances, we need to register them
|
d.Partial(true)
|
||||||
v = flatmap.Expand(rs.Attributes, "instances").([]interface{})
|
d.SetPartial("name")
|
||||||
instances := expandStringList(v)
|
d.SetPartial("internal")
|
||||||
|
d.SetPartial("availability_zones")
|
||||||
|
d.SetPartial("security_groups")
|
||||||
|
d.SetPartial("subnets")
|
||||||
|
|
||||||
if len(instances) > 0 {
|
if d.HasChange("health_check") {
|
||||||
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
|
vs := d.Get("health_check").(*schema.Set).List()
|
||||||
LoadBalancerName: elbName,
|
if len(vs) > 0 {
|
||||||
Instances: instances,
|
check := vs[0].(map[string]interface{})
|
||||||
|
|
||||||
|
configureHealthCheckOpts := elb.ConfigureHealthCheck{
|
||||||
|
LoadBalancerName: d.Id(),
|
||||||
|
Check: elb.HealthCheck{
|
||||||
|
HealthyThreshold: int64(check["healthy_threshold"].(int)),
|
||||||
|
UnhealthyThreshold: int64(check["unhealthy_threshold"].(int)),
|
||||||
|
Interval: int64(check["interval"].(int)),
|
||||||
|
Target: check["target"].(string),
|
||||||
|
Timeout: int64(check["timeout"].(int)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
_, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rs, fmt.Errorf("Failure registering instances: %s", err)
|
return fmt.Errorf("Failure configuring health check: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := rs.Attributes["health_check.#"]; ok {
|
return resourceAwsElbUpdate(d, meta)
|
||||||
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{
|
|
||||||
HealthyThreshold: healthyThreshold,
|
|
||||||
UnhealthyThreshold: unhealthyThreshold,
|
|
||||||
Interval: interval,
|
|
||||||
Target: health_check["target"].(string),
|
|
||||||
Timeout: timeout,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
|
|
||||||
if err != nil {
|
|
||||||
return rs, fmt.Errorf("Failure configuring health check: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
|
|
||||||
if err != nil {
|
|
||||||
return rs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resource_aws_elb_update_state(rs, loadBalancer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resource_aws_elb_update(
|
func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
s *terraform.InstanceState,
|
|
||||||
d *terraform.InstanceDiff,
|
|
||||||
meta interface{}) (*terraform.InstanceState, error) {
|
|
||||||
p := meta.(*ResourceProvider)
|
p := meta.(*ResourceProvider)
|
||||||
elbconn := p.elbconn
|
elbconn := p.elbconn
|
||||||
|
|
||||||
rs := s.MergeDiff(d)
|
d.Partial(true)
|
||||||
|
|
||||||
// If we currently have instances, or did have instances,
|
// If we currently have instances, or did have instances,
|
||||||
// we want to figure out what to add and remove from the load
|
// we want to figure out what to add and remove from the load
|
||||||
// balancer
|
// balancer
|
||||||
if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" {
|
if d.HasChange("instances") {
|
||||||
// The new state of instances merged with the diff
|
o, n := d.GetChange("instances")
|
||||||
mergedInstances := expandStringList(flatmap.Expand(
|
os := o.(*schema.Set)
|
||||||
rs.Attributes, "instances").([]interface{}))
|
ns := n.(*schema.Set)
|
||||||
|
remove := expandStringList(os.Difference(ns).List())
|
||||||
|
add := expandStringList(ns.Difference(os).List())
|
||||||
|
|
||||||
// The state before the diff merge
|
if len(add) > 0 {
|
||||||
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 {
|
|
||||||
for _, prevId := range previousInstances {
|
|
||||||
// If the merged instance ID existed
|
|
||||||
// previously, we don't have to do anything
|
|
||||||
if instanceId == prevId {
|
|
||||||
continue
|
|
||||||
// Otherwise, we need to add it to the load balancer
|
|
||||||
} else {
|
|
||||||
toAdd = append(toAdd, instanceId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, instanceId := range toAdd {
|
|
||||||
for _, prevId := range previousInstances {
|
|
||||||
// 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:]...)
|
|
||||||
// Otherwise, we continue adding it to the ELB
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(toAdd) > 0 {
|
|
||||||
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
|
registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
|
||||||
LoadBalancerName: rs.ID,
|
LoadBalancerName: d.Id(),
|
||||||
Instances: toAdd,
|
Instances: add,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
_, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, fmt.Errorf("Failure registering instances: %s", err)
|
return fmt.Errorf("Failure registering instances: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(remove) > 0 {
|
||||||
if len(toRemove) > 0 {
|
|
||||||
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
|
deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
|
||||||
LoadBalancerName: rs.ID,
|
LoadBalancerName: d.Id(),
|
||||||
Instances: toRemove,
|
Instances: remove,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, fmt.Errorf("Failure deregistering instances: %s", err)
|
return fmt.Errorf("Failure deregistering instances: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.SetPartial("instances")
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
|
d.Partial(false)
|
||||||
|
return nil
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resource_aws_elb_update_state(rs, loadBalancer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resource_aws_elb_destroy(
|
func resourceAwsElbDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
s *terraform.InstanceState,
|
|
||||||
meta interface{}) error {
|
|
||||||
p := meta.(*ResourceProvider)
|
p := meta.(*ResourceProvider)
|
||||||
elbconn := p.elbconn
|
elbconn := p.elbconn
|
||||||
|
|
||||||
log.Printf("[INFO] Deleting ELB: %s", s.ID)
|
log.Printf("[INFO] Deleting ELB: %s", d.Id())
|
||||||
|
|
||||||
// Destroy the load balancer
|
// Destroy the load balancer
|
||||||
deleteElbOpts := elb.DeleteLoadBalancer{
|
deleteElbOpts := elb.DeleteLoadBalancer{
|
||||||
LoadBalancerName: s.ID,
|
LoadBalancerName: d.Id(),
|
||||||
}
|
}
|
||||||
_, err := elbconn.DeleteLoadBalancer(&deleteElbOpts)
|
if _, err := elbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error deleting ELB: %s", err)
|
return fmt.Errorf("Error deleting ELB: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resource_aws_elb_refresh(
|
func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
s *terraform.InstanceState,
|
|
||||||
meta interface{}) (*terraform.InstanceState, error) {
|
|
||||||
p := meta.(*ResourceProvider)
|
p := meta.(*ResourceProvider)
|
||||||
elbconn := p.elbconn
|
elbconn := p.elbconn
|
||||||
|
|
||||||
loadBalancer, err := resource_aws_elb_retrieve_balancer(s.ID, elbconn)
|
// Retrieve the ELB properties for updating the state
|
||||||
|
describeElbOpts := &elb.DescribeLoadBalancer{
|
||||||
|
Names: []string{d.Id()},
|
||||||
|
}
|
||||||
|
|
||||||
|
describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("Error retrieving ELB: %s", err)
|
||||||
|
}
|
||||||
|
if len(describeResp.LoadBalancers) != 1 {
|
||||||
|
return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resource_aws_elb_update_state(s, loadBalancer)
|
lb := describeResp.LoadBalancers[0]
|
||||||
}
|
|
||||||
|
|
||||||
func resource_aws_elb_diff(
|
d.Set("name", lb.LoadBalancerName)
|
||||||
s *terraform.InstanceState,
|
d.Set("dns_name", lb.DNSName)
|
||||||
c *terraform.ResourceConfig,
|
d.Set("internal", lb.Scheme == "internal")
|
||||||
meta interface{}) (*terraform.InstanceDiff, error) {
|
d.Set("instances", flattenInstances(lb.Instances))
|
||||||
|
d.Set("security_groups", lb.SecurityGroups)
|
||||||
b := &diff.ResourceBuilder{
|
d.Set("subnets", lb.Subnets)
|
||||||
Attrs: map[string]diff.AttrType{
|
|
||||||
"name": diff.AttrTypeCreate,
|
|
||||||
"availability_zone": diff.AttrTypeCreate,
|
|
||||||
"security_groups": diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
|
|
||||||
"subnets": diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
|
|
||||||
"listener": diff.AttrTypeCreate,
|
|
||||||
"instances": diff.AttrTypeUpdate,
|
|
||||||
"health_check": diff.AttrTypeCreate,
|
|
||||||
"internal": diff.AttrTypeCreate,
|
|
||||||
},
|
|
||||||
|
|
||||||
ComputedAttrs: []string{
|
|
||||||
"dns_name",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.Diff(s, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resource_aws_elb_update_state(
|
|
||||||
s *terraform.InstanceState,
|
|
||||||
balancer *elb.LoadBalancer) (*terraform.InstanceState, error) {
|
|
||||||
|
|
||||||
s.Attributes["name"] = balancer.LoadBalancerName
|
|
||||||
s.Attributes["dns_name"] = balancer.DNSName
|
|
||||||
|
|
||||||
if balancer.Scheme == "internal" {
|
|
||||||
s.Attributes["internal"] = "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flatten our group values
|
|
||||||
toFlatten := make(map[string]interface{})
|
|
||||||
|
|
||||||
if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" {
|
|
||||||
toFlatten["instances"] = flattenInstances(balancer.Instances)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's only one health check, so save that to state as we
|
// There's only one health check, so save that to state as we
|
||||||
// currently can
|
// currently can
|
||||||
if balancer.HealthCheck.Target != "" {
|
if lb.HealthCheck.Target != "" {
|
||||||
toFlatten["health_check"] = flattenHealthCheck(balancer.HealthCheck)
|
d.Set("health_check", flattenHealthCheck(lb.HealthCheck))
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range flatmap.Flatten(toFlatten) {
|
return nil
|
||||||
s.Attributes[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieves an ELB by its ID
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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{
|
|
||||||
"instances.*",
|
|
||||||
"listener.*.ssl_certificate_id",
|
|
||||||
"internal",
|
|
||||||
"availability_zones.*",
|
|
||||||
"security_groups.*",
|
|
||||||
"subnets.*",
|
|
||||||
"health_check.#",
|
|
||||||
"health_check.0.healthy_threshold",
|
|
||||||
"health_check.0.unhealthy_threshold",
|
|
||||||
"health_check.0.interval",
|
|
||||||
"health_check.0.target",
|
|
||||||
"health_check.0.timeout",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,15 +38,6 @@ func init() {
|
||||||
Refresh: resource_aws_db_security_group_refresh,
|
Refresh: resource_aws_db_security_group_refresh,
|
||||||
},
|
},
|
||||||
|
|
||||||
"aws_elb": resource.Resource{
|
|
||||||
ConfigValidator: resource_aws_elb_validation(),
|
|
||||||
Create: resource_aws_elb_create,
|
|
||||||
Update: resource_aws_elb_update,
|
|
||||||
Destroy: resource_aws_elb_destroy,
|
|
||||||
Diff: resource_aws_elb_diff,
|
|
||||||
Refresh: resource_aws_elb_refresh,
|
|
||||||
},
|
|
||||||
|
|
||||||
"aws_internet_gateway": resource.Resource{
|
"aws_internet_gateway": resource.Resource{
|
||||||
Create: resource_aws_internet_gateway_create,
|
Create: resource_aws_internet_gateway_create,
|
||||||
Destroy: resource_aws_internet_gateway_destroy,
|
Destroy: resource_aws_internet_gateway_destroy,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/goamz/autoscaling"
|
"github.com/mitchellh/goamz/autoscaling"
|
||||||
|
@ -16,28 +15,20 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) {
|
||||||
|
|
||||||
// Loop over our configured listeners and create
|
// Loop over our configured listeners and create
|
||||||
// an array of goamz compatabile objects
|
// an array of goamz compatabile objects
|
||||||
for _, listener := range configured {
|
for _, lRaw := range configured {
|
||||||
newL := listener.(map[string]interface{})
|
data := lRaw.(map[string]interface{})
|
||||||
|
|
||||||
instancePort, err := strconv.ParseInt(newL["instance_port"].(string), 0, 0)
|
|
||||||
lbPort, err := strconv.ParseInt(newL["lb_port"].(string), 0, 0)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l := elb.Listener{
|
l := elb.Listener{
|
||||||
InstancePort: instancePort,
|
InstancePort: int64(data["instance_port"].(int)),
|
||||||
InstanceProtocol: newL["instance_protocol"].(string),
|
InstanceProtocol: data["instance_protocol"].(string),
|
||||||
LoadBalancerPort: lbPort,
|
LoadBalancerPort: int64(data["lb_port"].(int)),
|
||||||
Protocol: newL["lb_protocol"].(string),
|
Protocol: data["lb_protocol"].(string),
|
||||||
}
|
}
|
||||||
|
|
||||||
if attr, ok := newL["ssl_certificate_id"].(string); ok {
|
if v, ok := data["ssl_certificate_id"]; ok {
|
||||||
l.SSLCertificateId = attr
|
l.SSLCertificateId = v.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
listeners = append(listeners, l)
|
listeners = append(listeners, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,13 @@ func (d *ResourceData) getSet(
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the entire list is computed, then the entire set is
|
||||||
|
// necessarilly computed.
|
||||||
|
if raw.Computed {
|
||||||
|
result.Computed = true
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
list := raw.Value.([]interface{})
|
list := raw.Value.([]interface{})
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
if len(parts) > 0 {
|
if len(parts) > 0 {
|
||||||
|
|
|
@ -641,6 +641,88 @@ func TestSchemaMap_Diff(t *testing.T) {
|
||||||
Err: false,
|
Err: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ports": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Required: true,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"ports": []interface{}{"${var.foo}", 1},
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigVariables: map[string]string{
|
||||||
|
"var.foo": "2" + config.InterpSplitDelim + "5",
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: &terraform.InstanceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"ports.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "0",
|
||||||
|
New: "3",
|
||||||
|
},
|
||||||
|
"ports.0": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "1",
|
||||||
|
},
|
||||||
|
"ports.1": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "2",
|
||||||
|
},
|
||||||
|
"ports.2": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"ports": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Required: true,
|
||||||
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
Set: func(a interface{}) int {
|
||||||
|
return a.(int)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"ports": []interface{}{1, "${var.foo}"},
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigVariables: map[string]string{
|
||||||
|
"var.foo": config.UnknownVariableValue +
|
||||||
|
config.InterpSplitDelim + "5",
|
||||||
|
},
|
||||||
|
|
||||||
|
Diff: &terraform.InstanceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"ports.#": &terraform.ResourceAttrDiff{
|
||||||
|
Old: "0",
|
||||||
|
New: "",
|
||||||
|
NewComputed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
|
Loading…
Reference in New Issue