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