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