github.com/arvindram03/terraform@v0.3.7-0.20150212015210-408f838db36d/builtin/providers/aws/resource_aws_elb.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 8 "github.com/hashicorp/terraform/helper/hashcode" 9 "github.com/hashicorp/terraform/helper/schema" 10 "github.com/mitchellh/goamz/elb" 11 ) 12 13 func resourceAwsElb() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceAwsElbCreate, 16 Read: resourceAwsElbRead, 17 Update: resourceAwsElbUpdate, 18 Delete: resourceAwsElbDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "name": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 }, 26 27 "internal": &schema.Schema{ 28 Type: schema.TypeBool, 29 Optional: true, 30 ForceNew: true, 31 Computed: true, 32 }, 33 34 "cross_zone_load_balancing": &schema.Schema{ 35 Type: schema.TypeBool, 36 Optional: true, 37 }, 38 39 "availability_zones": &schema.Schema{ 40 Type: schema.TypeSet, 41 Elem: &schema.Schema{Type: schema.TypeString}, 42 Optional: true, 43 ForceNew: true, 44 Computed: true, 45 Set: func(v interface{}) int { 46 return hashcode.String(v.(string)) 47 }, 48 }, 49 50 "instances": &schema.Schema{ 51 Type: schema.TypeSet, 52 Elem: &schema.Schema{Type: schema.TypeString}, 53 Optional: true, 54 Computed: true, 55 Set: func(v interface{}) int { 56 return hashcode.String(v.(string)) 57 }, 58 }, 59 60 // TODO: could be not ForceNew 61 "security_groups": &schema.Schema{ 62 Type: schema.TypeSet, 63 Elem: &schema.Schema{Type: schema.TypeString}, 64 Optional: true, 65 ForceNew: true, 66 Computed: true, 67 Set: func(v interface{}) int { 68 return hashcode.String(v.(string)) 69 }, 70 }, 71 72 "subnets": &schema.Schema{ 73 Type: schema.TypeSet, 74 Elem: &schema.Schema{Type: schema.TypeString}, 75 Optional: true, 76 Computed: true, 77 Set: func(v interface{}) int { 78 return hashcode.String(v.(string)) 79 }, 80 }, 81 82 // TODO: could be not ForceNew 83 "listener": &schema.Schema{ 84 Type: schema.TypeSet, 85 Required: true, 86 ForceNew: true, 87 Elem: &schema.Resource{ 88 Schema: map[string]*schema.Schema{ 89 "instance_port": &schema.Schema{ 90 Type: schema.TypeInt, 91 Required: true, 92 }, 93 94 "instance_protocol": &schema.Schema{ 95 Type: schema.TypeString, 96 Required: true, 97 }, 98 99 "lb_port": &schema.Schema{ 100 Type: schema.TypeInt, 101 Required: true, 102 }, 103 104 "lb_protocol": &schema.Schema{ 105 Type: schema.TypeString, 106 Required: true, 107 }, 108 109 "ssl_certificate_id": &schema.Schema{ 110 Type: schema.TypeString, 111 Optional: true, 112 }, 113 }, 114 }, 115 Set: resourceAwsElbListenerHash, 116 }, 117 118 // TODO: could be not ForceNew 119 "health_check": &schema.Schema{ 120 Type: schema.TypeSet, 121 Optional: true, 122 Computed: true, 123 Elem: &schema.Resource{ 124 Schema: map[string]*schema.Schema{ 125 "healthy_threshold": &schema.Schema{ 126 Type: schema.TypeInt, 127 Required: true, 128 }, 129 130 "unhealthy_threshold": &schema.Schema{ 131 Type: schema.TypeInt, 132 Required: true, 133 }, 134 135 "target": &schema.Schema{ 136 Type: schema.TypeString, 137 Required: true, 138 }, 139 140 "interval": &schema.Schema{ 141 Type: schema.TypeInt, 142 Required: true, 143 }, 144 145 "timeout": &schema.Schema{ 146 Type: schema.TypeInt, 147 Required: true, 148 }, 149 }, 150 }, 151 Set: resourceAwsElbHealthCheckHash, 152 }, 153 154 "dns_name": &schema.Schema{ 155 Type: schema.TypeString, 156 Computed: true, 157 }, 158 }, 159 } 160 } 161 162 func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { 163 elbconn := meta.(*AWSClient).elbconn 164 165 // Expand the "listener" set to goamz compat []elb.Listener 166 listeners, err := expandListeners(d.Get("listener").(*schema.Set).List()) 167 if err != nil { 168 return err 169 } 170 171 // Provision the elb 172 elbOpts := &elb.CreateLoadBalancer{ 173 LoadBalancerName: d.Get("name").(string), 174 Listeners: listeners, 175 Internal: d.Get("internal").(bool), 176 } 177 178 if v, ok := d.GetOk("availability_zones"); ok { 179 elbOpts.AvailZone = expandStringList(v.(*schema.Set).List()) 180 } 181 182 if v, ok := d.GetOk("security_groups"); ok { 183 elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List()) 184 } 185 186 if v, ok := d.GetOk("subnets"); ok { 187 elbOpts.Subnets = expandStringList(v.(*schema.Set).List()) 188 } 189 190 log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) 191 if _, err := elbconn.CreateLoadBalancer(elbOpts); err != nil { 192 return fmt.Errorf("Error creating ELB: %s", err) 193 } 194 195 // Assign the elb's unique identifier for use later 196 d.SetId(d.Get("name").(string)) 197 log.Printf("[INFO] ELB ID: %s", d.Id()) 198 199 // Enable partial mode and record what we set 200 d.Partial(true) 201 d.SetPartial("name") 202 d.SetPartial("internal") 203 d.SetPartial("availability_zones") 204 d.SetPartial("listener") 205 d.SetPartial("security_groups") 206 d.SetPartial("subnets") 207 208 if d.HasChange("health_check") { 209 vs := d.Get("health_check").(*schema.Set).List() 210 if len(vs) > 0 { 211 check := vs[0].(map[string]interface{}) 212 213 configureHealthCheckOpts := elb.ConfigureHealthCheck{ 214 LoadBalancerName: d.Id(), 215 Check: elb.HealthCheck{ 216 HealthyThreshold: int64(check["healthy_threshold"].(int)), 217 UnhealthyThreshold: int64(check["unhealthy_threshold"].(int)), 218 Interval: int64(check["interval"].(int)), 219 Target: check["target"].(string), 220 Timeout: int64(check["timeout"].(int)), 221 }, 222 } 223 224 _, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts) 225 if err != nil { 226 return fmt.Errorf("Failure configuring health check: %s", err) 227 } 228 } 229 } 230 231 return resourceAwsElbUpdate(d, meta) 232 } 233 234 func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { 235 elbconn := meta.(*AWSClient).elbconn 236 237 // Retrieve the ELB properties for updating the state 238 describeElbOpts := &elb.DescribeLoadBalancer{ 239 Names: []string{d.Id()}, 240 } 241 242 describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) 243 if err != nil { 244 if ec2err, ok := err.(*elb.Error); ok && ec2err.Code == "LoadBalancerNotFound" { 245 // The ELB is gone now, so just remove it from the state 246 d.SetId("") 247 return nil 248 } 249 250 return fmt.Errorf("Error retrieving ELB: %s", err) 251 } 252 if len(describeResp.LoadBalancers) != 1 { 253 return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers) 254 } 255 256 lb := describeResp.LoadBalancers[0] 257 258 d.Set("name", lb.LoadBalancerName) 259 d.Set("dns_name", lb.DNSName) 260 d.Set("internal", lb.Scheme == "internal") 261 d.Set("availability_zones", lb.AvailabilityZones) 262 d.Set("instances", flattenInstances(lb.Instances)) 263 d.Set("listener", flattenListeners(lb.Listeners)) 264 d.Set("security_groups", lb.SecurityGroups) 265 d.Set("subnets", lb.Subnets) 266 267 // There's only one health check, so save that to state as we 268 // currently can 269 if lb.HealthCheck.Target != "" { 270 d.Set("health_check", flattenHealthCheck(lb.HealthCheck)) 271 } 272 273 return nil 274 } 275 276 func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { 277 elbconn := meta.(*AWSClient).elbconn 278 279 d.Partial(true) 280 281 // If we currently have instances, or did have instances, 282 // we want to figure out what to add and remove from the load 283 // balancer 284 if d.HasChange("instances") { 285 o, n := d.GetChange("instances") 286 os := o.(*schema.Set) 287 ns := n.(*schema.Set) 288 remove := expandStringList(os.Difference(ns).List()) 289 add := expandStringList(ns.Difference(os).List()) 290 291 if len(add) > 0 { 292 registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{ 293 LoadBalancerName: d.Id(), 294 Instances: add, 295 } 296 297 _, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts) 298 if err != nil { 299 return fmt.Errorf("Failure registering instances: %s", err) 300 } 301 } 302 if len(remove) > 0 { 303 deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{ 304 LoadBalancerName: d.Id(), 305 Instances: remove, 306 } 307 308 _, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts) 309 if err != nil { 310 return fmt.Errorf("Failure deregistering instances: %s", err) 311 } 312 } 313 314 d.SetPartial("instances") 315 } 316 317 log.Println("[INFO] outside modify attributes") 318 if d.HasChange("cross_zone_load_balancing") { 319 log.Println("[INFO] inside modify attributes") 320 attrs := elb.ModifyLoadBalancerAttributes{ 321 LoadBalancerName: d.Get("name").(string), 322 LoadBalancerAttributes: elb.LoadBalancerAttributes{ 323 CrossZoneLoadBalancingEnabled: d.Get("cross_zone_load_balancing").(bool), 324 }, 325 } 326 _, err := elbconn.ModifyLoadBalancerAttributes(&attrs) 327 if err != nil { 328 return fmt.Errorf("Failure configuring cross zone balancing: %s", err) 329 } 330 d.SetPartial("cross_zone_load_balancing") 331 } 332 333 if d.HasChange("health_check") { 334 vs := d.Get("health_check").(*schema.Set).List() 335 if len(vs) > 0 { 336 check := vs[0].(map[string]interface{}) 337 configureHealthCheckOpts := elb.ConfigureHealthCheck{ 338 LoadBalancerName: d.Id(), 339 Check: elb.HealthCheck{ 340 HealthyThreshold: int64(check["healthy_threshold"].(int)), 341 UnhealthyThreshold: int64(check["unhealthy_threshold"].(int)), 342 Interval: int64(check["interval"].(int)), 343 Target: check["target"].(string), 344 Timeout: int64(check["timeout"].(int)), 345 }, 346 } 347 _, err := elbconn.ConfigureHealthCheck(&configureHealthCheckOpts) 348 if err != nil { 349 return fmt.Errorf("Failure configuring health check: %s", err) 350 } 351 d.SetPartial("health_check") 352 } 353 } 354 355 d.Partial(false) 356 return resourceAwsElbRead(d, meta) 357 } 358 359 func resourceAwsElbDelete(d *schema.ResourceData, meta interface{}) error { 360 elbconn := meta.(*AWSClient).elbconn 361 362 log.Printf("[INFO] Deleting ELB: %s", d.Id()) 363 364 // Destroy the load balancer 365 deleteElbOpts := elb.DeleteLoadBalancer{ 366 LoadBalancerName: d.Id(), 367 } 368 if _, err := elbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil { 369 return fmt.Errorf("Error deleting ELB: %s", err) 370 } 371 372 return nil 373 } 374 375 func resourceAwsElbHealthCheckHash(v interface{}) int { 376 var buf bytes.Buffer 377 m := v.(map[string]interface{}) 378 buf.WriteString(fmt.Sprintf("%d-", m["healthy_threshold"].(int))) 379 buf.WriteString(fmt.Sprintf("%d-", m["unhealthy_threshold"].(int))) 380 buf.WriteString(fmt.Sprintf("%s-", m["target"].(string))) 381 buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int))) 382 buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int))) 383 384 return hashcode.String(buf.String()) 385 } 386 387 func resourceAwsElbListenerHash(v interface{}) int { 388 var buf bytes.Buffer 389 m := v.(map[string]interface{}) 390 buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int))) 391 buf.WriteString(fmt.Sprintf("%s-", m["instance_protocol"].(string))) 392 buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int))) 393 buf.WriteString(fmt.Sprintf("%s-", m["lb_protocol"].(string))) 394 395 if v, ok := m["ssl_certificate_id"]; ok { 396 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 397 } 398 399 return hashcode.String(buf.String()) 400 }