github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/builtin/providers/aws/structure.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "reflect" 8 "sort" 9 "strconv" 10 "strings" 11 12 "github.com/aws/aws-sdk-go/aws" 13 "github.com/aws/aws-sdk-go/service/apigateway" 14 "github.com/aws/aws-sdk-go/service/autoscaling" 15 "github.com/aws/aws-sdk-go/service/cloudformation" 16 "github.com/aws/aws-sdk-go/service/cloudwatchlogs" 17 "github.com/aws/aws-sdk-go/service/directoryservice" 18 "github.com/aws/aws-sdk-go/service/ec2" 19 "github.com/aws/aws-sdk-go/service/ecs" 20 "github.com/aws/aws-sdk-go/service/elasticache" 21 "github.com/aws/aws-sdk-go/service/elasticbeanstalk" 22 elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" 23 "github.com/aws/aws-sdk-go/service/elb" 24 "github.com/aws/aws-sdk-go/service/kinesis" 25 "github.com/aws/aws-sdk-go/service/lambda" 26 "github.com/aws/aws-sdk-go/service/rds" 27 "github.com/aws/aws-sdk-go/service/redshift" 28 "github.com/aws/aws-sdk-go/service/route53" 29 "github.com/hashicorp/terraform/helper/schema" 30 ) 31 32 // Takes the result of flatmap.Expand for an array of listeners and 33 // returns ELB API compatible objects 34 func expandListeners(configured []interface{}) ([]*elb.Listener, error) { 35 listeners := make([]*elb.Listener, 0, len(configured)) 36 37 // Loop over our configured listeners and create 38 // an array of aws-sdk-go compatabile objects 39 for _, lRaw := range configured { 40 data := lRaw.(map[string]interface{}) 41 42 ip := int64(data["instance_port"].(int)) 43 lp := int64(data["lb_port"].(int)) 44 l := &elb.Listener{ 45 InstancePort: &ip, 46 InstanceProtocol: aws.String(data["instance_protocol"].(string)), 47 LoadBalancerPort: &lp, 48 Protocol: aws.String(data["lb_protocol"].(string)), 49 } 50 51 if v, ok := data["ssl_certificate_id"]; ok { 52 l.SSLCertificateId = aws.String(v.(string)) 53 } 54 55 var valid bool 56 if l.SSLCertificateId != nil && *l.SSLCertificateId != "" { 57 // validate the protocol is correct 58 for _, p := range []string{"https", "ssl"} { 59 if (strings.ToLower(*l.InstanceProtocol) == p) || (strings.ToLower(*l.Protocol) == p) { 60 valid = true 61 } 62 } 63 } else { 64 valid = true 65 } 66 67 if valid { 68 listeners = append(listeners, l) 69 } else { 70 return nil, fmt.Errorf("[ERR] ELB Listener: ssl_certificate_id may be set only when protocol is 'https' or 'ssl'") 71 } 72 } 73 74 return listeners, nil 75 } 76 77 // Takes the result of flatmap. Expand for an array of listeners and 78 // returns ECS Volume compatible objects 79 func expandEcsVolumes(configured []interface{}) ([]*ecs.Volume, error) { 80 volumes := make([]*ecs.Volume, 0, len(configured)) 81 82 // Loop over our configured volumes and create 83 // an array of aws-sdk-go compatible objects 84 for _, lRaw := range configured { 85 data := lRaw.(map[string]interface{}) 86 87 l := &ecs.Volume{ 88 Name: aws.String(data["name"].(string)), 89 } 90 91 hostPath := data["host_path"].(string) 92 if hostPath != "" { 93 l.Host = &ecs.HostVolumeProperties{ 94 SourcePath: aws.String(hostPath), 95 } 96 } 97 98 volumes = append(volumes, l) 99 } 100 101 return volumes, nil 102 } 103 104 // Takes JSON in a string. Decodes JSON into 105 // an array of ecs.ContainerDefinition compatible objects 106 func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { 107 var definitions []*ecs.ContainerDefinition 108 109 err := json.Unmarshal([]byte(rawDefinitions), &definitions) 110 if err != nil { 111 return nil, fmt.Errorf("Error decoding JSON: %s", err) 112 } 113 114 return definitions, nil 115 } 116 117 // Takes the result of flatmap. Expand for an array of load balancers and 118 // returns ecs.LoadBalancer compatible objects 119 func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer { 120 loadBalancers := make([]*ecs.LoadBalancer, 0, len(configured)) 121 122 // Loop over our configured load balancers and create 123 // an array of aws-sdk-go compatible objects 124 for _, lRaw := range configured { 125 data := lRaw.(map[string]interface{}) 126 127 l := &ecs.LoadBalancer{ 128 ContainerName: aws.String(data["container_name"].(string)), 129 ContainerPort: aws.Int64(int64(data["container_port"].(int))), 130 } 131 132 if v, ok := data["elb_name"]; ok && v.(string) != "" { 133 l.LoadBalancerName = aws.String(v.(string)) 134 } 135 if v, ok := data["target_group_arn"]; ok && v.(string) != "" { 136 l.TargetGroupArn = aws.String(v.(string)) 137 } 138 139 loadBalancers = append(loadBalancers, l) 140 } 141 142 return loadBalancers 143 } 144 145 // Takes the result of flatmap.Expand for an array of ingress/egress security 146 // group rules and returns EC2 API compatible objects. This function will error 147 // if it finds invalid permissions input, namely a protocol of "-1" with either 148 // to_port or from_port set to a non-zero value. 149 func expandIPPerms( 150 group *ec2.SecurityGroup, configured []interface{}) ([]*ec2.IpPermission, error) { 151 vpc := group.VpcId != nil && *group.VpcId != "" 152 153 perms := make([]*ec2.IpPermission, len(configured)) 154 for i, mRaw := range configured { 155 var perm ec2.IpPermission 156 m := mRaw.(map[string]interface{}) 157 158 perm.FromPort = aws.Int64(int64(m["from_port"].(int))) 159 perm.ToPort = aws.Int64(int64(m["to_port"].(int))) 160 perm.IpProtocol = aws.String(m["protocol"].(string)) 161 162 // When protocol is "-1", AWS won't store any ports for the 163 // rule, but also won't error if the user specifies ports other 164 // than '0'. Force the user to make a deliberate '0' port 165 // choice when specifying a "-1" protocol, and tell them about 166 // AWS's behavior in the error message. 167 if *perm.IpProtocol == "-1" && (*perm.FromPort != 0 || *perm.ToPort != 0) { 168 return nil, fmt.Errorf( 169 "from_port (%d) and to_port (%d) must both be 0 to use the the 'ALL' \"-1\" protocol!", 170 *perm.FromPort, *perm.ToPort) 171 } 172 173 var groups []string 174 if raw, ok := m["security_groups"]; ok { 175 list := raw.(*schema.Set).List() 176 for _, v := range list { 177 groups = append(groups, v.(string)) 178 } 179 } 180 if v, ok := m["self"]; ok && v.(bool) { 181 if vpc { 182 groups = append(groups, *group.GroupId) 183 } else { 184 groups = append(groups, *group.GroupName) 185 } 186 } 187 188 if len(groups) > 0 { 189 perm.UserIdGroupPairs = make([]*ec2.UserIdGroupPair, len(groups)) 190 for i, name := range groups { 191 ownerId, id := "", name 192 if items := strings.Split(id, "/"); len(items) > 1 { 193 ownerId, id = items[0], items[1] 194 } 195 196 perm.UserIdGroupPairs[i] = &ec2.UserIdGroupPair{ 197 GroupId: aws.String(id), 198 } 199 200 if ownerId != "" { 201 perm.UserIdGroupPairs[i].UserId = aws.String(ownerId) 202 } 203 204 if !vpc { 205 perm.UserIdGroupPairs[i].GroupId = nil 206 perm.UserIdGroupPairs[i].GroupName = aws.String(id) 207 } 208 } 209 } 210 211 if raw, ok := m["cidr_blocks"]; ok { 212 list := raw.([]interface{}) 213 for _, v := range list { 214 perm.IpRanges = append(perm.IpRanges, &ec2.IpRange{CidrIp: aws.String(v.(string))}) 215 } 216 } 217 218 if raw, ok := m["prefix_list_ids"]; ok { 219 list := raw.([]interface{}) 220 for _, v := range list { 221 perm.PrefixListIds = append(perm.PrefixListIds, &ec2.PrefixListId{PrefixListId: aws.String(v.(string))}) 222 } 223 } 224 225 perms[i] = &perm 226 } 227 228 return perms, nil 229 } 230 231 // Takes the result of flatmap.Expand for an array of parameters and 232 // returns Parameter API compatible objects 233 func expandParameters(configured []interface{}) ([]*rds.Parameter, error) { 234 var parameters []*rds.Parameter 235 236 // Loop over our configured parameters and create 237 // an array of aws-sdk-go compatabile objects 238 for _, pRaw := range configured { 239 data := pRaw.(map[string]interface{}) 240 241 if data["name"].(string) == "" { 242 continue 243 } 244 245 p := &rds.Parameter{ 246 ApplyMethod: aws.String(data["apply_method"].(string)), 247 ParameterName: aws.String(data["name"].(string)), 248 ParameterValue: aws.String(data["value"].(string)), 249 } 250 251 parameters = append(parameters, p) 252 } 253 254 return parameters, nil 255 } 256 257 func expandRedshiftParameters(configured []interface{}) ([]*redshift.Parameter, error) { 258 var parameters []*redshift.Parameter 259 260 // Loop over our configured parameters and create 261 // an array of aws-sdk-go compatabile objects 262 for _, pRaw := range configured { 263 data := pRaw.(map[string]interface{}) 264 265 if data["name"].(string) == "" { 266 continue 267 } 268 269 p := &redshift.Parameter{ 270 ParameterName: aws.String(data["name"].(string)), 271 ParameterValue: aws.String(data["value"].(string)), 272 } 273 274 parameters = append(parameters, p) 275 } 276 277 return parameters, nil 278 } 279 280 func expandOptionConfiguration(configured []interface{}) ([]*rds.OptionConfiguration, error) { 281 var option []*rds.OptionConfiguration 282 283 for _, pRaw := range configured { 284 data := pRaw.(map[string]interface{}) 285 286 o := &rds.OptionConfiguration{ 287 OptionName: aws.String(data["option_name"].(string)), 288 } 289 290 if raw, ok := data["port"]; ok { 291 port := raw.(int) 292 if port != 0 { 293 o.Port = aws.Int64(int64(port)) 294 } 295 } 296 297 if raw, ok := data["db_security_group_memberships"]; ok { 298 memberships := expandStringList(raw.(*schema.Set).List()) 299 if len(memberships) > 0 { 300 o.DBSecurityGroupMemberships = memberships 301 } 302 } 303 304 if raw, ok := data["vpc_security_group_memberships"]; ok { 305 memberships := expandStringList(raw.(*schema.Set).List()) 306 if len(memberships) > 0 { 307 o.VpcSecurityGroupMemberships = memberships 308 } 309 } 310 311 if raw, ok := data["option_settings"]; ok { 312 o.OptionSettings = expandOptionSetting(raw.(*schema.Set).List()) 313 } 314 315 option = append(option, o) 316 } 317 318 return option, nil 319 } 320 321 func expandOptionSetting(list []interface{}) []*rds.OptionSetting { 322 options := make([]*rds.OptionSetting, 0, len(list)) 323 324 for _, oRaw := range list { 325 data := oRaw.(map[string]interface{}) 326 327 o := &rds.OptionSetting{ 328 Name: aws.String(data["name"].(string)), 329 Value: aws.String(data["value"].(string)), 330 } 331 332 options = append(options, o) 333 } 334 335 return options 336 } 337 338 // Takes the result of flatmap.Expand for an array of parameters and 339 // returns Parameter API compatible objects 340 func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) { 341 parameters := make([]*elasticache.ParameterNameValue, 0, len(configured)) 342 343 // Loop over our configured parameters and create 344 // an array of aws-sdk-go compatabile objects 345 for _, pRaw := range configured { 346 data := pRaw.(map[string]interface{}) 347 348 p := &elasticache.ParameterNameValue{ 349 ParameterName: aws.String(data["name"].(string)), 350 ParameterValue: aws.String(data["value"].(string)), 351 } 352 353 parameters = append(parameters, p) 354 } 355 356 return parameters, nil 357 } 358 359 // Flattens an access log into something that flatmap.Flatten() can handle 360 func flattenAccessLog(l *elb.AccessLog) []map[string]interface{} { 361 result := make([]map[string]interface{}, 0, 1) 362 363 if l != nil && *l.Enabled { 364 r := make(map[string]interface{}) 365 if l.S3BucketName != nil { 366 r["bucket"] = *l.S3BucketName 367 } 368 369 if l.S3BucketPrefix != nil { 370 r["bucket_prefix"] = *l.S3BucketPrefix 371 } 372 373 if l.EmitInterval != nil { 374 r["interval"] = *l.EmitInterval 375 } 376 377 result = append(result, r) 378 } 379 380 return result 381 } 382 383 // Takes the result of flatmap.Expand for an array of step adjustments and 384 // returns a []*autoscaling.StepAdjustment. 385 func expandStepAdjustments(configured []interface{}) ([]*autoscaling.StepAdjustment, error) { 386 var adjustments []*autoscaling.StepAdjustment 387 388 // Loop over our configured step adjustments and create an array 389 // of aws-sdk-go compatible objects. We're forced to convert strings 390 // to floats here because there's no way to detect whether or not 391 // an uninitialized, optional schema element is "0.0" deliberately. 392 // With strings, we can test for "", which is definitely an empty 393 // struct value. 394 for _, raw := range configured { 395 data := raw.(map[string]interface{}) 396 a := &autoscaling.StepAdjustment{ 397 ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))), 398 } 399 if data["metric_interval_lower_bound"] != "" { 400 bound := data["metric_interval_lower_bound"] 401 switch bound := bound.(type) { 402 case string: 403 f, err := strconv.ParseFloat(bound, 64) 404 if err != nil { 405 return nil, fmt.Errorf( 406 "metric_interval_lower_bound must be a float value represented as a string") 407 } 408 a.MetricIntervalLowerBound = aws.Float64(f) 409 default: 410 return nil, fmt.Errorf( 411 "metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.") 412 } 413 } 414 if data["metric_interval_upper_bound"] != "" { 415 bound := data["metric_interval_upper_bound"] 416 switch bound := bound.(type) { 417 case string: 418 f, err := strconv.ParseFloat(bound, 64) 419 if err != nil { 420 return nil, fmt.Errorf( 421 "metric_interval_upper_bound must be a float value represented as a string") 422 } 423 a.MetricIntervalUpperBound = aws.Float64(f) 424 default: 425 return nil, fmt.Errorf( 426 "metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.") 427 } 428 } 429 adjustments = append(adjustments, a) 430 } 431 432 return adjustments, nil 433 } 434 435 // Flattens a health check into something that flatmap.Flatten() 436 // can handle 437 func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} { 438 result := make([]map[string]interface{}, 0, 1) 439 440 chk := make(map[string]interface{}) 441 chk["unhealthy_threshold"] = *check.UnhealthyThreshold 442 chk["healthy_threshold"] = *check.HealthyThreshold 443 chk["target"] = *check.Target 444 chk["timeout"] = *check.Timeout 445 chk["interval"] = *check.Interval 446 447 result = append(result, chk) 448 449 return result 450 } 451 452 // Flattens an array of UserSecurityGroups into a []*ec2.GroupIdentifier 453 func flattenSecurityGroups(list []*ec2.UserIdGroupPair, ownerId *string) []*ec2.GroupIdentifier { 454 result := make([]*ec2.GroupIdentifier, 0, len(list)) 455 for _, g := range list { 456 var userId *string 457 if g.UserId != nil && *g.UserId != "" && (ownerId == nil || *ownerId != *g.UserId) { 458 userId = g.UserId 459 } 460 // userid nil here for same vpc groups 461 462 vpc := g.GroupName == nil || *g.GroupName == "" 463 var id *string 464 if vpc { 465 id = g.GroupId 466 } else { 467 id = g.GroupName 468 } 469 470 // id is groupid for vpcs 471 // id is groupname for non vpc (classic) 472 473 if userId != nil { 474 id = aws.String(*userId + "/" + *id) 475 } 476 477 if vpc { 478 result = append(result, &ec2.GroupIdentifier{ 479 GroupId: id, 480 }) 481 } else { 482 result = append(result, &ec2.GroupIdentifier{ 483 GroupId: g.GroupId, 484 GroupName: id, 485 }) 486 } 487 } 488 return result 489 } 490 491 // Flattens an array of Instances into a []string 492 func flattenInstances(list []*elb.Instance) []string { 493 result := make([]string, 0, len(list)) 494 for _, i := range list { 495 result = append(result, *i.InstanceId) 496 } 497 return result 498 } 499 500 // Expands an array of String Instance IDs into a []Instances 501 func expandInstanceString(list []interface{}) []*elb.Instance { 502 result := make([]*elb.Instance, 0, len(list)) 503 for _, i := range list { 504 result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))}) 505 } 506 return result 507 } 508 509 // Flattens an array of Backend Descriptions into a a map of instance_port to policy names. 510 func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string { 511 policies := make(map[int64][]string) 512 for _, i := range backends { 513 for _, p := range i.PolicyNames { 514 policies[*i.InstancePort] = append(policies[*i.InstancePort], *p) 515 } 516 sort.Strings(policies[*i.InstancePort]) 517 } 518 return policies 519 } 520 521 // Flattens an array of Listeners into a []map[string]interface{} 522 func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} { 523 result := make([]map[string]interface{}, 0, len(list)) 524 for _, i := range list { 525 l := map[string]interface{}{ 526 "instance_port": *i.Listener.InstancePort, 527 "instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol), 528 "lb_port": *i.Listener.LoadBalancerPort, 529 "lb_protocol": strings.ToLower(*i.Listener.Protocol), 530 } 531 // SSLCertificateID is optional, and may be nil 532 if i.Listener.SSLCertificateId != nil { 533 l["ssl_certificate_id"] = *i.Listener.SSLCertificateId 534 } 535 result = append(result, l) 536 } 537 return result 538 } 539 540 // Flattens an array of Volumes into a []map[string]interface{} 541 func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { 542 result := make([]map[string]interface{}, 0, len(list)) 543 for _, volume := range list { 544 l := map[string]interface{}{ 545 "name": *volume.Name, 546 } 547 548 if volume.Host.SourcePath != nil { 549 l["host_path"] = *volume.Host.SourcePath 550 } 551 552 result = append(result, l) 553 } 554 return result 555 } 556 557 // Flattens an array of ECS LoadBalancers into a []map[string]interface{} 558 func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} { 559 result := make([]map[string]interface{}, 0, len(list)) 560 for _, loadBalancer := range list { 561 l := map[string]interface{}{ 562 "container_name": *loadBalancer.ContainerName, 563 "container_port": *loadBalancer.ContainerPort, 564 } 565 566 if loadBalancer.LoadBalancerName != nil { 567 l["elb_name"] = *loadBalancer.LoadBalancerName 568 } 569 570 if loadBalancer.TargetGroupArn != nil { 571 l["target_group_arn"] = *loadBalancer.TargetGroupArn 572 } 573 574 result = append(result, l) 575 } 576 return result 577 } 578 579 // Encodes an array of ecs.ContainerDefinitions into a JSON string 580 func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { 581 byteArray, err := json.Marshal(definitions) 582 if err != nil { 583 return "", fmt.Errorf("Error encoding to JSON: %s", err) 584 } 585 586 n := bytes.Index(byteArray, []byte{0}) 587 return string(byteArray[:n]), nil 588 } 589 590 // Flattens an array of Options into a []map[string]interface{} 591 func flattenOptions(list []*rds.Option) []map[string]interface{} { 592 result := make([]map[string]interface{}, 0, len(list)) 593 for _, i := range list { 594 if i.OptionName != nil { 595 r := make(map[string]interface{}) 596 r["option_name"] = strings.ToLower(*i.OptionName) 597 // Default empty string, guard against nil parameter values 598 r["port"] = "" 599 if i.Port != nil { 600 r["port"] = int(*i.Port) 601 } 602 if i.VpcSecurityGroupMemberships != nil { 603 vpcs := make([]string, 0, len(i.VpcSecurityGroupMemberships)) 604 for _, vpc := range i.VpcSecurityGroupMemberships { 605 id := vpc.VpcSecurityGroupId 606 vpcs = append(vpcs, *id) 607 } 608 609 r["vpc_security_group_memberships"] = vpcs 610 } 611 if i.DBSecurityGroupMemberships != nil { 612 dbs := make([]string, 0, len(i.DBSecurityGroupMemberships)) 613 for _, db := range i.DBSecurityGroupMemberships { 614 id := db.DBSecurityGroupName 615 dbs = append(dbs, *id) 616 } 617 618 r["db_security_group_memberships"] = dbs 619 } 620 if i.OptionSettings != nil { 621 settings := make([]map[string]interface{}, 0, len(i.OptionSettings)) 622 for _, j := range i.OptionSettings { 623 settings = append(settings, map[string]interface{}{ 624 "name": *j.Name, 625 "value": *j.Value, 626 }) 627 } 628 629 r["option_settings"] = settings 630 } 631 result = append(result, r) 632 } 633 } 634 return result 635 } 636 637 // Flattens an array of Parameters into a []map[string]interface{} 638 func flattenParameters(list []*rds.Parameter) []map[string]interface{} { 639 result := make([]map[string]interface{}, 0, len(list)) 640 for _, i := range list { 641 if i.ParameterName != nil { 642 r := make(map[string]interface{}) 643 r["name"] = strings.ToLower(*i.ParameterName) 644 // Default empty string, guard against nil parameter values 645 r["value"] = "" 646 if i.ParameterValue != nil { 647 r["value"] = strings.ToLower(*i.ParameterValue) 648 } 649 result = append(result, r) 650 } 651 } 652 return result 653 } 654 655 // Flattens an array of Redshift Parameters into a []map[string]interface{} 656 func flattenRedshiftParameters(list []*redshift.Parameter) []map[string]interface{} { 657 result := make([]map[string]interface{}, 0, len(list)) 658 for _, i := range list { 659 result = append(result, map[string]interface{}{ 660 "name": strings.ToLower(*i.ParameterName), 661 "value": strings.ToLower(*i.ParameterValue), 662 }) 663 } 664 return result 665 } 666 667 // Flattens an array of Parameters into a []map[string]interface{} 668 func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} { 669 result := make([]map[string]interface{}, 0, len(list)) 670 for _, i := range list { 671 if i.ParameterValue != nil { 672 result = append(result, map[string]interface{}{ 673 "name": strings.ToLower(*i.ParameterName), 674 "value": strings.ToLower(*i.ParameterValue), 675 }) 676 } 677 } 678 return result 679 } 680 681 // Takes the result of flatmap.Expand for an array of strings 682 // and returns a []*string 683 func expandStringList(configured []interface{}) []*string { 684 vs := make([]*string, 0, len(configured)) 685 for _, v := range configured { 686 vs = append(vs, aws.String(v.(string))) 687 } 688 return vs 689 } 690 691 // Takes the result of schema.Set of strings and returns a []*string 692 func expandStringSet(configured *schema.Set) []*string { 693 return expandStringList(configured.List()) 694 } 695 696 // Takes list of pointers to strings. Expand to an array 697 // of raw strings and returns a []interface{} 698 // to keep compatibility w/ schema.NewSetschema.NewSet 699 func flattenStringList(list []*string) []interface{} { 700 vs := make([]interface{}, 0, len(list)) 701 for _, v := range list { 702 vs = append(vs, *v) 703 } 704 return vs 705 } 706 707 //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0" 708 func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string { 709 ips := make([]string, 0, len(dtos)) 710 for _, v := range dtos { 711 ip := *v.PrivateIpAddress 712 ips = append(ips, ip) 713 } 714 return ips 715 } 716 717 //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs 718 func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string { 719 ids := make([]string, 0, len(dtos)) 720 for _, v := range dtos { 721 group_id := *v.GroupId 722 ids = append(ids, group_id) 723 } 724 return ids 725 } 726 727 //Expands an array of IPs into a ec2 Private IP Address Spec 728 func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification { 729 dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips)) 730 for i, v := range ips { 731 new_private_ip := &ec2.PrivateIpAddressSpecification{ 732 PrivateIpAddress: aws.String(v.(string)), 733 } 734 735 new_private_ip.Primary = aws.Bool(i == 0) 736 737 dtos = append(dtos, new_private_ip) 738 } 739 return dtos 740 } 741 742 //Flattens network interface attachment into a map[string]interface 743 func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} { 744 att := make(map[string]interface{}) 745 if a.InstanceId != nil { 746 att["instance"] = *a.InstanceId 747 } 748 att["device_index"] = *a.DeviceIndex 749 att["attachment_id"] = *a.AttachmentId 750 return att 751 } 752 753 // Flattens step adjustments into a list of map[string]interface. 754 func flattenStepAdjustments(adjustments []*autoscaling.StepAdjustment) []map[string]interface{} { 755 result := make([]map[string]interface{}, 0, len(adjustments)) 756 for _, raw := range adjustments { 757 a := map[string]interface{}{ 758 "scaling_adjustment": *raw.ScalingAdjustment, 759 } 760 if raw.MetricIntervalUpperBound != nil { 761 a["metric_interval_upper_bound"] = *raw.MetricIntervalUpperBound 762 } 763 if raw.MetricIntervalLowerBound != nil { 764 a["metric_interval_lower_bound"] = *raw.MetricIntervalLowerBound 765 } 766 result = append(result, a) 767 } 768 return result 769 } 770 771 func flattenResourceRecords(recs []*route53.ResourceRecord) []string { 772 strs := make([]string, 0, len(recs)) 773 for _, r := range recs { 774 if r.Value != nil { 775 s := strings.Replace(*r.Value, "\"", "", 2) 776 strs = append(strs, s) 777 } 778 } 779 return strs 780 } 781 782 func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord { 783 records := make([]*route53.ResourceRecord, 0, len(recs)) 784 for _, r := range recs { 785 s := r.(string) 786 switch typeStr { 787 case "TXT", "SPF": 788 str := fmt.Sprintf("\"%s\"", s) 789 records = append(records, &route53.ResourceRecord{Value: aws.String(str)}) 790 default: 791 records = append(records, &route53.ResourceRecord{Value: aws.String(s)}) 792 } 793 } 794 return records 795 } 796 797 func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig { 798 config := elasticsearch.ElasticsearchClusterConfig{} 799 800 if v, ok := m["dedicated_master_enabled"]; ok { 801 isEnabled := v.(bool) 802 config.DedicatedMasterEnabled = aws.Bool(isEnabled) 803 804 if isEnabled { 805 if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 { 806 config.DedicatedMasterCount = aws.Int64(int64(v.(int))) 807 } 808 if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" { 809 config.DedicatedMasterType = aws.String(v.(string)) 810 } 811 } 812 } 813 814 if v, ok := m["instance_count"]; ok { 815 config.InstanceCount = aws.Int64(int64(v.(int))) 816 } 817 if v, ok := m["instance_type"]; ok { 818 config.InstanceType = aws.String(v.(string)) 819 } 820 821 if v, ok := m["zone_awareness_enabled"]; ok { 822 config.ZoneAwarenessEnabled = aws.Bool(v.(bool)) 823 } 824 825 return &config 826 } 827 828 func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} { 829 m := map[string]interface{}{} 830 831 if c.DedicatedMasterCount != nil { 832 m["dedicated_master_count"] = *c.DedicatedMasterCount 833 } 834 if c.DedicatedMasterEnabled != nil { 835 m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled 836 } 837 if c.DedicatedMasterType != nil { 838 m["dedicated_master_type"] = *c.DedicatedMasterType 839 } 840 if c.InstanceCount != nil { 841 m["instance_count"] = *c.InstanceCount 842 } 843 if c.InstanceType != nil { 844 m["instance_type"] = *c.InstanceType 845 } 846 if c.ZoneAwarenessEnabled != nil { 847 m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled 848 } 849 850 return []map[string]interface{}{m} 851 } 852 853 func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} { 854 m := map[string]interface{}{} 855 856 if o.EBSEnabled != nil { 857 m["ebs_enabled"] = *o.EBSEnabled 858 } 859 if o.Iops != nil { 860 m["iops"] = *o.Iops 861 } 862 if o.VolumeSize != nil { 863 m["volume_size"] = *o.VolumeSize 864 } 865 if o.VolumeType != nil { 866 m["volume_type"] = *o.VolumeType 867 } 868 869 return []map[string]interface{}{m} 870 } 871 872 func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions { 873 options := elasticsearch.EBSOptions{} 874 875 if v, ok := m["ebs_enabled"]; ok { 876 options.EBSEnabled = aws.Bool(v.(bool)) 877 } 878 if v, ok := m["iops"]; ok && v.(int) > 0 { 879 options.Iops = aws.Int64(int64(v.(int))) 880 } 881 if v, ok := m["volume_size"]; ok && v.(int) > 0 { 882 options.VolumeSize = aws.Int64(int64(v.(int))) 883 } 884 if v, ok := m["volume_type"]; ok && v.(string) != "" { 885 options.VolumeType = aws.String(v.(string)) 886 } 887 888 return &options 889 } 890 891 func pointersMapToStringList(pointers map[string]*string) map[string]interface{} { 892 list := make(map[string]interface{}, len(pointers)) 893 for i, v := range pointers { 894 list[i] = *v 895 } 896 return list 897 } 898 899 func stringMapToPointers(m map[string]interface{}) map[string]*string { 900 list := make(map[string]*string, len(m)) 901 for i, v := range m { 902 list[i] = aws.String(v.(string)) 903 } 904 return list 905 } 906 907 func flattenDSVpcSettings( 908 s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} { 909 settings := make(map[string]interface{}, 0) 910 911 if s == nil { 912 return nil 913 } 914 915 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 916 settings["vpc_id"] = *s.VpcId 917 918 return []map[string]interface{}{settings} 919 } 920 921 func flattenLambdaVpcConfigResponse(s *lambda.VpcConfigResponse) []map[string]interface{} { 922 settings := make(map[string]interface{}, 0) 923 924 if s == nil { 925 return nil 926 } 927 928 if len(s.SubnetIds) == 0 && len(s.SecurityGroupIds) == 0 && s.VpcId == nil { 929 return nil 930 } 931 932 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 933 settings["security_group_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SecurityGroupIds)) 934 if s.VpcId != nil { 935 settings["vpc_id"] = *s.VpcId 936 } 937 938 return []map[string]interface{}{settings} 939 } 940 941 func flattenDSConnectSettings( 942 customerDnsIps []*string, 943 s *directoryservice.DirectoryConnectSettingsDescription) []map[string]interface{} { 944 if s == nil { 945 return nil 946 } 947 948 settings := make(map[string]interface{}, 0) 949 950 settings["customer_dns_ips"] = schema.NewSet(schema.HashString, flattenStringList(customerDnsIps)) 951 settings["connect_ips"] = schema.NewSet(schema.HashString, flattenStringList(s.ConnectIps)) 952 settings["customer_username"] = *s.CustomerUserName 953 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 954 settings["vpc_id"] = *s.VpcId 955 956 return []map[string]interface{}{settings} 957 } 958 959 func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter { 960 var cfParams []*cloudformation.Parameter 961 for k, v := range params { 962 cfParams = append(cfParams, &cloudformation.Parameter{ 963 ParameterKey: aws.String(k), 964 ParameterValue: aws.String(v.(string)), 965 }) 966 } 967 968 return cfParams 969 } 970 971 // flattenCloudFormationParameters is flattening list of 972 // *cloudformation.Parameters and only returning existing 973 // parameters to avoid clash with default values 974 func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter, 975 originalParams map[string]interface{}) map[string]interface{} { 976 params := make(map[string]interface{}, len(cfParams)) 977 for _, p := range cfParams { 978 _, isConfigured := originalParams[*p.ParameterKey] 979 if isConfigured { 980 params[*p.ParameterKey] = *p.ParameterValue 981 } 982 } 983 return params 984 } 985 986 func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag { 987 var cfTags []*cloudformation.Tag 988 for k, v := range tags { 989 cfTags = append(cfTags, &cloudformation.Tag{ 990 Key: aws.String(k), 991 Value: aws.String(v.(string)), 992 }) 993 } 994 return cfTags 995 } 996 997 func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string { 998 tags := make(map[string]string, len(cfTags)) 999 for _, t := range cfTags { 1000 tags[*t.Key] = *t.Value 1001 } 1002 return tags 1003 } 1004 1005 func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string { 1006 outputs := make(map[string]string, len(cfOutputs)) 1007 for _, o := range cfOutputs { 1008 outputs[*o.OutputKey] = *o.OutputValue 1009 } 1010 return outputs 1011 } 1012 1013 func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string { 1014 strs := make([]string, 0, len(list)) 1015 for _, r := range list { 1016 if r.Metric != nil { 1017 strs = append(strs, *r.Metric) 1018 } 1019 } 1020 return strs 1021 } 1022 1023 func flattenKinesisShardLevelMetrics(list []*kinesis.EnhancedMetrics) []string { 1024 if len(list) == 0 { 1025 return []string{} 1026 } 1027 strs := make([]string, 0, len(list[0].ShardLevelMetrics)) 1028 for _, s := range list[0].ShardLevelMetrics { 1029 strs = append(strs, *s) 1030 } 1031 return strs 1032 } 1033 1034 func flattenApiGatewayStageKeys(keys []*string) []map[string]interface{} { 1035 stageKeys := make([]map[string]interface{}, 0, len(keys)) 1036 for _, o := range keys { 1037 key := make(map[string]interface{}) 1038 parts := strings.Split(*o, "/") 1039 key["stage_name"] = parts[1] 1040 key["rest_api_id"] = parts[0] 1041 1042 stageKeys = append(stageKeys, key) 1043 } 1044 return stageKeys 1045 } 1046 1047 func expandApiGatewayStageKeys(d *schema.ResourceData) []*apigateway.StageKey { 1048 var stageKeys []*apigateway.StageKey 1049 1050 if stageKeyData, ok := d.GetOk("stage_key"); ok { 1051 params := stageKeyData.(*schema.Set).List() 1052 for k := range params { 1053 data := params[k].(map[string]interface{}) 1054 stageKeys = append(stageKeys, &apigateway.StageKey{ 1055 RestApiId: aws.String(data["rest_api_id"].(string)), 1056 StageName: aws.String(data["stage_name"].(string)), 1057 }) 1058 } 1059 } 1060 1061 return stageKeys 1062 } 1063 1064 func expandApiGatewayRequestResponseModelOperations(d *schema.ResourceData, key string, prefix string) []*apigateway.PatchOperation { 1065 operations := make([]*apigateway.PatchOperation, 0) 1066 1067 oldModels, newModels := d.GetChange(key) 1068 oldModelMap := oldModels.(map[string]interface{}) 1069 newModelMap := newModels.(map[string]interface{}) 1070 1071 for k, _ := range oldModelMap { 1072 operation := apigateway.PatchOperation{ 1073 Op: aws.String("remove"), 1074 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))), 1075 } 1076 1077 for nK, nV := range newModelMap { 1078 if nK == k { 1079 operation.Op = aws.String("replace") 1080 operation.Value = aws.String(nV.(string)) 1081 } 1082 } 1083 1084 operations = append(operations, &operation) 1085 } 1086 1087 for nK, nV := range newModelMap { 1088 exists := false 1089 for k, _ := range oldModelMap { 1090 if k == nK { 1091 exists = true 1092 } 1093 } 1094 if !exists { 1095 operation := apigateway.PatchOperation{ 1096 Op: aws.String("add"), 1097 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(nK, "/", "~1", -1))), 1098 Value: aws.String(nV.(string)), 1099 } 1100 operations = append(operations, &operation) 1101 } 1102 } 1103 1104 return operations 1105 } 1106 1107 func deprecatedExpandApiGatewayMethodParametersJSONOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) { 1108 operations := make([]*apigateway.PatchOperation, 0) 1109 oldParameters, newParameters := d.GetChange(key) 1110 oldParametersMap := make(map[string]interface{}) 1111 newParametersMap := make(map[string]interface{}) 1112 1113 if err := json.Unmarshal([]byte(oldParameters.(string)), &oldParametersMap); err != nil { 1114 err := fmt.Errorf("Error unmarshaling old %s: %s", key, err) 1115 return operations, err 1116 } 1117 1118 if err := json.Unmarshal([]byte(newParameters.(string)), &newParametersMap); err != nil { 1119 err := fmt.Errorf("Error unmarshaling new %s: %s", key, err) 1120 return operations, err 1121 } 1122 1123 for k, _ := range oldParametersMap { 1124 operation := apigateway.PatchOperation{ 1125 Op: aws.String("remove"), 1126 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)), 1127 } 1128 1129 for nK, nV := range newParametersMap { 1130 if nK == k { 1131 operation.Op = aws.String("replace") 1132 operation.Value = aws.String(strconv.FormatBool(nV.(bool))) 1133 } 1134 } 1135 1136 operations = append(operations, &operation) 1137 } 1138 1139 for nK, nV := range newParametersMap { 1140 exists := false 1141 for k, _ := range oldParametersMap { 1142 if k == nK { 1143 exists = true 1144 } 1145 } 1146 if !exists { 1147 operation := apigateway.PatchOperation{ 1148 Op: aws.String("add"), 1149 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, nK)), 1150 Value: aws.String(strconv.FormatBool(nV.(bool))), 1151 } 1152 operations = append(operations, &operation) 1153 } 1154 } 1155 1156 return operations, nil 1157 } 1158 1159 func expandApiGatewayMethodParametersOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) { 1160 operations := make([]*apigateway.PatchOperation, 0) 1161 1162 oldParameters, newParameters := d.GetChange(key) 1163 oldParametersMap := oldParameters.(map[string]interface{}) 1164 newParametersMap := newParameters.(map[string]interface{}) 1165 1166 for k, _ := range oldParametersMap { 1167 operation := apigateway.PatchOperation{ 1168 Op: aws.String("remove"), 1169 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)), 1170 } 1171 1172 for nK, nV := range newParametersMap { 1173 b, ok := nV.(bool) 1174 if !ok { 1175 value, _ := strconv.ParseBool(nV.(string)) 1176 b = value 1177 } 1178 if nK == k { 1179 operation.Op = aws.String("replace") 1180 operation.Value = aws.String(strconv.FormatBool(b)) 1181 } 1182 } 1183 1184 operations = append(operations, &operation) 1185 } 1186 1187 for nK, nV := range newParametersMap { 1188 exists := false 1189 for k, _ := range oldParametersMap { 1190 if k == nK { 1191 exists = true 1192 } 1193 } 1194 if !exists { 1195 b, ok := nV.(bool) 1196 if !ok { 1197 value, _ := strconv.ParseBool(nV.(string)) 1198 b = value 1199 } 1200 operation := apigateway.PatchOperation{ 1201 Op: aws.String("add"), 1202 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, nK)), 1203 Value: aws.String(strconv.FormatBool(b)), 1204 } 1205 operations = append(operations, &operation) 1206 } 1207 } 1208 1209 return operations, nil 1210 } 1211 1212 func expandApiGatewayStageKeyOperations(d *schema.ResourceData) []*apigateway.PatchOperation { 1213 operations := make([]*apigateway.PatchOperation, 0) 1214 1215 prev, curr := d.GetChange("stage_key") 1216 prevList := prev.(*schema.Set).List() 1217 currList := curr.(*schema.Set).List() 1218 1219 for i := range prevList { 1220 p := prevList[i].(map[string]interface{}) 1221 exists := false 1222 1223 for j := range currList { 1224 c := currList[j].(map[string]interface{}) 1225 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1226 exists = true 1227 } 1228 } 1229 1230 if !exists { 1231 operations = append(operations, &apigateway.PatchOperation{ 1232 Op: aws.String("remove"), 1233 Path: aws.String("/stages"), 1234 Value: aws.String(fmt.Sprintf("%s/%s", p["rest_api_id"].(string), p["stage_name"].(string))), 1235 }) 1236 } 1237 } 1238 1239 for i := range currList { 1240 c := currList[i].(map[string]interface{}) 1241 exists := false 1242 1243 for j := range prevList { 1244 p := prevList[j].(map[string]interface{}) 1245 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1246 exists = true 1247 } 1248 } 1249 1250 if !exists { 1251 operations = append(operations, &apigateway.PatchOperation{ 1252 Op: aws.String("add"), 1253 Path: aws.String("/stages"), 1254 Value: aws.String(fmt.Sprintf("%s/%s", c["rest_api_id"].(string), c["stage_name"].(string))), 1255 }) 1256 } 1257 } 1258 1259 return operations 1260 } 1261 1262 func expandCloudWachLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation { 1263 transformation := cloudwatchlogs.MetricTransformation{ 1264 MetricName: aws.String(m["name"].(string)), 1265 MetricNamespace: aws.String(m["namespace"].(string)), 1266 MetricValue: aws.String(m["value"].(string)), 1267 } 1268 1269 return []*cloudwatchlogs.MetricTransformation{&transformation} 1270 } 1271 1272 func flattenCloudWachLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) map[string]string { 1273 m := make(map[string]string, 0) 1274 1275 m["name"] = *ts[0].MetricName 1276 m["namespace"] = *ts[0].MetricNamespace 1277 m["value"] = *ts[0].MetricValue 1278 1279 return m 1280 } 1281 1282 func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string { 1283 strs := make([]string, 0, len(list)) 1284 for _, r := range list { 1285 if r.Name != nil { 1286 strs = append(strs, *r.Name) 1287 } 1288 } 1289 return strs 1290 } 1291 1292 func flattenBeanstalkInstances(list []*elasticbeanstalk.Instance) []string { 1293 strs := make([]string, 0, len(list)) 1294 for _, r := range list { 1295 if r.Id != nil { 1296 strs = append(strs, *r.Id) 1297 } 1298 } 1299 return strs 1300 } 1301 1302 func flattenBeanstalkLc(list []*elasticbeanstalk.LaunchConfiguration) []string { 1303 strs := make([]string, 0, len(list)) 1304 for _, r := range list { 1305 if r.Name != nil { 1306 strs = append(strs, *r.Name) 1307 } 1308 } 1309 return strs 1310 } 1311 1312 func flattenBeanstalkElb(list []*elasticbeanstalk.LoadBalancer) []string { 1313 strs := make([]string, 0, len(list)) 1314 for _, r := range list { 1315 if r.Name != nil { 1316 strs = append(strs, *r.Name) 1317 } 1318 } 1319 return strs 1320 } 1321 1322 func flattenBeanstalkSqs(list []*elasticbeanstalk.Queue) []string { 1323 strs := make([]string, 0, len(list)) 1324 for _, r := range list { 1325 if r.URL != nil { 1326 strs = append(strs, *r.URL) 1327 } 1328 } 1329 return strs 1330 } 1331 1332 func flattenBeanstalkTrigger(list []*elasticbeanstalk.Trigger) []string { 1333 strs := make([]string, 0, len(list)) 1334 for _, r := range list { 1335 if r.Name != nil { 1336 strs = append(strs, *r.Name) 1337 } 1338 } 1339 return strs 1340 } 1341 1342 // There are several parts of the AWS API that will sort lists of strings, 1343 // causing diffs inbetweeen resources that use lists. This avoids a bit of 1344 // code duplication for pre-sorts that can be used for things like hash 1345 // functions, etc. 1346 func sortInterfaceSlice(in []interface{}) []interface{} { 1347 a := []string{} 1348 b := []interface{}{} 1349 for _, v := range in { 1350 a = append(a, v.(string)) 1351 } 1352 1353 sort.Strings(a) 1354 1355 for _, v := range a { 1356 b = append(b, v) 1357 } 1358 1359 return b 1360 } 1361 1362 func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) []map[string]interface{} { 1363 result := make([]map[string]interface{}, 0, 1) 1364 1365 if settings != nil { 1366 r := make(map[string]interface{}) 1367 if settings.BurstLimit != nil { 1368 r["burst_limit"] = *settings.BurstLimit 1369 } 1370 1371 if settings.RateLimit != nil { 1372 r["rate_limit"] = *settings.RateLimit 1373 } 1374 1375 result = append(result, r) 1376 } 1377 1378 return result 1379 } 1380 1381 // TODO: refactor some of these helper functions and types in the terraform/helper packages 1382 1383 // getStringPtr returns a *string version of the value taken from m, where m 1384 // can be a map[string]interface{} or a *schema.ResourceData. If the key isn't 1385 // present or is empty, getNilString returns nil. 1386 func getStringPtr(m interface{}, key string) *string { 1387 switch m := m.(type) { 1388 case map[string]interface{}: 1389 v := m[key] 1390 1391 if v == nil { 1392 return nil 1393 } 1394 1395 s := v.(string) 1396 if s == "" { 1397 return nil 1398 } 1399 1400 return &s 1401 1402 case *schema.ResourceData: 1403 if v, ok := m.GetOk(key); ok { 1404 if v == nil || v.(string) == "" { 1405 return nil 1406 } 1407 s := v.(string) 1408 return &s 1409 } 1410 1411 default: 1412 panic("unknown type in getStringPtr") 1413 } 1414 1415 return nil 1416 } 1417 1418 // getStringPtrList returns a []*string version of the map value. If the key 1419 // isn't present, getNilStringList returns nil. 1420 func getStringPtrList(m map[string]interface{}, key string) []*string { 1421 if v, ok := m[key]; ok { 1422 var stringList []*string 1423 for _, i := range v.([]interface{}) { 1424 s := i.(string) 1425 stringList = append(stringList, &s) 1426 } 1427 1428 return stringList 1429 } 1430 1431 return nil 1432 } 1433 1434 // a convenience wrapper type for the schema.Set map[string]interface{} 1435 // Set operations only alter the underlying map if the value is not nil 1436 type setMap map[string]interface{} 1437 1438 // SetString sets m[key] = *value only if `value != nil` 1439 func (s setMap) SetString(key string, value *string) { 1440 if value == nil { 1441 return 1442 } 1443 1444 s[key] = *value 1445 } 1446 1447 // SetStringMap sets key to value as a map[string]interface{}, stripping any nil 1448 // values. The value parameter can be a map[string]interface{}, a 1449 // map[string]*string, or a map[string]string. 1450 func (s setMap) SetStringMap(key string, value interface{}) { 1451 // because these methods are meant to be chained without intermediate 1452 // checks for nil, we are likely to get interfaces with dynamic types but 1453 // a nil value. 1454 if reflect.ValueOf(value).IsNil() { 1455 return 1456 } 1457 1458 m := make(map[string]interface{}) 1459 1460 switch value := value.(type) { 1461 case map[string]string: 1462 for k, v := range value { 1463 m[k] = v 1464 } 1465 case map[string]*string: 1466 for k, v := range value { 1467 if v == nil { 1468 continue 1469 } 1470 m[k] = *v 1471 } 1472 case map[string]interface{}: 1473 for k, v := range value { 1474 if v == nil { 1475 continue 1476 } 1477 1478 switch v := v.(type) { 1479 case string: 1480 m[k] = v 1481 case *string: 1482 if v != nil { 1483 m[k] = *v 1484 } 1485 default: 1486 panic(fmt.Sprintf("unknown type for SetString: %T", v)) 1487 } 1488 } 1489 } 1490 1491 // catch the case where the interface wasn't nil, but we had no non-nil values 1492 if len(m) > 0 { 1493 s[key] = m 1494 } 1495 } 1496 1497 // Set assigns value to s[key] if value isn't nil 1498 func (s setMap) Set(key string, value interface{}) { 1499 if reflect.ValueOf(value).IsNil() { 1500 return 1501 } 1502 1503 s[key] = value 1504 } 1505 1506 // Map returns the raw map type for a shorter type conversion 1507 func (s setMap) Map() map[string]interface{} { 1508 return map[string]interface{}(s) 1509 } 1510 1511 // MapList returns the map[string]interface{} as a single element in a slice to 1512 // match the schema.Set data type used for structs. 1513 func (s setMap) MapList() []map[string]interface{} { 1514 return []map[string]interface{}{s.Map()} 1515 } 1516 1517 // Takes the result of flatmap.Expand for an array of policy attributes and 1518 // returns ELB API compatible objects 1519 func expandPolicyAttributes(configured []interface{}) ([]*elb.PolicyAttribute, error) { 1520 attributes := make([]*elb.PolicyAttribute, 0, len(configured)) 1521 1522 // Loop over our configured attributes and create 1523 // an array of aws-sdk-go compatible objects 1524 for _, lRaw := range configured { 1525 data := lRaw.(map[string]interface{}) 1526 1527 a := &elb.PolicyAttribute{ 1528 AttributeName: aws.String(data["name"].(string)), 1529 AttributeValue: aws.String(data["value"].(string)), 1530 } 1531 1532 attributes = append(attributes, a) 1533 1534 } 1535 1536 return attributes, nil 1537 } 1538 1539 // Flattens an array of PolicyAttributes into a []interface{} 1540 func flattenPolicyAttributes(list []*elb.PolicyAttributeDescription) []interface{} { 1541 attributes := []interface{}{} 1542 for _, attrdef := range list { 1543 attribute := map[string]string{ 1544 "name": *attrdef.AttributeName, 1545 "value": *attrdef.AttributeValue, 1546 } 1547 1548 attributes = append(attributes, attribute) 1549 1550 } 1551 1552 return attributes 1553 }