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