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(®isterInstancesOpts) 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(®isterInstancesOpts) 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 }