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