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