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