github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_alb.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/service/elbv2" 10 "github.com/hashicorp/errwrap" 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 func resourceAwsAlb() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceAwsAlbCreate, 17 Read: resourceAwsAlbRead, 18 Update: resourceAwsAlbUpdate, 19 Delete: resourceAwsAlbDelete, 20 Importer: &schema.ResourceImporter{ 21 State: schema.ImportStatePassthrough, 22 }, 23 24 Schema: map[string]*schema.Schema{ 25 "arn": { 26 Type: schema.TypeString, 27 Computed: true, 28 }, 29 30 "name": { 31 Type: schema.TypeString, 32 Required: true, 33 ForceNew: true, 34 ValidateFunc: validateElbName, 35 }, 36 37 "internal": { 38 Type: schema.TypeBool, 39 Optional: true, 40 ForceNew: true, 41 Computed: true, 42 }, 43 44 "security_groups": { 45 Type: schema.TypeSet, 46 Elem: &schema.Schema{Type: schema.TypeString}, 47 Computed: true, 48 ForceNew: true, 49 Optional: true, 50 Set: schema.HashString, 51 }, 52 53 "subnets": { 54 Type: schema.TypeSet, 55 Elem: &schema.Schema{Type: schema.TypeString}, 56 ForceNew: true, 57 Required: true, 58 Set: schema.HashString, 59 }, 60 61 "access_logs": { 62 Type: schema.TypeList, 63 Optional: true, 64 MaxItems: 1, 65 Elem: &schema.Resource{ 66 Schema: map[string]*schema.Schema{ 67 "bucket": { 68 Type: schema.TypeString, 69 Required: true, 70 }, 71 "prefix": { 72 Type: schema.TypeString, 73 Optional: true, 74 }, 75 }, 76 }, 77 }, 78 79 "enable_deletion_protection": { 80 Type: schema.TypeBool, 81 Optional: true, 82 Default: false, 83 }, 84 85 "idle_timeout": { 86 Type: schema.TypeInt, 87 Optional: true, 88 Default: 60, 89 }, 90 91 "vpc_id": { 92 Type: schema.TypeString, 93 Computed: true, 94 }, 95 96 "zone_id": { 97 Type: schema.TypeString, 98 Computed: true, 99 }, 100 101 "dns_name": { 102 Type: schema.TypeString, 103 Computed: true, 104 }, 105 106 "tags": tagsSchema(), 107 }, 108 } 109 } 110 111 func resourceAwsAlbCreate(d *schema.ResourceData, meta interface{}) error { 112 elbconn := meta.(*AWSClient).elbv2conn 113 114 elbOpts := &elbv2.CreateLoadBalancerInput{ 115 Name: aws.String(d.Get("name").(string)), 116 Tags: tagsFromMapELBv2(d.Get("tags").(map[string]interface{})), 117 } 118 119 if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) { 120 elbOpts.Scheme = aws.String("internal") 121 } 122 123 if v, ok := d.GetOk("security_groups"); ok { 124 elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List()) 125 } 126 127 if v, ok := d.GetOk("subnets"); ok { 128 elbOpts.Subnets = expandStringList(v.(*schema.Set).List()) 129 } 130 131 log.Printf("[DEBUG] ALB create configuration: %#v", elbOpts) 132 133 resp, err := elbconn.CreateLoadBalancer(elbOpts) 134 if err != nil { 135 return errwrap.Wrapf("Error creating Application Load Balancer: {{err}}", err) 136 } 137 138 if len(resp.LoadBalancers) != 1 { 139 return fmt.Errorf("No load balancers returned following creation of %s", d.Get("name").(string)) 140 } 141 142 d.SetId(*resp.LoadBalancers[0].LoadBalancerArn) 143 log.Printf("[INFO] ALB ID: %s", d.Id()) 144 145 return resourceAwsAlbUpdate(d, meta) 146 } 147 148 func resourceAwsAlbRead(d *schema.ResourceData, meta interface{}) error { 149 elbconn := meta.(*AWSClient).elbv2conn 150 albArn := d.Id() 151 152 describeAlbOpts := &elbv2.DescribeLoadBalancersInput{ 153 LoadBalancerArns: []*string{aws.String(albArn)}, 154 } 155 156 describeResp, err := elbconn.DescribeLoadBalancers(describeAlbOpts) 157 if err != nil { 158 if isLoadBalancerNotFound(err) { 159 // The ALB is gone now, so just remove it from the state 160 log.Printf("[WARN] ALB %s not found in AWS, removing from state", d.Id()) 161 d.SetId("") 162 return nil 163 } 164 165 return errwrap.Wrapf("Error retrieving ALB: {{err}}", err) 166 } 167 if len(describeResp.LoadBalancers) != 1 { 168 return fmt.Errorf("Unable to find ALB: %#v", describeResp.LoadBalancers) 169 } 170 171 alb := describeResp.LoadBalancers[0] 172 173 d.Set("arn", alb.LoadBalancerArn) 174 d.Set("name", alb.LoadBalancerName) 175 d.Set("internal", (alb.Scheme != nil && *alb.Scheme == "internal")) 176 d.Set("security_groups", flattenStringList(alb.SecurityGroups)) 177 d.Set("subnets", flattenSubnetsFromAvailabilityZones(alb.AvailabilityZones)) 178 d.Set("vpc_id", alb.VpcId) 179 d.Set("zone_id", alb.CanonicalHostedZoneId) 180 d.Set("dns_name", alb.DNSName) 181 182 respTags, err := elbconn.DescribeTags(&elbv2.DescribeTagsInput{ 183 ResourceArns: []*string{alb.LoadBalancerArn}, 184 }) 185 if err != nil { 186 return errwrap.Wrapf("Error retrieving ALB Tags: {{err}}", err) 187 } 188 189 var et []*elbv2.Tag 190 if len(respTags.TagDescriptions) > 0 { 191 et = respTags.TagDescriptions[0].Tags 192 } 193 d.Set("tags", tagsToMapELBv2(et)) 194 195 attributesResp, err := elbconn.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ 196 LoadBalancerArn: aws.String(d.Id()), 197 }) 198 if err != nil { 199 return errwrap.Wrapf("Error retrieving ALB Attributes: {{err}}", err) 200 } 201 202 accessLogMap := map[string]interface{}{} 203 for _, attr := range attributesResp.Attributes { 204 switch *attr.Key { 205 case "access_logs.s3.bucket": 206 accessLogMap["bucket"] = *attr.Value 207 case "access_logs.s3.prefix": 208 accessLogMap["prefix"] = *attr.Value 209 case "idle_timeout.timeout_seconds": 210 timeout, err := strconv.Atoi(*attr.Value) 211 if err != nil { 212 return errwrap.Wrapf("Error parsing ALB timeout: {{err}}", err) 213 } 214 log.Printf("[DEBUG] Setting ALB Timeout Seconds: %d", timeout) 215 d.Set("idle_timeout", timeout) 216 case "deletion_protection.enabled": 217 protectionEnabled := (*attr.Value) == "true" 218 log.Printf("[DEBUG] Setting ALB Deletion Protection Enabled: %t", protectionEnabled) 219 d.Set("enable_deletion_protection", protectionEnabled) 220 } 221 } 222 223 log.Printf("[DEBUG] Setting ALB Access Logs: %#v", accessLogMap) 224 if accessLogMap["bucket"] != "" || accessLogMap["prefix"] != "" { 225 d.Set("access_logs", []interface{}{accessLogMap}) 226 } else { 227 d.Set("access_logs", []interface{}{}) 228 } 229 230 return nil 231 } 232 233 func resourceAwsAlbUpdate(d *schema.ResourceData, meta interface{}) error { 234 elbconn := meta.(*AWSClient).elbv2conn 235 236 if !d.IsNewResource() { 237 if err := setElbV2Tags(elbconn, d); err != nil { 238 return errwrap.Wrapf("Error Modifying Tags on ALB: {{err}}", err) 239 } 240 } 241 242 attributes := make([]*elbv2.LoadBalancerAttribute, 0) 243 244 if d.HasChange("access_logs") { 245 logs := d.Get("access_logs").([]interface{}) 246 if len(logs) == 1 { 247 log := logs[0].(map[string]interface{}) 248 249 attributes = append(attributes, 250 &elbv2.LoadBalancerAttribute{ 251 Key: aws.String("access_logs.s3.enabled"), 252 Value: aws.String("true"), 253 }, 254 &elbv2.LoadBalancerAttribute{ 255 Key: aws.String("access_logs.s3.bucket"), 256 Value: aws.String(log["bucket"].(string)), 257 }) 258 259 if prefix, ok := log["prefix"]; ok { 260 attributes = append(attributes, &elbv2.LoadBalancerAttribute{ 261 Key: aws.String("access_logs.s3.prefix"), 262 Value: aws.String(prefix.(string)), 263 }) 264 } 265 } else if len(logs) == 0 { 266 attributes = append(attributes, &elbv2.LoadBalancerAttribute{ 267 Key: aws.String("access_logs.s3.enabled"), 268 Value: aws.String("false"), 269 }) 270 } 271 } 272 273 if d.HasChange("enable_deletion_protection") { 274 attributes = append(attributes, &elbv2.LoadBalancerAttribute{ 275 Key: aws.String("deletion_protection.enabled"), 276 Value: aws.String(fmt.Sprintf("%t", d.Get("enable_deletion_protection").(bool))), 277 }) 278 } 279 280 if d.HasChange("idle_timeout") { 281 attributes = append(attributes, &elbv2.LoadBalancerAttribute{ 282 Key: aws.String("idle_timeout.timeout_seconds"), 283 Value: aws.String(fmt.Sprintf("%d", d.Get("idle_timeout").(int))), 284 }) 285 } 286 287 if len(attributes) != 0 { 288 input := &elbv2.ModifyLoadBalancerAttributesInput{ 289 LoadBalancerArn: aws.String(d.Id()), 290 Attributes: attributes, 291 } 292 293 log.Printf("[DEBUG] ALB Modify Load Balancer Attributes Request: %#v", input) 294 _, err := elbconn.ModifyLoadBalancerAttributes(input) 295 if err != nil { 296 return fmt.Errorf("Failure configuring ALB attributes: %s", err) 297 } 298 } 299 300 return resourceAwsAlbRead(d, meta) 301 } 302 303 func resourceAwsAlbDelete(d *schema.ResourceData, meta interface{}) error { 304 albconn := meta.(*AWSClient).elbv2conn 305 306 log.Printf("[INFO] Deleting ALB: %s", d.Id()) 307 308 // Destroy the load balancer 309 deleteElbOpts := elbv2.DeleteLoadBalancerInput{ 310 LoadBalancerArn: aws.String(d.Id()), 311 } 312 if _, err := albconn.DeleteLoadBalancer(&deleteElbOpts); err != nil { 313 return fmt.Errorf("Error deleting ALB: %s", err) 314 } 315 316 return nil 317 } 318 319 // flattenSubnetsFromAvailabilityZones creates a slice of strings containing the subnet IDs 320 // for the ALB based on the AvailabilityZones structure returned by the API. 321 func flattenSubnetsFromAvailabilityZones(availabilityZones []*elbv2.AvailabilityZone) []string { 322 var result []string 323 for _, az := range availabilityZones { 324 result = append(result, *az.SubnetId) 325 } 326 return result 327 }