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