github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/providers/aws/resource_aws_elb.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/terraform/flatmap"
     8  	"github.com/hashicorp/terraform/helper/config"
     9  	"github.com/hashicorp/terraform/helper/diff"
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"github.com/mitchellh/goamz/elb"
    12  )
    13  
    14  func resource_aws_elb_create(
    15  	s *terraform.ResourceState,
    16  	d *terraform.ResourceDiff,
    17  	meta interface{}) (*terraform.ResourceState, error) {
    18  	p := meta.(*ResourceProvider)
    19  	elbconn := p.elbconn
    20  
    21  	// Merge the diff into the state so that we have all the attributes
    22  	// properly.
    23  	rs := s.MergeDiff(d)
    24  
    25  	// The name specified for the ELB. This is also our unique ID
    26  	// we save to state if the creation is succesful (amazon verifies
    27  	// it is unique)
    28  	elbName := rs.Attributes["name"]
    29  
    30  	// Expand the "listener" array to goamz compat []elb.Listener
    31  	v := flatmap.Expand(rs.Attributes, "listener").([]interface{})
    32  	listeners, err := expandListeners(v)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	// Provision the elb
    38  	elbOpts := &elb.CreateLoadBalancer{
    39  		LoadBalancerName: elbName,
    40  		Listeners:        listeners,
    41  	}
    42  
    43  	if _, ok := rs.Attributes["availability_zones.#"]; ok {
    44  		v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{})
    45  		zones := expandStringList(v)
    46  		elbOpts.AvailZone = zones
    47  	}
    48  
    49  	log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)
    50  
    51  	_, err = elbconn.CreateLoadBalancer(elbOpts)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("Error creating ELB: %s", err)
    54  	}
    55  
    56  	// Assign the elb's unique identifer for use later
    57  	rs.ID = elbName
    58  	log.Printf("[INFO] ELB ID: %s", elbName)
    59  
    60  	if _, ok := rs.Attributes["instances.#"]; ok {
    61  		// If we have any instances, we need to register them
    62  		v = flatmap.Expand(rs.Attributes, "instances").([]interface{})
    63  		instances := expandStringList(v)
    64  
    65  		if len(instances) > 0 {
    66  			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
    67  				LoadBalancerName: elbName,
    68  				Instances:        instances,
    69  			}
    70  
    71  			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)
    72  
    73  			if err != nil {
    74  				return rs, fmt.Errorf("Failure registering instances: %s", err)
    75  			}
    76  		}
    77  	}
    78  
    79  	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
    80  	if err != nil {
    81  		return rs, err
    82  	}
    83  
    84  	return resource_aws_elb_update_state(rs, loadBalancer)
    85  }
    86  
    87  func resource_aws_elb_update(
    88  	s *terraform.ResourceState,
    89  	d *terraform.ResourceDiff,
    90  	meta interface{}) (*terraform.ResourceState, error) {
    91  	p := meta.(*ResourceProvider)
    92  	elbconn := p.elbconn
    93  
    94  	rs := s.MergeDiff(d)
    95  
    96  	// If we currently have instances, or did have instances,
    97  	// we want to figure out what to add and remove from the load
    98  	// balancer
    99  	if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" {
   100  		// The new state of instances merged with the diff
   101  		mergedInstances := expandStringList(flatmap.Expand(
   102  			rs.Attributes, "instances").([]interface{}))
   103  
   104  		// The state before the diff merge
   105  		previousInstances := expandStringList(flatmap.Expand(
   106  			s.Attributes, "instances").([]interface{}))
   107  
   108  		// keep track of what instances we are removing, and which
   109  		// we are adding
   110  		var toRemove []string
   111  		var toAdd []string
   112  
   113  		for _, instanceId := range mergedInstances {
   114  			for _, prevId := range previousInstances {
   115  				// If the merged instance ID existed
   116  				// previously, we don't have to do anything
   117  				if instanceId == prevId {
   118  					continue
   119  					// Otherwise, we need to add it to the load balancer
   120  				} else {
   121  					toAdd = append(toAdd, instanceId)
   122  				}
   123  			}
   124  		}
   125  
   126  		for i, instanceId := range toAdd {
   127  			for _, prevId := range previousInstances {
   128  				// If the instance ID we are adding existed
   129  				// previously, we want to not add it, but rather remove
   130  				// it
   131  				if instanceId == prevId {
   132  					toRemove = append(toRemove, instanceId)
   133  					toAdd = append(toAdd[:i], toAdd[i+1:]...)
   134  					// Otherwise, we continue adding it to the ELB
   135  				} else {
   136  					continue
   137  				}
   138  			}
   139  		}
   140  
   141  		if len(toAdd) > 0 {
   142  			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
   143  				LoadBalancerName: rs.ID,
   144  				Instances:        toAdd,
   145  			}
   146  
   147  			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)
   148  
   149  			if err != nil {
   150  				return s, fmt.Errorf("Failure registering instances: %s", err)
   151  			}
   152  		}
   153  
   154  		if len(toRemove) > 0 {
   155  			deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
   156  				LoadBalancerName: rs.ID,
   157  				Instances:        toRemove,
   158  			}
   159  
   160  			_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)
   161  
   162  			if err != nil {
   163  				return s, fmt.Errorf("Failure deregistering instances: %s", err)
   164  			}
   165  		}
   166  	}
   167  
   168  	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
   169  
   170  	if err != nil {
   171  		return s, err
   172  	}
   173  
   174  	return resource_aws_elb_update_state(rs, loadBalancer)
   175  }
   176  
   177  func resource_aws_elb_destroy(
   178  	s *terraform.ResourceState,
   179  	meta interface{}) error {
   180  	p := meta.(*ResourceProvider)
   181  	elbconn := p.elbconn
   182  
   183  	log.Printf("[INFO] Deleting ELB: %s", s.ID)
   184  
   185  	// Destroy the load balancer
   186  	deleteElbOpts := elb.DeleteLoadBalancer{
   187  		LoadBalancerName: s.ID,
   188  	}
   189  	_, err := elbconn.DeleteLoadBalancer(&deleteElbOpts)
   190  
   191  	if err != nil {
   192  		return fmt.Errorf("Error deleting ELB: %s", err)
   193  	}
   194  
   195  	return nil
   196  }
   197  
   198  func resource_aws_elb_refresh(
   199  	s *terraform.ResourceState,
   200  	meta interface{}) (*terraform.ResourceState, error) {
   201  	p := meta.(*ResourceProvider)
   202  	elbconn := p.elbconn
   203  
   204  	loadBalancer, err := resource_aws_elb_retrieve_balancer(s.ID, elbconn)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	return resource_aws_elb_update_state(s, loadBalancer)
   210  }
   211  
   212  func resource_aws_elb_diff(
   213  	s *terraform.ResourceState,
   214  	c *terraform.ResourceConfig,
   215  	meta interface{}) (*terraform.ResourceDiff, error) {
   216  
   217  	b := &diff.ResourceBuilder{
   218  		Attrs: map[string]diff.AttrType{
   219  			"name":              diff.AttrTypeCreate,
   220  			"availability_zone": diff.AttrTypeCreate,
   221  			"listener":          diff.AttrTypeCreate,
   222  			"instances":         diff.AttrTypeUpdate,
   223  		},
   224  
   225  		ComputedAttrs: []string{
   226  			"dns_name",
   227  		},
   228  	}
   229  
   230  	return b.Diff(s, c)
   231  }
   232  
   233  func resource_aws_elb_update_state(
   234  	s *terraform.ResourceState,
   235  	balancer *elb.LoadBalancer) (*terraform.ResourceState, error) {
   236  
   237  	s.Attributes["name"] = balancer.LoadBalancerName
   238  	s.Attributes["dns_name"] = balancer.DNSName
   239  
   240  	// Flatten our group values
   241  	toFlatten := make(map[string]interface{})
   242  
   243  	if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" {
   244  		toFlatten["instances"] = flattenInstances(balancer.Instances)
   245  		for k, v := range flatmap.Flatten(toFlatten) {
   246  			s.Attributes[k] = v
   247  		}
   248  	}
   249  
   250  	return s, nil
   251  }
   252  
   253  // retrieves an ELB by it's ID
   254  func resource_aws_elb_retrieve_balancer(id string, elbconn *elb.ELB) (*elb.LoadBalancer, error) {
   255  	describeElbOpts := &elb.DescribeLoadBalancer{
   256  		Names: []string{id},
   257  	}
   258  
   259  	// Retrieve the ELB properties for updating the state
   260  	describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
   261  	if err != nil {
   262  		return nil, fmt.Errorf("Error retrieving ELB: %s", err)
   263  	}
   264  
   265  	loadBalancer := describeResp.LoadBalancers[0]
   266  
   267  	// Verify AWS returned our ELB
   268  	if len(describeResp.LoadBalancers) != 1 ||
   269  		describeResp.LoadBalancers[0].LoadBalancerName != id {
   270  		if err != nil {
   271  			return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers)
   272  		}
   273  	}
   274  
   275  	return &loadBalancer, nil
   276  }
   277  
   278  func resource_aws_elb_validation() *config.Validator {
   279  	return &config.Validator{
   280  		Required: []string{
   281  			"name",
   282  			"listener.*",
   283  			"listener.*.instance_port",
   284  			"listener.*.instance_protocol",
   285  			"listener.*.lb_port",
   286  			"listener.*.lb_protocol",
   287  		},
   288  		Optional: []string{
   289  			"instances.*",
   290  			"availability_zones.*",
   291  		},
   292  	}
   293  }