github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/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 compatible 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 '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 compatible 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 compatible 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 compatible 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 { 364 return nil 365 } 366 367 r := make(map[string]interface{}) 368 if l.S3BucketName != nil { 369 r["bucket"] = *l.S3BucketName 370 } 371 372 if l.S3BucketPrefix != nil { 373 r["bucket_prefix"] = *l.S3BucketPrefix 374 } 375 376 if l.EmitInterval != nil { 377 r["interval"] = *l.EmitInterval 378 } 379 380 if l.Enabled != nil { 381 r["enabled"] = *l.Enabled 382 } 383 384 result = append(result, r) 385 386 return result 387 } 388 389 // Takes the result of flatmap.Expand for an array of step adjustments and 390 // returns a []*autoscaling.StepAdjustment. 391 func expandStepAdjustments(configured []interface{}) ([]*autoscaling.StepAdjustment, error) { 392 var adjustments []*autoscaling.StepAdjustment 393 394 // Loop over our configured step adjustments and create an array 395 // of aws-sdk-go compatible objects. We're forced to convert strings 396 // to floats here because there's no way to detect whether or not 397 // an uninitialized, optional schema element is "0.0" deliberately. 398 // With strings, we can test for "", which is definitely an empty 399 // struct value. 400 for _, raw := range configured { 401 data := raw.(map[string]interface{}) 402 a := &autoscaling.StepAdjustment{ 403 ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))), 404 } 405 if data["metric_interval_lower_bound"] != "" { 406 bound := data["metric_interval_lower_bound"] 407 switch bound := bound.(type) { 408 case string: 409 f, err := strconv.ParseFloat(bound, 64) 410 if err != nil { 411 return nil, fmt.Errorf( 412 "metric_interval_lower_bound must be a float value represented as a string") 413 } 414 a.MetricIntervalLowerBound = aws.Float64(f) 415 default: 416 return nil, fmt.Errorf( 417 "metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.") 418 } 419 } 420 if data["metric_interval_upper_bound"] != "" { 421 bound := data["metric_interval_upper_bound"] 422 switch bound := bound.(type) { 423 case string: 424 f, err := strconv.ParseFloat(bound, 64) 425 if err != nil { 426 return nil, fmt.Errorf( 427 "metric_interval_upper_bound must be a float value represented as a string") 428 } 429 a.MetricIntervalUpperBound = aws.Float64(f) 430 default: 431 return nil, fmt.Errorf( 432 "metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.") 433 } 434 } 435 adjustments = append(adjustments, a) 436 } 437 438 return adjustments, nil 439 } 440 441 // Flattens a health check into something that flatmap.Flatten() 442 // can handle 443 func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} { 444 result := make([]map[string]interface{}, 0, 1) 445 446 chk := make(map[string]interface{}) 447 chk["unhealthy_threshold"] = *check.UnhealthyThreshold 448 chk["healthy_threshold"] = *check.HealthyThreshold 449 chk["target"] = *check.Target 450 chk["timeout"] = *check.Timeout 451 chk["interval"] = *check.Interval 452 453 result = append(result, chk) 454 455 return result 456 } 457 458 // Flattens an array of UserSecurityGroups into a []*ec2.GroupIdentifier 459 func flattenSecurityGroups(list []*ec2.UserIdGroupPair, ownerId *string) []*ec2.GroupIdentifier { 460 result := make([]*ec2.GroupIdentifier, 0, len(list)) 461 for _, g := range list { 462 var userId *string 463 if g.UserId != nil && *g.UserId != "" && (ownerId == nil || *ownerId != *g.UserId) { 464 userId = g.UserId 465 } 466 // userid nil here for same vpc groups 467 468 vpc := g.GroupName == nil || *g.GroupName == "" 469 var id *string 470 if vpc { 471 id = g.GroupId 472 } else { 473 id = g.GroupName 474 } 475 476 // id is groupid for vpcs 477 // id is groupname for non vpc (classic) 478 479 if userId != nil { 480 id = aws.String(*userId + "/" + *id) 481 } 482 483 if vpc { 484 result = append(result, &ec2.GroupIdentifier{ 485 GroupId: id, 486 }) 487 } else { 488 result = append(result, &ec2.GroupIdentifier{ 489 GroupId: g.GroupId, 490 GroupName: id, 491 }) 492 } 493 } 494 return result 495 } 496 497 // Flattens an array of Instances into a []string 498 func flattenInstances(list []*elb.Instance) []string { 499 result := make([]string, 0, len(list)) 500 for _, i := range list { 501 result = append(result, *i.InstanceId) 502 } 503 return result 504 } 505 506 // Expands an array of String Instance IDs into a []Instances 507 func expandInstanceString(list []interface{}) []*elb.Instance { 508 result := make([]*elb.Instance, 0, len(list)) 509 for _, i := range list { 510 result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))}) 511 } 512 return result 513 } 514 515 // Flattens an array of Backend Descriptions into a a map of instance_port to policy names. 516 func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string { 517 policies := make(map[int64][]string) 518 for _, i := range backends { 519 for _, p := range i.PolicyNames { 520 policies[*i.InstancePort] = append(policies[*i.InstancePort], *p) 521 } 522 sort.Strings(policies[*i.InstancePort]) 523 } 524 return policies 525 } 526 527 // Flattens an array of Listeners into a []map[string]interface{} 528 func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} { 529 result := make([]map[string]interface{}, 0, len(list)) 530 for _, i := range list { 531 l := map[string]interface{}{ 532 "instance_port": *i.Listener.InstancePort, 533 "instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol), 534 "lb_port": *i.Listener.LoadBalancerPort, 535 "lb_protocol": strings.ToLower(*i.Listener.Protocol), 536 } 537 // SSLCertificateID is optional, and may be nil 538 if i.Listener.SSLCertificateId != nil { 539 l["ssl_certificate_id"] = *i.Listener.SSLCertificateId 540 } 541 result = append(result, l) 542 } 543 return result 544 } 545 546 // Flattens an array of Volumes into a []map[string]interface{} 547 func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { 548 result := make([]map[string]interface{}, 0, len(list)) 549 for _, volume := range list { 550 l := map[string]interface{}{ 551 "name": *volume.Name, 552 } 553 554 if volume.Host.SourcePath != nil { 555 l["host_path"] = *volume.Host.SourcePath 556 } 557 558 result = append(result, l) 559 } 560 return result 561 } 562 563 // Flattens an array of ECS LoadBalancers into a []map[string]interface{} 564 func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} { 565 result := make([]map[string]interface{}, 0, len(list)) 566 for _, loadBalancer := range list { 567 l := map[string]interface{}{ 568 "container_name": *loadBalancer.ContainerName, 569 "container_port": *loadBalancer.ContainerPort, 570 } 571 572 if loadBalancer.LoadBalancerName != nil { 573 l["elb_name"] = *loadBalancer.LoadBalancerName 574 } 575 576 if loadBalancer.TargetGroupArn != nil { 577 l["target_group_arn"] = *loadBalancer.TargetGroupArn 578 } 579 580 result = append(result, l) 581 } 582 return result 583 } 584 585 // Encodes an array of ecs.ContainerDefinitions into a JSON string 586 func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { 587 byteArray, err := json.Marshal(definitions) 588 if err != nil { 589 return "", fmt.Errorf("Error encoding to JSON: %s", err) 590 } 591 592 n := bytes.Index(byteArray, []byte{0}) 593 return string(byteArray[:n]), nil 594 } 595 596 // Flattens an array of Options into a []map[string]interface{} 597 func flattenOptions(list []*rds.Option) []map[string]interface{} { 598 result := make([]map[string]interface{}, 0, len(list)) 599 for _, i := range list { 600 if i.OptionName != nil { 601 r := make(map[string]interface{}) 602 r["option_name"] = strings.ToLower(*i.OptionName) 603 // Default empty string, guard against nil parameter values 604 r["port"] = "" 605 if i.Port != nil { 606 r["port"] = int(*i.Port) 607 } 608 if i.VpcSecurityGroupMemberships != nil { 609 vpcs := make([]string, 0, len(i.VpcSecurityGroupMemberships)) 610 for _, vpc := range i.VpcSecurityGroupMemberships { 611 id := vpc.VpcSecurityGroupId 612 vpcs = append(vpcs, *id) 613 } 614 615 r["vpc_security_group_memberships"] = vpcs 616 } 617 if i.DBSecurityGroupMemberships != nil { 618 dbs := make([]string, 0, len(i.DBSecurityGroupMemberships)) 619 for _, db := range i.DBSecurityGroupMemberships { 620 id := db.DBSecurityGroupName 621 dbs = append(dbs, *id) 622 } 623 624 r["db_security_group_memberships"] = dbs 625 } 626 if i.OptionSettings != nil { 627 settings := make([]map[string]interface{}, 0, len(i.OptionSettings)) 628 for _, j := range i.OptionSettings { 629 setting := map[string]interface{}{ 630 "name": *j.Name, 631 } 632 if j.Value != nil { 633 setting["value"] = *j.Value 634 } 635 636 settings = append(settings, setting) 637 } 638 639 r["option_settings"] = settings 640 } 641 result = append(result, r) 642 } 643 } 644 return result 645 } 646 647 // Flattens an array of Parameters into a []map[string]interface{} 648 func flattenParameters(list []*rds.Parameter) []map[string]interface{} { 649 result := make([]map[string]interface{}, 0, len(list)) 650 for _, i := range list { 651 if i.ParameterName != nil { 652 r := make(map[string]interface{}) 653 r["name"] = strings.ToLower(*i.ParameterName) 654 // Default empty string, guard against nil parameter values 655 r["value"] = "" 656 if i.ParameterValue != nil { 657 r["value"] = strings.ToLower(*i.ParameterValue) 658 } 659 if i.ApplyMethod != nil { 660 r["apply_method"] = strings.ToLower(*i.ApplyMethod) 661 } 662 663 result = append(result, r) 664 } 665 } 666 return result 667 } 668 669 // Flattens an array of Redshift Parameters into a []map[string]interface{} 670 func flattenRedshiftParameters(list []*redshift.Parameter) []map[string]interface{} { 671 result := make([]map[string]interface{}, 0, len(list)) 672 for _, i := range list { 673 result = append(result, map[string]interface{}{ 674 "name": strings.ToLower(*i.ParameterName), 675 "value": strings.ToLower(*i.ParameterValue), 676 }) 677 } 678 return result 679 } 680 681 // Flattens an array of Parameters into a []map[string]interface{} 682 func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} { 683 result := make([]map[string]interface{}, 0, len(list)) 684 for _, i := range list { 685 if i.ParameterValue != nil { 686 result = append(result, map[string]interface{}{ 687 "name": strings.ToLower(*i.ParameterName), 688 "value": *i.ParameterValue, 689 }) 690 } 691 } 692 return result 693 } 694 695 // Takes the result of flatmap.Expand for an array of strings 696 // and returns a []*string 697 func expandStringList(configured []interface{}) []*string { 698 vs := make([]*string, 0, len(configured)) 699 for _, v := range configured { 700 val, ok := v.(string) 701 if ok && val != "" { 702 vs = append(vs, aws.String(v.(string))) 703 } 704 } 705 return vs 706 } 707 708 // Takes the result of schema.Set of strings and returns a []*string 709 func expandStringSet(configured *schema.Set) []*string { 710 return expandStringList(configured.List()) 711 } 712 713 // Takes list of pointers to strings. Expand to an array 714 // of raw strings and returns a []interface{} 715 // to keep compatibility w/ schema.NewSetschema.NewSet 716 func flattenStringList(list []*string) []interface{} { 717 vs := make([]interface{}, 0, len(list)) 718 for _, v := range list { 719 vs = append(vs, *v) 720 } 721 return vs 722 } 723 724 //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0" 725 func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string { 726 ips := make([]string, 0, len(dtos)) 727 for _, v := range dtos { 728 ip := *v.PrivateIpAddress 729 ips = append(ips, ip) 730 } 731 return ips 732 } 733 734 //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs 735 func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string { 736 ids := make([]string, 0, len(dtos)) 737 for _, v := range dtos { 738 group_id := *v.GroupId 739 ids = append(ids, group_id) 740 } 741 return ids 742 } 743 744 //Expands an array of IPs into a ec2 Private IP Address Spec 745 func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification { 746 dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips)) 747 for i, v := range ips { 748 new_private_ip := &ec2.PrivateIpAddressSpecification{ 749 PrivateIpAddress: aws.String(v.(string)), 750 } 751 752 new_private_ip.Primary = aws.Bool(i == 0) 753 754 dtos = append(dtos, new_private_ip) 755 } 756 return dtos 757 } 758 759 //Flattens network interface attachment into a map[string]interface 760 func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} { 761 att := make(map[string]interface{}) 762 if a.InstanceId != nil { 763 att["instance"] = *a.InstanceId 764 } 765 att["device_index"] = *a.DeviceIndex 766 att["attachment_id"] = *a.AttachmentId 767 return att 768 } 769 770 func flattenElastiCacheSecurityGroupNames(securityGroups []*elasticache.CacheSecurityGroupMembership) []string { 771 result := make([]string, 0, len(securityGroups)) 772 for _, sg := range securityGroups { 773 if sg.CacheSecurityGroupName != nil { 774 result = append(result, *sg.CacheSecurityGroupName) 775 } 776 } 777 return result 778 } 779 780 func flattenElastiCacheSecurityGroupIds(securityGroups []*elasticache.SecurityGroupMembership) []string { 781 result := make([]string, 0, len(securityGroups)) 782 for _, sg := range securityGroups { 783 if sg.SecurityGroupId != nil { 784 result = append(result, *sg.SecurityGroupId) 785 } 786 } 787 return result 788 } 789 790 // Flattens step adjustments into a list of map[string]interface. 791 func flattenStepAdjustments(adjustments []*autoscaling.StepAdjustment) []map[string]interface{} { 792 result := make([]map[string]interface{}, 0, len(adjustments)) 793 for _, raw := range adjustments { 794 a := map[string]interface{}{ 795 "scaling_adjustment": *raw.ScalingAdjustment, 796 } 797 if raw.MetricIntervalUpperBound != nil { 798 a["metric_interval_upper_bound"] = *raw.MetricIntervalUpperBound 799 } 800 if raw.MetricIntervalLowerBound != nil { 801 a["metric_interval_lower_bound"] = *raw.MetricIntervalLowerBound 802 } 803 result = append(result, a) 804 } 805 return result 806 } 807 808 func flattenResourceRecords(recs []*route53.ResourceRecord) []string { 809 strs := make([]string, 0, len(recs)) 810 for _, r := range recs { 811 if r.Value != nil { 812 s := strings.Replace(*r.Value, "\"", "", 2) 813 strs = append(strs, s) 814 } 815 } 816 return strs 817 } 818 819 func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord { 820 records := make([]*route53.ResourceRecord, 0, len(recs)) 821 for _, r := range recs { 822 s := r.(string) 823 switch typeStr { 824 case "TXT", "SPF": 825 str := fmt.Sprintf("\"%s\"", s) 826 records = append(records, &route53.ResourceRecord{Value: aws.String(str)}) 827 default: 828 records = append(records, &route53.ResourceRecord{Value: aws.String(s)}) 829 } 830 } 831 return records 832 } 833 834 func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig { 835 config := elasticsearch.ElasticsearchClusterConfig{} 836 837 if v, ok := m["dedicated_master_enabled"]; ok { 838 isEnabled := v.(bool) 839 config.DedicatedMasterEnabled = aws.Bool(isEnabled) 840 841 if isEnabled { 842 if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 { 843 config.DedicatedMasterCount = aws.Int64(int64(v.(int))) 844 } 845 if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" { 846 config.DedicatedMasterType = aws.String(v.(string)) 847 } 848 } 849 } 850 851 if v, ok := m["instance_count"]; ok { 852 config.InstanceCount = aws.Int64(int64(v.(int))) 853 } 854 if v, ok := m["instance_type"]; ok { 855 config.InstanceType = aws.String(v.(string)) 856 } 857 858 if v, ok := m["zone_awareness_enabled"]; ok { 859 config.ZoneAwarenessEnabled = aws.Bool(v.(bool)) 860 } 861 862 return &config 863 } 864 865 func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} { 866 m := map[string]interface{}{} 867 868 if c.DedicatedMasterCount != nil { 869 m["dedicated_master_count"] = *c.DedicatedMasterCount 870 } 871 if c.DedicatedMasterEnabled != nil { 872 m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled 873 } 874 if c.DedicatedMasterType != nil { 875 m["dedicated_master_type"] = *c.DedicatedMasterType 876 } 877 if c.InstanceCount != nil { 878 m["instance_count"] = *c.InstanceCount 879 } 880 if c.InstanceType != nil { 881 m["instance_type"] = *c.InstanceType 882 } 883 if c.ZoneAwarenessEnabled != nil { 884 m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled 885 } 886 887 return []map[string]interface{}{m} 888 } 889 890 func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} { 891 m := map[string]interface{}{} 892 893 if o.EBSEnabled != nil { 894 m["ebs_enabled"] = *o.EBSEnabled 895 } 896 if o.Iops != nil { 897 m["iops"] = *o.Iops 898 } 899 if o.VolumeSize != nil { 900 m["volume_size"] = *o.VolumeSize 901 } 902 if o.VolumeType != nil { 903 m["volume_type"] = *o.VolumeType 904 } 905 906 return []map[string]interface{}{m} 907 } 908 909 func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions { 910 options := elasticsearch.EBSOptions{} 911 912 if v, ok := m["ebs_enabled"]; ok { 913 options.EBSEnabled = aws.Bool(v.(bool)) 914 } 915 if v, ok := m["iops"]; ok && v.(int) > 0 { 916 options.Iops = aws.Int64(int64(v.(int))) 917 } 918 if v, ok := m["volume_size"]; ok && v.(int) > 0 { 919 options.VolumeSize = aws.Int64(int64(v.(int))) 920 } 921 if v, ok := m["volume_type"]; ok && v.(string) != "" { 922 options.VolumeType = aws.String(v.(string)) 923 } 924 925 return &options 926 } 927 928 func pointersMapToStringList(pointers map[string]*string) map[string]interface{} { 929 list := make(map[string]interface{}, len(pointers)) 930 for i, v := range pointers { 931 list[i] = *v 932 } 933 return list 934 } 935 936 func stringMapToPointers(m map[string]interface{}) map[string]*string { 937 list := make(map[string]*string, len(m)) 938 for i, v := range m { 939 list[i] = aws.String(v.(string)) 940 } 941 return list 942 } 943 944 func flattenDSVpcSettings( 945 s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} { 946 settings := make(map[string]interface{}, 0) 947 948 if s == nil { 949 return nil 950 } 951 952 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 953 settings["vpc_id"] = *s.VpcId 954 955 return []map[string]interface{}{settings} 956 } 957 958 func flattenLambdaEnvironment(lambdaEnv *lambda.EnvironmentResponse) []interface{} { 959 envs := make(map[string]interface{}) 960 en := make(map[string]string) 961 962 if lambdaEnv == nil { 963 return nil 964 } 965 966 for k, v := range lambdaEnv.Variables { 967 en[k] = *v 968 } 969 if len(en) > 0 { 970 envs["variables"] = en 971 } 972 973 return []interface{}{envs} 974 } 975 976 func flattenLambdaVpcConfigResponse(s *lambda.VpcConfigResponse) []map[string]interface{} { 977 settings := make(map[string]interface{}, 0) 978 979 if s == nil { 980 return nil 981 } 982 983 var emptyVpc bool 984 if s.VpcId == nil || *s.VpcId == "" { 985 emptyVpc = true 986 } 987 if len(s.SubnetIds) == 0 && len(s.SecurityGroupIds) == 0 && emptyVpc { 988 return nil 989 } 990 991 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 992 settings["security_group_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SecurityGroupIds)) 993 if s.VpcId != nil { 994 settings["vpc_id"] = *s.VpcId 995 } 996 997 return []map[string]interface{}{settings} 998 } 999 1000 func flattenDSConnectSettings( 1001 customerDnsIps []*string, 1002 s *directoryservice.DirectoryConnectSettingsDescription) []map[string]interface{} { 1003 if s == nil { 1004 return nil 1005 } 1006 1007 settings := make(map[string]interface{}, 0) 1008 1009 settings["customer_dns_ips"] = schema.NewSet(schema.HashString, flattenStringList(customerDnsIps)) 1010 settings["connect_ips"] = schema.NewSet(schema.HashString, flattenStringList(s.ConnectIps)) 1011 settings["customer_username"] = *s.CustomerUserName 1012 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 1013 settings["vpc_id"] = *s.VpcId 1014 1015 return []map[string]interface{}{settings} 1016 } 1017 1018 func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter { 1019 var cfParams []*cloudformation.Parameter 1020 for k, v := range params { 1021 cfParams = append(cfParams, &cloudformation.Parameter{ 1022 ParameterKey: aws.String(k), 1023 ParameterValue: aws.String(v.(string)), 1024 }) 1025 } 1026 1027 return cfParams 1028 } 1029 1030 // flattenCloudFormationParameters is flattening list of 1031 // *cloudformation.Parameters and only returning existing 1032 // parameters to avoid clash with default values 1033 func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter, 1034 originalParams map[string]interface{}) map[string]interface{} { 1035 params := make(map[string]interface{}, len(cfParams)) 1036 for _, p := range cfParams { 1037 _, isConfigured := originalParams[*p.ParameterKey] 1038 if isConfigured { 1039 params[*p.ParameterKey] = *p.ParameterValue 1040 } 1041 } 1042 return params 1043 } 1044 1045 func flattenAllCloudFormationParameters(cfParams []*cloudformation.Parameter) map[string]interface{} { 1046 params := make(map[string]interface{}, len(cfParams)) 1047 for _, p := range cfParams { 1048 params[*p.ParameterKey] = *p.ParameterValue 1049 } 1050 return params 1051 } 1052 1053 func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag { 1054 var cfTags []*cloudformation.Tag 1055 for k, v := range tags { 1056 cfTags = append(cfTags, &cloudformation.Tag{ 1057 Key: aws.String(k), 1058 Value: aws.String(v.(string)), 1059 }) 1060 } 1061 return cfTags 1062 } 1063 1064 func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string { 1065 tags := make(map[string]string, len(cfTags)) 1066 for _, t := range cfTags { 1067 tags[*t.Key] = *t.Value 1068 } 1069 return tags 1070 } 1071 1072 func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string { 1073 outputs := make(map[string]string, len(cfOutputs)) 1074 for _, o := range cfOutputs { 1075 outputs[*o.OutputKey] = *o.OutputValue 1076 } 1077 return outputs 1078 } 1079 1080 func flattenAsgSuspendedProcesses(list []*autoscaling.SuspendedProcess) []string { 1081 strs := make([]string, 0, len(list)) 1082 for _, r := range list { 1083 if r.ProcessName != nil { 1084 strs = append(strs, *r.ProcessName) 1085 } 1086 } 1087 return strs 1088 } 1089 1090 func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string { 1091 strs := make([]string, 0, len(list)) 1092 for _, r := range list { 1093 if r.Metric != nil { 1094 strs = append(strs, *r.Metric) 1095 } 1096 } 1097 return strs 1098 } 1099 1100 func flattenKinesisShardLevelMetrics(list []*kinesis.EnhancedMetrics) []string { 1101 if len(list) == 0 { 1102 return []string{} 1103 } 1104 strs := make([]string, 0, len(list[0].ShardLevelMetrics)) 1105 for _, s := range list[0].ShardLevelMetrics { 1106 strs = append(strs, *s) 1107 } 1108 return strs 1109 } 1110 1111 func flattenApiGatewayStageKeys(keys []*string) []map[string]interface{} { 1112 stageKeys := make([]map[string]interface{}, 0, len(keys)) 1113 for _, o := range keys { 1114 key := make(map[string]interface{}) 1115 parts := strings.Split(*o, "/") 1116 key["stage_name"] = parts[1] 1117 key["rest_api_id"] = parts[0] 1118 1119 stageKeys = append(stageKeys, key) 1120 } 1121 return stageKeys 1122 } 1123 1124 func expandApiGatewayStageKeys(d *schema.ResourceData) []*apigateway.StageKey { 1125 var stageKeys []*apigateway.StageKey 1126 1127 if stageKeyData, ok := d.GetOk("stage_key"); ok { 1128 params := stageKeyData.(*schema.Set).List() 1129 for k := range params { 1130 data := params[k].(map[string]interface{}) 1131 stageKeys = append(stageKeys, &apigateway.StageKey{ 1132 RestApiId: aws.String(data["rest_api_id"].(string)), 1133 StageName: aws.String(data["stage_name"].(string)), 1134 }) 1135 } 1136 } 1137 1138 return stageKeys 1139 } 1140 1141 func expandApiGatewayRequestResponseModelOperations(d *schema.ResourceData, key string, prefix string) []*apigateway.PatchOperation { 1142 operations := make([]*apigateway.PatchOperation, 0) 1143 1144 oldModels, newModels := d.GetChange(key) 1145 oldModelMap := oldModels.(map[string]interface{}) 1146 newModelMap := newModels.(map[string]interface{}) 1147 1148 for k, _ := range oldModelMap { 1149 operation := apigateway.PatchOperation{ 1150 Op: aws.String("remove"), 1151 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))), 1152 } 1153 1154 for nK, nV := range newModelMap { 1155 if nK == k { 1156 operation.Op = aws.String("replace") 1157 operation.Value = aws.String(nV.(string)) 1158 } 1159 } 1160 1161 operations = append(operations, &operation) 1162 } 1163 1164 for nK, nV := range newModelMap { 1165 exists := false 1166 for k, _ := range oldModelMap { 1167 if k == nK { 1168 exists = true 1169 } 1170 } 1171 if !exists { 1172 operation := apigateway.PatchOperation{ 1173 Op: aws.String("add"), 1174 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(nK, "/", "~1", -1))), 1175 Value: aws.String(nV.(string)), 1176 } 1177 operations = append(operations, &operation) 1178 } 1179 } 1180 1181 return operations 1182 } 1183 1184 func deprecatedExpandApiGatewayMethodParametersJSONOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) { 1185 operations := make([]*apigateway.PatchOperation, 0) 1186 oldParameters, newParameters := d.GetChange(key) 1187 oldParametersMap := make(map[string]interface{}) 1188 newParametersMap := make(map[string]interface{}) 1189 1190 if err := json.Unmarshal([]byte(oldParameters.(string)), &oldParametersMap); err != nil { 1191 err := fmt.Errorf("Error unmarshaling old %s: %s", key, err) 1192 return operations, err 1193 } 1194 1195 if err := json.Unmarshal([]byte(newParameters.(string)), &newParametersMap); err != nil { 1196 err := fmt.Errorf("Error unmarshaling new %s: %s", key, err) 1197 return operations, err 1198 } 1199 1200 for k, _ := range oldParametersMap { 1201 operation := apigateway.PatchOperation{ 1202 Op: aws.String("remove"), 1203 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)), 1204 } 1205 1206 for nK, nV := range newParametersMap { 1207 if nK == k { 1208 operation.Op = aws.String("replace") 1209 operation.Value = aws.String(strconv.FormatBool(nV.(bool))) 1210 } 1211 } 1212 1213 operations = append(operations, &operation) 1214 } 1215 1216 for nK, nV := range newParametersMap { 1217 exists := false 1218 for k, _ := range oldParametersMap { 1219 if k == nK { 1220 exists = true 1221 } 1222 } 1223 if !exists { 1224 operation := apigateway.PatchOperation{ 1225 Op: aws.String("add"), 1226 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, nK)), 1227 Value: aws.String(strconv.FormatBool(nV.(bool))), 1228 } 1229 operations = append(operations, &operation) 1230 } 1231 } 1232 1233 return operations, nil 1234 } 1235 1236 func expandApiGatewayMethodParametersOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) { 1237 operations := make([]*apigateway.PatchOperation, 0) 1238 1239 oldParameters, newParameters := d.GetChange(key) 1240 oldParametersMap := oldParameters.(map[string]interface{}) 1241 newParametersMap := newParameters.(map[string]interface{}) 1242 1243 for k, _ := range oldParametersMap { 1244 operation := apigateway.PatchOperation{ 1245 Op: aws.String("remove"), 1246 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)), 1247 } 1248 1249 for nK, nV := range newParametersMap { 1250 b, ok := nV.(bool) 1251 if !ok { 1252 value, _ := strconv.ParseBool(nV.(string)) 1253 b = value 1254 } 1255 if nK == k { 1256 operation.Op = aws.String("replace") 1257 operation.Value = aws.String(strconv.FormatBool(b)) 1258 } 1259 } 1260 1261 operations = append(operations, &operation) 1262 } 1263 1264 for nK, nV := range newParametersMap { 1265 exists := false 1266 for k, _ := range oldParametersMap { 1267 if k == nK { 1268 exists = true 1269 } 1270 } 1271 if !exists { 1272 b, ok := nV.(bool) 1273 if !ok { 1274 value, _ := strconv.ParseBool(nV.(string)) 1275 b = value 1276 } 1277 operation := apigateway.PatchOperation{ 1278 Op: aws.String("add"), 1279 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, nK)), 1280 Value: aws.String(strconv.FormatBool(b)), 1281 } 1282 operations = append(operations, &operation) 1283 } 1284 } 1285 1286 return operations, nil 1287 } 1288 1289 func expandApiGatewayStageKeyOperations(d *schema.ResourceData) []*apigateway.PatchOperation { 1290 operations := make([]*apigateway.PatchOperation, 0) 1291 1292 prev, curr := d.GetChange("stage_key") 1293 prevList := prev.(*schema.Set).List() 1294 currList := curr.(*schema.Set).List() 1295 1296 for i := range prevList { 1297 p := prevList[i].(map[string]interface{}) 1298 exists := false 1299 1300 for j := range currList { 1301 c := currList[j].(map[string]interface{}) 1302 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1303 exists = true 1304 } 1305 } 1306 1307 if !exists { 1308 operations = append(operations, &apigateway.PatchOperation{ 1309 Op: aws.String("remove"), 1310 Path: aws.String("/stages"), 1311 Value: aws.String(fmt.Sprintf("%s/%s", p["rest_api_id"].(string), p["stage_name"].(string))), 1312 }) 1313 } 1314 } 1315 1316 for i := range currList { 1317 c := currList[i].(map[string]interface{}) 1318 exists := false 1319 1320 for j := range prevList { 1321 p := prevList[j].(map[string]interface{}) 1322 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1323 exists = true 1324 } 1325 } 1326 1327 if !exists { 1328 operations = append(operations, &apigateway.PatchOperation{ 1329 Op: aws.String("add"), 1330 Path: aws.String("/stages"), 1331 Value: aws.String(fmt.Sprintf("%s/%s", c["rest_api_id"].(string), c["stage_name"].(string))), 1332 }) 1333 } 1334 } 1335 1336 return operations 1337 } 1338 1339 func expandCloudWachLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation { 1340 transformation := cloudwatchlogs.MetricTransformation{ 1341 MetricName: aws.String(m["name"].(string)), 1342 MetricNamespace: aws.String(m["namespace"].(string)), 1343 MetricValue: aws.String(m["value"].(string)), 1344 } 1345 1346 return []*cloudwatchlogs.MetricTransformation{&transformation} 1347 } 1348 1349 func flattenCloudWachLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) map[string]string { 1350 m := make(map[string]string, 0) 1351 1352 m["name"] = *ts[0].MetricName 1353 m["namespace"] = *ts[0].MetricNamespace 1354 m["value"] = *ts[0].MetricValue 1355 1356 return m 1357 } 1358 1359 func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string { 1360 strs := make([]string, 0, len(list)) 1361 for _, r := range list { 1362 if r.Name != nil { 1363 strs = append(strs, *r.Name) 1364 } 1365 } 1366 return strs 1367 } 1368 1369 func flattenBeanstalkInstances(list []*elasticbeanstalk.Instance) []string { 1370 strs := make([]string, 0, len(list)) 1371 for _, r := range list { 1372 if r.Id != nil { 1373 strs = append(strs, *r.Id) 1374 } 1375 } 1376 return strs 1377 } 1378 1379 func flattenBeanstalkLc(list []*elasticbeanstalk.LaunchConfiguration) []string { 1380 strs := make([]string, 0, len(list)) 1381 for _, r := range list { 1382 if r.Name != nil { 1383 strs = append(strs, *r.Name) 1384 } 1385 } 1386 return strs 1387 } 1388 1389 func flattenBeanstalkElb(list []*elasticbeanstalk.LoadBalancer) []string { 1390 strs := make([]string, 0, len(list)) 1391 for _, r := range list { 1392 if r.Name != nil { 1393 strs = append(strs, *r.Name) 1394 } 1395 } 1396 return strs 1397 } 1398 1399 func flattenBeanstalkSqs(list []*elasticbeanstalk.Queue) []string { 1400 strs := make([]string, 0, len(list)) 1401 for _, r := range list { 1402 if r.URL != nil { 1403 strs = append(strs, *r.URL) 1404 } 1405 } 1406 return strs 1407 } 1408 1409 func flattenBeanstalkTrigger(list []*elasticbeanstalk.Trigger) []string { 1410 strs := make([]string, 0, len(list)) 1411 for _, r := range list { 1412 if r.Name != nil { 1413 strs = append(strs, *r.Name) 1414 } 1415 } 1416 return strs 1417 } 1418 1419 // There are several parts of the AWS API that will sort lists of strings, 1420 // causing diffs inbetween resources that use lists. This avoids a bit of 1421 // code duplication for pre-sorts that can be used for things like hash 1422 // functions, etc. 1423 func sortInterfaceSlice(in []interface{}) []interface{} { 1424 a := []string{} 1425 b := []interface{}{} 1426 for _, v := range in { 1427 a = append(a, v.(string)) 1428 } 1429 1430 sort.Strings(a) 1431 1432 for _, v := range a { 1433 b = append(b, v) 1434 } 1435 1436 return b 1437 } 1438 1439 func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) []map[string]interface{} { 1440 result := make([]map[string]interface{}, 0, 1) 1441 1442 if settings != nil { 1443 r := make(map[string]interface{}) 1444 if settings.BurstLimit != nil { 1445 r["burst_limit"] = *settings.BurstLimit 1446 } 1447 1448 if settings.RateLimit != nil { 1449 r["rate_limit"] = *settings.RateLimit 1450 } 1451 1452 result = append(result, r) 1453 } 1454 1455 return result 1456 } 1457 1458 // TODO: refactor some of these helper functions and types in the terraform/helper packages 1459 1460 // getStringPtr returns a *string version of the value taken from m, where m 1461 // can be a map[string]interface{} or a *schema.ResourceData. If the key isn't 1462 // present or is empty, getNilString returns nil. 1463 func getStringPtr(m interface{}, key string) *string { 1464 switch m := m.(type) { 1465 case map[string]interface{}: 1466 v := m[key] 1467 1468 if v == nil { 1469 return nil 1470 } 1471 1472 s := v.(string) 1473 if s == "" { 1474 return nil 1475 } 1476 1477 return &s 1478 1479 case *schema.ResourceData: 1480 if v, ok := m.GetOk(key); ok { 1481 if v == nil || v.(string) == "" { 1482 return nil 1483 } 1484 s := v.(string) 1485 return &s 1486 } 1487 1488 default: 1489 panic("unknown type in getStringPtr") 1490 } 1491 1492 return nil 1493 } 1494 1495 // getStringPtrList returns a []*string version of the map value. If the key 1496 // isn't present, getNilStringList returns nil. 1497 func getStringPtrList(m map[string]interface{}, key string) []*string { 1498 if v, ok := m[key]; ok { 1499 var stringList []*string 1500 for _, i := range v.([]interface{}) { 1501 s := i.(string) 1502 stringList = append(stringList, &s) 1503 } 1504 1505 return stringList 1506 } 1507 1508 return nil 1509 } 1510 1511 // a convenience wrapper type for the schema.Set map[string]interface{} 1512 // Set operations only alter the underlying map if the value is not nil 1513 type setMap map[string]interface{} 1514 1515 // SetString sets m[key] = *value only if `value != nil` 1516 func (s setMap) SetString(key string, value *string) { 1517 if value == nil { 1518 return 1519 } 1520 1521 s[key] = *value 1522 } 1523 1524 // SetStringMap sets key to value as a map[string]interface{}, stripping any nil 1525 // values. The value parameter can be a map[string]interface{}, a 1526 // map[string]*string, or a map[string]string. 1527 func (s setMap) SetStringMap(key string, value interface{}) { 1528 // because these methods are meant to be chained without intermediate 1529 // checks for nil, we are likely to get interfaces with dynamic types but 1530 // a nil value. 1531 if reflect.ValueOf(value).IsNil() { 1532 return 1533 } 1534 1535 m := make(map[string]interface{}) 1536 1537 switch value := value.(type) { 1538 case map[string]string: 1539 for k, v := range value { 1540 m[k] = v 1541 } 1542 case map[string]*string: 1543 for k, v := range value { 1544 if v == nil { 1545 continue 1546 } 1547 m[k] = *v 1548 } 1549 case map[string]interface{}: 1550 for k, v := range value { 1551 if v == nil { 1552 continue 1553 } 1554 1555 switch v := v.(type) { 1556 case string: 1557 m[k] = v 1558 case *string: 1559 if v != nil { 1560 m[k] = *v 1561 } 1562 default: 1563 panic(fmt.Sprintf("unknown type for SetString: %T", v)) 1564 } 1565 } 1566 } 1567 1568 // catch the case where the interface wasn't nil, but we had no non-nil values 1569 if len(m) > 0 { 1570 s[key] = m 1571 } 1572 } 1573 1574 // Set assigns value to s[key] if value isn't nil 1575 func (s setMap) Set(key string, value interface{}) { 1576 if reflect.ValueOf(value).IsNil() { 1577 return 1578 } 1579 1580 s[key] = value 1581 } 1582 1583 // Map returns the raw map type for a shorter type conversion 1584 func (s setMap) Map() map[string]interface{} { 1585 return map[string]interface{}(s) 1586 } 1587 1588 // MapList returns the map[string]interface{} as a single element in a slice to 1589 // match the schema.Set data type used for structs. 1590 func (s setMap) MapList() []map[string]interface{} { 1591 return []map[string]interface{}{s.Map()} 1592 } 1593 1594 // Takes the result of flatmap.Expand for an array of policy attributes and 1595 // returns ELB API compatible objects 1596 func expandPolicyAttributes(configured []interface{}) ([]*elb.PolicyAttribute, error) { 1597 attributes := make([]*elb.PolicyAttribute, 0, len(configured)) 1598 1599 // Loop over our configured attributes and create 1600 // an array of aws-sdk-go compatible objects 1601 for _, lRaw := range configured { 1602 data := lRaw.(map[string]interface{}) 1603 1604 a := &elb.PolicyAttribute{ 1605 AttributeName: aws.String(data["name"].(string)), 1606 AttributeValue: aws.String(data["value"].(string)), 1607 } 1608 1609 attributes = append(attributes, a) 1610 1611 } 1612 1613 return attributes, nil 1614 } 1615 1616 // Flattens an array of PolicyAttributes into a []interface{} 1617 func flattenPolicyAttributes(list []*elb.PolicyAttributeDescription) []interface{} { 1618 attributes := []interface{}{} 1619 for _, attrdef := range list { 1620 attribute := map[string]string{ 1621 "name": *attrdef.AttributeName, 1622 "value": *attrdef.AttributeValue, 1623 } 1624 1625 attributes = append(attributes, attribute) 1626 1627 } 1628 1629 return attributes 1630 } 1631 1632 // Takes a value containing JSON string and passes it through 1633 // the JSON parser to normalize it, returns either a parsing 1634 // error or normalized JSON string. 1635 func normalizeJsonString(jsonString interface{}) (string, error) { 1636 var j interface{} 1637 1638 if jsonString == nil || jsonString.(string) == "" { 1639 return "", nil 1640 } 1641 1642 s := jsonString.(string) 1643 1644 err := json.Unmarshal([]byte(s), &j) 1645 if err != nil { 1646 return s, err 1647 } 1648 1649 bytes, _ := json.Marshal(j) 1650 return string(bytes[:]), nil 1651 } 1652 1653 func flattenInspectorTags(cfTags []*cloudformation.Tag) map[string]string { 1654 tags := make(map[string]string, len(cfTags)) 1655 for _, t := range cfTags { 1656 tags[*t.Key] = *t.Value 1657 } 1658 return tags 1659 }