github.com/ricardclau/terraform@v0.6.17-0.20160519222547-283e3ae6b5a9/builtin/providers/aws/structure.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strconv" 9 "strings" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/service/apigateway" 13 "github.com/aws/aws-sdk-go/service/autoscaling" 14 "github.com/aws/aws-sdk-go/service/cloudformation" 15 "github.com/aws/aws-sdk-go/service/cloudwatchlogs" 16 "github.com/aws/aws-sdk-go/service/directoryservice" 17 "github.com/aws/aws-sdk-go/service/ec2" 18 "github.com/aws/aws-sdk-go/service/ecs" 19 "github.com/aws/aws-sdk-go/service/elasticache" 20 "github.com/aws/aws-sdk-go/service/elasticbeanstalk" 21 elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" 22 "github.com/aws/aws-sdk-go/service/elb" 23 "github.com/aws/aws-sdk-go/service/lambda" 24 "github.com/aws/aws-sdk-go/service/rds" 25 "github.com/aws/aws-sdk-go/service/redshift" 26 "github.com/aws/aws-sdk-go/service/route53" 27 "github.com/hashicorp/terraform/helper/schema" 28 ) 29 30 // Takes the result of flatmap.Expand for an array of listeners and 31 // returns ELB API compatible objects 32 func expandListeners(configured []interface{}) ([]*elb.Listener, error) { 33 listeners := make([]*elb.Listener, 0, len(configured)) 34 35 // Loop over our configured listeners and create 36 // an array of aws-sdk-go compatabile objects 37 for _, lRaw := range configured { 38 data := lRaw.(map[string]interface{}) 39 40 ip := int64(data["instance_port"].(int)) 41 lp := int64(data["lb_port"].(int)) 42 l := &elb.Listener{ 43 InstancePort: &ip, 44 InstanceProtocol: aws.String(data["instance_protocol"].(string)), 45 LoadBalancerPort: &lp, 46 Protocol: aws.String(data["lb_protocol"].(string)), 47 } 48 49 if v, ok := data["ssl_certificate_id"]; ok { 50 l.SSLCertificateId = aws.String(v.(string)) 51 } 52 53 var valid bool 54 if l.SSLCertificateId != nil && *l.SSLCertificateId != "" { 55 // validate the protocol is correct 56 for _, p := range []string{"https", "ssl"} { 57 if (strings.ToLower(*l.InstanceProtocol) == p) || (strings.ToLower(*l.Protocol) == p) { 58 valid = true 59 } 60 } 61 } else { 62 valid = true 63 } 64 65 if valid { 66 listeners = append(listeners, l) 67 } else { 68 return nil, fmt.Errorf("[ERR] ELB Listener: ssl_certificate_id may be set only when protocol is 'https' or 'ssl'") 69 } 70 } 71 72 return listeners, nil 73 } 74 75 // Takes the result of flatmap. Expand for an array of listeners and 76 // returns ECS Volume compatible objects 77 func expandEcsVolumes(configured []interface{}) ([]*ecs.Volume, error) { 78 volumes := make([]*ecs.Volume, 0, len(configured)) 79 80 // Loop over our configured volumes and create 81 // an array of aws-sdk-go compatible objects 82 for _, lRaw := range configured { 83 data := lRaw.(map[string]interface{}) 84 85 l := &ecs.Volume{ 86 Name: aws.String(data["name"].(string)), 87 } 88 89 hostPath := data["host_path"].(string) 90 if hostPath != "" { 91 l.Host = &ecs.HostVolumeProperties{ 92 SourcePath: aws.String(hostPath), 93 } 94 } 95 96 volumes = append(volumes, l) 97 } 98 99 return volumes, nil 100 } 101 102 // Takes JSON in a string. Decodes JSON into 103 // an array of ecs.ContainerDefinition compatible objects 104 func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { 105 var definitions []*ecs.ContainerDefinition 106 107 err := json.Unmarshal([]byte(rawDefinitions), &definitions) 108 if err != nil { 109 return nil, fmt.Errorf("Error decoding JSON: %s", err) 110 } 111 112 return definitions, nil 113 } 114 115 // Takes the result of flatmap. Expand for an array of load balancers and 116 // returns ecs.LoadBalancer compatible objects 117 func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer { 118 loadBalancers := make([]*ecs.LoadBalancer, 0, len(configured)) 119 120 // Loop over our configured load balancers and create 121 // an array of aws-sdk-go compatible objects 122 for _, lRaw := range configured { 123 data := lRaw.(map[string]interface{}) 124 125 l := &ecs.LoadBalancer{ 126 ContainerName: aws.String(data["container_name"].(string)), 127 ContainerPort: aws.Int64(int64(data["container_port"].(int))), 128 LoadBalancerName: aws.String(data["elb_name"].(string)), 129 } 130 131 loadBalancers = append(loadBalancers, l) 132 } 133 134 return loadBalancers 135 } 136 137 // Takes the result of flatmap.Expand for an array of ingress/egress security 138 // group rules and returns EC2 API compatible objects. This function will error 139 // if it finds invalid permissions input, namely a protocol of "-1" with either 140 // to_port or from_port set to a non-zero value. 141 func expandIPPerms( 142 group *ec2.SecurityGroup, configured []interface{}) ([]*ec2.IpPermission, error) { 143 vpc := group.VpcId != nil && *group.VpcId != "" 144 145 perms := make([]*ec2.IpPermission, len(configured)) 146 for i, mRaw := range configured { 147 var perm ec2.IpPermission 148 m := mRaw.(map[string]interface{}) 149 150 perm.FromPort = aws.Int64(int64(m["from_port"].(int))) 151 perm.ToPort = aws.Int64(int64(m["to_port"].(int))) 152 perm.IpProtocol = aws.String(m["protocol"].(string)) 153 154 // When protocol is "-1", AWS won't store any ports for the 155 // rule, but also won't error if the user specifies ports other 156 // than '0'. Force the user to make a deliberate '0' port 157 // choice when specifying a "-1" protocol, and tell them about 158 // AWS's behavior in the error message. 159 if *perm.IpProtocol == "-1" && (*perm.FromPort != 0 || *perm.ToPort != 0) { 160 return nil, fmt.Errorf( 161 "from_port (%d) and to_port (%d) must both be 0 to use the the 'ALL' \"-1\" protocol!", 162 *perm.FromPort, *perm.ToPort) 163 } 164 165 var groups []string 166 if raw, ok := m["security_groups"]; ok { 167 list := raw.(*schema.Set).List() 168 for _, v := range list { 169 groups = append(groups, v.(string)) 170 } 171 } 172 if v, ok := m["self"]; ok && v.(bool) { 173 if vpc { 174 groups = append(groups, *group.GroupId) 175 } else { 176 groups = append(groups, *group.GroupName) 177 } 178 } 179 180 if len(groups) > 0 { 181 perm.UserIdGroupPairs = make([]*ec2.UserIdGroupPair, len(groups)) 182 for i, name := range groups { 183 ownerId, id := "", name 184 if items := strings.Split(id, "/"); len(items) > 1 { 185 ownerId, id = items[0], items[1] 186 } 187 188 perm.UserIdGroupPairs[i] = &ec2.UserIdGroupPair{ 189 GroupId: aws.String(id), 190 } 191 192 if ownerId != "" { 193 perm.UserIdGroupPairs[i].UserId = aws.String(ownerId) 194 } 195 196 if !vpc { 197 perm.UserIdGroupPairs[i].GroupId = nil 198 perm.UserIdGroupPairs[i].GroupName = aws.String(id) 199 } 200 } 201 } 202 203 if raw, ok := m["cidr_blocks"]; ok { 204 list := raw.([]interface{}) 205 for _, v := range list { 206 perm.IpRanges = append(perm.IpRanges, &ec2.IpRange{CidrIp: aws.String(v.(string))}) 207 } 208 } 209 210 perms[i] = &perm 211 } 212 213 return perms, nil 214 } 215 216 // Takes the result of flatmap.Expand for an array of parameters and 217 // returns Parameter API compatible objects 218 func expandParameters(configured []interface{}) ([]*rds.Parameter, error) { 219 var parameters []*rds.Parameter 220 221 // Loop over our configured parameters and create 222 // an array of aws-sdk-go compatabile objects 223 for _, pRaw := range configured { 224 data := pRaw.(map[string]interface{}) 225 226 if data["name"].(string) == "" { 227 continue 228 } 229 230 p := &rds.Parameter{ 231 ApplyMethod: aws.String(data["apply_method"].(string)), 232 ParameterName: aws.String(data["name"].(string)), 233 ParameterValue: aws.String(data["value"].(string)), 234 } 235 236 parameters = append(parameters, p) 237 } 238 239 return parameters, nil 240 } 241 242 func expandRedshiftParameters(configured []interface{}) ([]*redshift.Parameter, error) { 243 var parameters []*redshift.Parameter 244 245 // Loop over our configured parameters and create 246 // an array of aws-sdk-go compatabile objects 247 for _, pRaw := range configured { 248 data := pRaw.(map[string]interface{}) 249 250 if data["name"].(string) == "" { 251 continue 252 } 253 254 p := &redshift.Parameter{ 255 ParameterName: aws.String(data["name"].(string)), 256 ParameterValue: aws.String(data["value"].(string)), 257 } 258 259 parameters = append(parameters, p) 260 } 261 262 return parameters, nil 263 } 264 265 func expandOptionConfiguration(configured []interface{}) ([]*rds.OptionConfiguration, error) { 266 var option []*rds.OptionConfiguration 267 268 for _, pRaw := range configured { 269 data := pRaw.(map[string]interface{}) 270 271 o := &rds.OptionConfiguration{ 272 OptionName: aws.String(data["option_name"].(string)), 273 } 274 275 if raw, ok := data["port"]; ok { 276 port := raw.(int) 277 if port != 0 { 278 o.Port = aws.Int64(int64(port)) 279 } 280 } 281 282 if raw, ok := data["db_security_group_memberships"]; ok { 283 memberships := expandStringList(raw.(*schema.Set).List()) 284 if len(memberships) > 0 { 285 o.DBSecurityGroupMemberships = memberships 286 } 287 } 288 289 if raw, ok := data["vpc_security_group_memberships"]; ok { 290 memberships := expandStringList(raw.(*schema.Set).List()) 291 if len(memberships) > 0 { 292 o.VpcSecurityGroupMemberships = memberships 293 } 294 } 295 296 if raw, ok := data["option_settings"]; ok { 297 o.OptionSettings = expandOptionSetting(raw.(*schema.Set).List()) 298 } 299 300 option = append(option, o) 301 } 302 303 return option, nil 304 } 305 306 func expandOptionSetting(list []interface{}) []*rds.OptionSetting { 307 options := make([]*rds.OptionSetting, 0, len(list)) 308 309 for _, oRaw := range list { 310 data := oRaw.(map[string]interface{}) 311 312 o := &rds.OptionSetting{ 313 Name: aws.String(data["name"].(string)), 314 Value: aws.String(data["value"].(string)), 315 } 316 317 options = append(options, o) 318 } 319 320 return options 321 } 322 323 // Takes the result of flatmap.Expand for an array of parameters and 324 // returns Parameter API compatible objects 325 func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) { 326 parameters := make([]*elasticache.ParameterNameValue, 0, len(configured)) 327 328 // Loop over our configured parameters and create 329 // an array of aws-sdk-go compatabile objects 330 for _, pRaw := range configured { 331 data := pRaw.(map[string]interface{}) 332 333 p := &elasticache.ParameterNameValue{ 334 ParameterName: aws.String(data["name"].(string)), 335 ParameterValue: aws.String(data["value"].(string)), 336 } 337 338 parameters = append(parameters, p) 339 } 340 341 return parameters, nil 342 } 343 344 // Flattens an access log into something that flatmap.Flatten() can handle 345 func flattenAccessLog(l *elb.AccessLog) []map[string]interface{} { 346 result := make([]map[string]interface{}, 0, 1) 347 348 if l != nil && *l.Enabled { 349 r := make(map[string]interface{}) 350 if l.S3BucketName != nil { 351 r["bucket"] = *l.S3BucketName 352 } 353 354 if l.S3BucketPrefix != nil { 355 r["bucket_prefix"] = *l.S3BucketPrefix 356 } 357 358 if l.EmitInterval != nil { 359 r["interval"] = *l.EmitInterval 360 } 361 362 result = append(result, r) 363 } 364 365 return result 366 } 367 368 // Takes the result of flatmap.Expand for an array of step adjustments and 369 // returns a []*autoscaling.StepAdjustment. 370 func expandStepAdjustments(configured []interface{}) ([]*autoscaling.StepAdjustment, error) { 371 var adjustments []*autoscaling.StepAdjustment 372 373 // Loop over our configured step adjustments and create an array 374 // of aws-sdk-go compatible objects. We're forced to convert strings 375 // to floats here because there's no way to detect whether or not 376 // an uninitialized, optional schema element is "0.0" deliberately. 377 // With strings, we can test for "", which is definitely an empty 378 // struct value. 379 for _, raw := range configured { 380 data := raw.(map[string]interface{}) 381 a := &autoscaling.StepAdjustment{ 382 ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))), 383 } 384 if data["metric_interval_lower_bound"] != "" { 385 bound := data["metric_interval_lower_bound"] 386 switch bound := bound.(type) { 387 case string: 388 f, err := strconv.ParseFloat(bound, 64) 389 if err != nil { 390 return nil, fmt.Errorf( 391 "metric_interval_lower_bound must be a float value represented as a string") 392 } 393 a.MetricIntervalLowerBound = aws.Float64(f) 394 default: 395 return nil, fmt.Errorf( 396 "metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.") 397 } 398 } 399 if data["metric_interval_upper_bound"] != "" { 400 bound := data["metric_interval_upper_bound"] 401 switch bound := bound.(type) { 402 case string: 403 f, err := strconv.ParseFloat(bound, 64) 404 if err != nil { 405 return nil, fmt.Errorf( 406 "metric_interval_upper_bound must be a float value represented as a string") 407 } 408 a.MetricIntervalUpperBound = aws.Float64(f) 409 default: 410 return nil, fmt.Errorf( 411 "metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.") 412 } 413 } 414 adjustments = append(adjustments, a) 415 } 416 417 return adjustments, nil 418 } 419 420 // Flattens a health check into something that flatmap.Flatten() 421 // can handle 422 func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} { 423 result := make([]map[string]interface{}, 0, 1) 424 425 chk := make(map[string]interface{}) 426 chk["unhealthy_threshold"] = *check.UnhealthyThreshold 427 chk["healthy_threshold"] = *check.HealthyThreshold 428 chk["target"] = *check.Target 429 chk["timeout"] = *check.Timeout 430 chk["interval"] = *check.Interval 431 432 result = append(result, chk) 433 434 return result 435 } 436 437 // Flattens an array of UserSecurityGroups into a []*ec2.GroupIdentifier 438 func flattenSecurityGroups(list []*ec2.UserIdGroupPair, ownerId *string) []*ec2.GroupIdentifier { 439 result := make([]*ec2.GroupIdentifier, 0, len(list)) 440 for _, g := range list { 441 var userId *string 442 if g.UserId != nil && *g.UserId != "" && (ownerId == nil || *ownerId != *g.UserId) { 443 userId = g.UserId 444 } 445 // userid nil here for same vpc groups 446 447 vpc := g.GroupName == nil || *g.GroupName == "" 448 var id *string 449 if vpc { 450 id = g.GroupId 451 } else { 452 id = g.GroupName 453 } 454 455 // id is groupid for vpcs 456 // id is groupname for non vpc (classic) 457 458 if userId != nil { 459 id = aws.String(*userId + "/" + *id) 460 } 461 462 if vpc { 463 result = append(result, &ec2.GroupIdentifier{ 464 GroupId: id, 465 }) 466 } else { 467 result = append(result, &ec2.GroupIdentifier{ 468 GroupId: g.GroupId, 469 GroupName: id, 470 }) 471 } 472 } 473 return result 474 } 475 476 // Flattens an array of Instances into a []string 477 func flattenInstances(list []*elb.Instance) []string { 478 result := make([]string, 0, len(list)) 479 for _, i := range list { 480 result = append(result, *i.InstanceId) 481 } 482 return result 483 } 484 485 // Expands an array of String Instance IDs into a []Instances 486 func expandInstanceString(list []interface{}) []*elb.Instance { 487 result := make([]*elb.Instance, 0, len(list)) 488 for _, i := range list { 489 result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))}) 490 } 491 return result 492 } 493 494 // Flattens an array of Backend Descriptions into a a map of instance_port to policy names. 495 func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string { 496 policies := make(map[int64][]string) 497 for _, i := range backends { 498 for _, p := range i.PolicyNames { 499 policies[*i.InstancePort] = append(policies[*i.InstancePort], *p) 500 } 501 sort.Strings(policies[*i.InstancePort]) 502 } 503 return policies 504 } 505 506 // Flattens an array of Listeners into a []map[string]interface{} 507 func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} { 508 result := make([]map[string]interface{}, 0, len(list)) 509 for _, i := range list { 510 l := map[string]interface{}{ 511 "instance_port": *i.Listener.InstancePort, 512 "instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol), 513 "lb_port": *i.Listener.LoadBalancerPort, 514 "lb_protocol": strings.ToLower(*i.Listener.Protocol), 515 } 516 // SSLCertificateID is optional, and may be nil 517 if i.Listener.SSLCertificateId != nil { 518 l["ssl_certificate_id"] = *i.Listener.SSLCertificateId 519 } 520 result = append(result, l) 521 } 522 return result 523 } 524 525 // Flattens an array of Volumes into a []map[string]interface{} 526 func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { 527 result := make([]map[string]interface{}, 0, len(list)) 528 for _, volume := range list { 529 l := map[string]interface{}{ 530 "name": *volume.Name, 531 } 532 533 if volume.Host.SourcePath != nil { 534 l["host_path"] = *volume.Host.SourcePath 535 } 536 537 result = append(result, l) 538 } 539 return result 540 } 541 542 // Flattens an array of ECS LoadBalancers into a []map[string]interface{} 543 func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} { 544 result := make([]map[string]interface{}, 0, len(list)) 545 for _, loadBalancer := range list { 546 l := map[string]interface{}{ 547 "elb_name": *loadBalancer.LoadBalancerName, 548 "container_name": *loadBalancer.ContainerName, 549 "container_port": *loadBalancer.ContainerPort, 550 } 551 result = append(result, l) 552 } 553 return result 554 } 555 556 // Encodes an array of ecs.ContainerDefinitions into a JSON string 557 func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { 558 byteArray, err := json.Marshal(definitions) 559 if err != nil { 560 return "", fmt.Errorf("Error encoding to JSON: %s", err) 561 } 562 563 n := bytes.Index(byteArray, []byte{0}) 564 return string(byteArray[:n]), nil 565 } 566 567 // Flattens an array of Options into a []map[string]interface{} 568 func flattenOptions(list []*rds.Option) []map[string]interface{} { 569 result := make([]map[string]interface{}, 0, len(list)) 570 for _, i := range list { 571 if i.OptionName != nil { 572 r := make(map[string]interface{}) 573 r["option_name"] = strings.ToLower(*i.OptionName) 574 // Default empty string, guard against nil parameter values 575 r["port"] = "" 576 if i.Port != nil { 577 r["port"] = int(*i.Port) 578 } 579 if i.VpcSecurityGroupMemberships != nil { 580 vpcs := make([]string, 0, len(i.VpcSecurityGroupMemberships)) 581 for _, vpc := range i.VpcSecurityGroupMemberships { 582 id := vpc.VpcSecurityGroupId 583 vpcs = append(vpcs, *id) 584 } 585 586 r["vpc_security_group_memberships"] = vpcs 587 } 588 if i.DBSecurityGroupMemberships != nil { 589 dbs := make([]string, 0, len(i.DBSecurityGroupMemberships)) 590 for _, db := range i.DBSecurityGroupMemberships { 591 id := db.DBSecurityGroupName 592 dbs = append(dbs, *id) 593 } 594 595 r["db_security_group_memberships"] = dbs 596 } 597 if i.OptionSettings != nil { 598 settings := make([]map[string]interface{}, 0, len(i.OptionSettings)) 599 for _, j := range i.OptionSettings { 600 settings = append(settings, map[string]interface{}{ 601 "name": *j.Name, 602 "value": *j.Value, 603 }) 604 } 605 606 r["option_settings"] = settings 607 } 608 result = append(result, r) 609 } 610 } 611 return result 612 } 613 614 // Flattens an array of Parameters into a []map[string]interface{} 615 func flattenParameters(list []*rds.Parameter) []map[string]interface{} { 616 result := make([]map[string]interface{}, 0, len(list)) 617 for _, i := range list { 618 if i.ParameterName != nil { 619 r := make(map[string]interface{}) 620 r["name"] = strings.ToLower(*i.ParameterName) 621 // Default empty string, guard against nil parameter values 622 r["value"] = "" 623 if i.ParameterValue != nil { 624 r["value"] = strings.ToLower(*i.ParameterValue) 625 } 626 result = append(result, r) 627 } 628 } 629 return result 630 } 631 632 // Flattens an array of Redshift Parameters into a []map[string]interface{} 633 func flattenRedshiftParameters(list []*redshift.Parameter) []map[string]interface{} { 634 result := make([]map[string]interface{}, 0, len(list)) 635 for _, i := range list { 636 result = append(result, map[string]interface{}{ 637 "name": strings.ToLower(*i.ParameterName), 638 "value": strings.ToLower(*i.ParameterValue), 639 }) 640 } 641 return result 642 } 643 644 // Flattens an array of Parameters into a []map[string]interface{} 645 func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} { 646 result := make([]map[string]interface{}, 0, len(list)) 647 for _, i := range list { 648 if i.ParameterValue != nil { 649 result = append(result, map[string]interface{}{ 650 "name": strings.ToLower(*i.ParameterName), 651 "value": strings.ToLower(*i.ParameterValue), 652 }) 653 } 654 } 655 return result 656 } 657 658 // Takes the result of flatmap.Expand for an array of strings 659 // and returns a []*string 660 func expandStringList(configured []interface{}) []*string { 661 vs := make([]*string, 0, len(configured)) 662 for _, v := range configured { 663 vs = append(vs, aws.String(v.(string))) 664 } 665 return vs 666 } 667 668 // Takes the result of schema.Set of strings and returns a []*string 669 func expandStringSet(configured *schema.Set) []*string { 670 return expandStringList(configured.List()) 671 } 672 673 // Takes list of pointers to strings. Expand to an array 674 // of raw strings and returns a []interface{} 675 // to keep compatibility w/ schema.NewSetschema.NewSet 676 func flattenStringList(list []*string) []interface{} { 677 vs := make([]interface{}, 0, len(list)) 678 for _, v := range list { 679 vs = append(vs, *v) 680 } 681 return vs 682 } 683 684 //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0" 685 func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string { 686 ips := make([]string, 0, len(dtos)) 687 for _, v := range dtos { 688 ip := *v.PrivateIpAddress 689 ips = append(ips, ip) 690 } 691 return ips 692 } 693 694 //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs 695 func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string { 696 ids := make([]string, 0, len(dtos)) 697 for _, v := range dtos { 698 group_id := *v.GroupId 699 ids = append(ids, group_id) 700 } 701 return ids 702 } 703 704 //Expands an array of IPs into a ec2 Private IP Address Spec 705 func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification { 706 dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips)) 707 for i, v := range ips { 708 new_private_ip := &ec2.PrivateIpAddressSpecification{ 709 PrivateIpAddress: aws.String(v.(string)), 710 } 711 712 new_private_ip.Primary = aws.Bool(i == 0) 713 714 dtos = append(dtos, new_private_ip) 715 } 716 return dtos 717 } 718 719 //Flattens network interface attachment into a map[string]interface 720 func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} { 721 att := make(map[string]interface{}) 722 att["instance"] = *a.InstanceId 723 att["device_index"] = *a.DeviceIndex 724 att["attachment_id"] = *a.AttachmentId 725 return att 726 } 727 728 // Flattens step adjustments into a list of map[string]interface. 729 func flattenStepAdjustments(adjustments []*autoscaling.StepAdjustment) []map[string]interface{} { 730 result := make([]map[string]interface{}, 0, len(adjustments)) 731 for _, raw := range adjustments { 732 a := map[string]interface{}{ 733 "scaling_adjustment": *raw.ScalingAdjustment, 734 } 735 if raw.MetricIntervalUpperBound != nil { 736 a["metric_interval_upper_bound"] = *raw.MetricIntervalUpperBound 737 } 738 if raw.MetricIntervalLowerBound != nil { 739 a["metric_interval_lower_bound"] = *raw.MetricIntervalLowerBound 740 } 741 result = append(result, a) 742 } 743 return result 744 } 745 746 func flattenResourceRecords(recs []*route53.ResourceRecord) []string { 747 strs := make([]string, 0, len(recs)) 748 for _, r := range recs { 749 if r.Value != nil { 750 s := strings.Replace(*r.Value, "\"", "", 2) 751 strs = append(strs, s) 752 } 753 } 754 return strs 755 } 756 757 func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord { 758 records := make([]*route53.ResourceRecord, 0, len(recs)) 759 for _, r := range recs { 760 s := r.(string) 761 switch typeStr { 762 case "TXT", "SPF": 763 str := fmt.Sprintf("\"%s\"", s) 764 records = append(records, &route53.ResourceRecord{Value: aws.String(str)}) 765 default: 766 records = append(records, &route53.ResourceRecord{Value: aws.String(s)}) 767 } 768 } 769 return records 770 } 771 772 func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig { 773 config := elasticsearch.ElasticsearchClusterConfig{} 774 775 if v, ok := m["dedicated_master_enabled"]; ok { 776 isEnabled := v.(bool) 777 config.DedicatedMasterEnabled = aws.Bool(isEnabled) 778 779 if isEnabled { 780 if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 { 781 config.DedicatedMasterCount = aws.Int64(int64(v.(int))) 782 } 783 if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" { 784 config.DedicatedMasterType = aws.String(v.(string)) 785 } 786 } 787 } 788 789 if v, ok := m["instance_count"]; ok { 790 config.InstanceCount = aws.Int64(int64(v.(int))) 791 } 792 if v, ok := m["instance_type"]; ok { 793 config.InstanceType = aws.String(v.(string)) 794 } 795 796 if v, ok := m["zone_awareness_enabled"]; ok { 797 config.ZoneAwarenessEnabled = aws.Bool(v.(bool)) 798 } 799 800 return &config 801 } 802 803 func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} { 804 m := map[string]interface{}{} 805 806 if c.DedicatedMasterCount != nil { 807 m["dedicated_master_count"] = *c.DedicatedMasterCount 808 } 809 if c.DedicatedMasterEnabled != nil { 810 m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled 811 } 812 if c.DedicatedMasterType != nil { 813 m["dedicated_master_type"] = *c.DedicatedMasterType 814 } 815 if c.InstanceCount != nil { 816 m["instance_count"] = *c.InstanceCount 817 } 818 if c.InstanceType != nil { 819 m["instance_type"] = *c.InstanceType 820 } 821 if c.ZoneAwarenessEnabled != nil { 822 m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled 823 } 824 825 return []map[string]interface{}{m} 826 } 827 828 func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} { 829 m := map[string]interface{}{} 830 831 if o.EBSEnabled != nil { 832 m["ebs_enabled"] = *o.EBSEnabled 833 } 834 if o.Iops != nil { 835 m["iops"] = *o.Iops 836 } 837 if o.VolumeSize != nil { 838 m["volume_size"] = *o.VolumeSize 839 } 840 if o.VolumeType != nil { 841 m["volume_type"] = *o.VolumeType 842 } 843 844 return []map[string]interface{}{m} 845 } 846 847 func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions { 848 options := elasticsearch.EBSOptions{} 849 850 if v, ok := m["ebs_enabled"]; ok { 851 options.EBSEnabled = aws.Bool(v.(bool)) 852 } 853 if v, ok := m["iops"]; ok && v.(int) > 0 { 854 options.Iops = aws.Int64(int64(v.(int))) 855 } 856 if v, ok := m["volume_size"]; ok && v.(int) > 0 { 857 options.VolumeSize = aws.Int64(int64(v.(int))) 858 } 859 if v, ok := m["volume_type"]; ok && v.(string) != "" { 860 options.VolumeType = aws.String(v.(string)) 861 } 862 863 return &options 864 } 865 866 func pointersMapToStringList(pointers map[string]*string) map[string]interface{} { 867 list := make(map[string]interface{}, len(pointers)) 868 for i, v := range pointers { 869 list[i] = *v 870 } 871 return list 872 } 873 874 func stringMapToPointers(m map[string]interface{}) map[string]*string { 875 list := make(map[string]*string, len(m)) 876 for i, v := range m { 877 list[i] = aws.String(v.(string)) 878 } 879 return list 880 } 881 882 func flattenDSVpcSettings( 883 s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} { 884 settings := make(map[string]interface{}, 0) 885 886 if s == nil { 887 return nil 888 } 889 890 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 891 settings["vpc_id"] = *s.VpcId 892 893 return []map[string]interface{}{settings} 894 } 895 896 func flattenLambdaVpcConfigResponse(s *lambda.VpcConfigResponse) []map[string]interface{} { 897 settings := make(map[string]interface{}, 0) 898 899 if s == nil { 900 return nil 901 } 902 903 if len(s.SubnetIds) == 0 && len(s.SecurityGroupIds) == 0 && s.VpcId == nil { 904 return nil 905 } 906 907 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 908 settings["security_group_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SecurityGroupIds)) 909 if s.VpcId != nil { 910 settings["vpc_id"] = *s.VpcId 911 } 912 913 return []map[string]interface{}{settings} 914 } 915 916 func flattenDSConnectSettings( 917 customerDnsIps []*string, 918 s *directoryservice.DirectoryConnectSettingsDescription) []map[string]interface{} { 919 if s == nil { 920 return nil 921 } 922 923 settings := make(map[string]interface{}, 0) 924 925 settings["customer_dns_ips"] = schema.NewSet(schema.HashString, flattenStringList(customerDnsIps)) 926 settings["connect_ips"] = schema.NewSet(schema.HashString, flattenStringList(s.ConnectIps)) 927 settings["customer_username"] = *s.CustomerUserName 928 settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds)) 929 settings["vpc_id"] = *s.VpcId 930 931 return []map[string]interface{}{settings} 932 } 933 934 func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter { 935 var cfParams []*cloudformation.Parameter 936 for k, v := range params { 937 cfParams = append(cfParams, &cloudformation.Parameter{ 938 ParameterKey: aws.String(k), 939 ParameterValue: aws.String(v.(string)), 940 }) 941 } 942 943 return cfParams 944 } 945 946 // flattenCloudFormationParameters is flattening list of 947 // *cloudformation.Parameters and only returning existing 948 // parameters to avoid clash with default values 949 func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter, 950 originalParams map[string]interface{}) map[string]interface{} { 951 params := make(map[string]interface{}, len(cfParams)) 952 for _, p := range cfParams { 953 _, isConfigured := originalParams[*p.ParameterKey] 954 if isConfigured { 955 params[*p.ParameterKey] = *p.ParameterValue 956 } 957 } 958 return params 959 } 960 961 func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag { 962 var cfTags []*cloudformation.Tag 963 for k, v := range tags { 964 cfTags = append(cfTags, &cloudformation.Tag{ 965 Key: aws.String(k), 966 Value: aws.String(v.(string)), 967 }) 968 } 969 return cfTags 970 } 971 972 func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string { 973 tags := make(map[string]string, len(cfTags)) 974 for _, t := range cfTags { 975 tags[*t.Key] = *t.Value 976 } 977 return tags 978 } 979 980 func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string { 981 outputs := make(map[string]string, len(cfOutputs)) 982 for _, o := range cfOutputs { 983 outputs[*o.OutputKey] = *o.OutputValue 984 } 985 return outputs 986 } 987 988 func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string { 989 strs := make([]string, 0, len(list)) 990 for _, r := range list { 991 if r.Metric != nil { 992 strs = append(strs, *r.Metric) 993 } 994 } 995 return strs 996 } 997 998 func expandApiGatewayStageKeys(d *schema.ResourceData) []*apigateway.StageKey { 999 var stageKeys []*apigateway.StageKey 1000 1001 if stageKeyData, ok := d.GetOk("stage_key"); ok { 1002 params := stageKeyData.(*schema.Set).List() 1003 for k := range params { 1004 data := params[k].(map[string]interface{}) 1005 stageKeys = append(stageKeys, &apigateway.StageKey{ 1006 RestApiId: aws.String(data["rest_api_id"].(string)), 1007 StageName: aws.String(data["stage_name"].(string)), 1008 }) 1009 } 1010 } 1011 1012 return stageKeys 1013 } 1014 1015 func expandApiGatewayRequestResponseModelOperations(d *schema.ResourceData, key string, prefix string) []*apigateway.PatchOperation { 1016 operations := make([]*apigateway.PatchOperation, 0) 1017 1018 oldModels, newModels := d.GetChange(key) 1019 oldModelMap := oldModels.(map[string]interface{}) 1020 newModelMap := newModels.(map[string]interface{}) 1021 1022 for k, _ := range oldModelMap { 1023 operation := apigateway.PatchOperation{ 1024 Op: aws.String("remove"), 1025 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))), 1026 } 1027 1028 for nK, nV := range newModelMap { 1029 if nK == k { 1030 operation.Op = aws.String("replace") 1031 operation.Value = aws.String(nV.(string)) 1032 } 1033 } 1034 1035 operations = append(operations, &operation) 1036 } 1037 1038 for nK, nV := range newModelMap { 1039 exists := false 1040 for k, _ := range oldModelMap { 1041 if k == nK { 1042 exists = true 1043 } 1044 } 1045 if !exists { 1046 operation := apigateway.PatchOperation{ 1047 Op: aws.String("add"), 1048 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(nK, "/", "~1", -1))), 1049 Value: aws.String(nV.(string)), 1050 } 1051 operations = append(operations, &operation) 1052 } 1053 } 1054 1055 return operations 1056 } 1057 1058 func expandApiGatewayMethodParametersJSONOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) { 1059 operations := make([]*apigateway.PatchOperation, 0) 1060 1061 oldParameters, newParameters := d.GetChange(key) 1062 oldParametersMap := make(map[string]interface{}) 1063 newParametersMap := make(map[string]interface{}) 1064 1065 if err := json.Unmarshal([]byte(oldParameters.(string)), &oldParametersMap); err != nil { 1066 err := fmt.Errorf("Error unmarshaling old %s: %s", key, err) 1067 return operations, err 1068 } 1069 1070 if err := json.Unmarshal([]byte(newParameters.(string)), &newParametersMap); err != nil { 1071 err := fmt.Errorf("Error unmarshaling new %s: %s", key, err) 1072 return operations, err 1073 } 1074 1075 for k, _ := range oldParametersMap { 1076 operation := apigateway.PatchOperation{ 1077 Op: aws.String("remove"), 1078 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)), 1079 } 1080 1081 for nK, nV := range newParametersMap { 1082 if nK == k { 1083 operation.Op = aws.String("replace") 1084 operation.Value = aws.String(strconv.FormatBool(nV.(bool))) 1085 } 1086 } 1087 1088 operations = append(operations, &operation) 1089 } 1090 1091 for nK, nV := range newParametersMap { 1092 exists := false 1093 for k, _ := range oldParametersMap { 1094 if k == nK { 1095 exists = true 1096 } 1097 } 1098 if !exists { 1099 operation := apigateway.PatchOperation{ 1100 Op: aws.String("add"), 1101 Path: aws.String(fmt.Sprintf("/%s/%s", prefix, nK)), 1102 Value: aws.String(strconv.FormatBool(nV.(bool))), 1103 } 1104 operations = append(operations, &operation) 1105 } 1106 } 1107 1108 return operations, nil 1109 } 1110 1111 func expandApiGatewayStageKeyOperations(d *schema.ResourceData) []*apigateway.PatchOperation { 1112 operations := make([]*apigateway.PatchOperation, 0) 1113 1114 prev, curr := d.GetChange("stage_key") 1115 prevList := prev.(*schema.Set).List() 1116 currList := curr.(*schema.Set).List() 1117 1118 for i := range prevList { 1119 p := prevList[i].(map[string]interface{}) 1120 exists := false 1121 1122 for j := range currList { 1123 c := currList[j].(map[string]interface{}) 1124 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1125 exists = true 1126 } 1127 } 1128 1129 if !exists { 1130 operations = append(operations, &apigateway.PatchOperation{ 1131 Op: aws.String("remove"), 1132 Path: aws.String("/stages"), 1133 Value: aws.String(fmt.Sprintf("%s/%s", p["rest_api_id"].(string), p["stage_name"].(string))), 1134 }) 1135 } 1136 } 1137 1138 for i := range currList { 1139 c := currList[i].(map[string]interface{}) 1140 exists := false 1141 1142 for j := range prevList { 1143 p := prevList[j].(map[string]interface{}) 1144 if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) { 1145 exists = true 1146 } 1147 } 1148 1149 if !exists { 1150 operations = append(operations, &apigateway.PatchOperation{ 1151 Op: aws.String("add"), 1152 Path: aws.String("/stages"), 1153 Value: aws.String(fmt.Sprintf("%s/%s", c["rest_api_id"].(string), c["stage_name"].(string))), 1154 }) 1155 } 1156 } 1157 1158 return operations 1159 } 1160 1161 func expandCloudWachLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation { 1162 transformation := cloudwatchlogs.MetricTransformation{ 1163 MetricName: aws.String(m["name"].(string)), 1164 MetricNamespace: aws.String(m["namespace"].(string)), 1165 MetricValue: aws.String(m["value"].(string)), 1166 } 1167 1168 return []*cloudwatchlogs.MetricTransformation{&transformation} 1169 } 1170 1171 func flattenCloudWachLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) map[string]string { 1172 m := make(map[string]string, 0) 1173 1174 m["name"] = *ts[0].MetricName 1175 m["namespace"] = *ts[0].MetricNamespace 1176 m["value"] = *ts[0].MetricValue 1177 1178 return m 1179 } 1180 1181 func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string { 1182 strs := make([]string, 0, len(list)) 1183 for _, r := range list { 1184 if r.Name != nil { 1185 strs = append(strs, *r.Name) 1186 } 1187 } 1188 return strs 1189 } 1190 1191 func flattenBeanstalkInstances(list []*elasticbeanstalk.Instance) []string { 1192 strs := make([]string, 0, len(list)) 1193 for _, r := range list { 1194 if r.Id != nil { 1195 strs = append(strs, *r.Id) 1196 } 1197 } 1198 return strs 1199 } 1200 1201 func flattenBeanstalkLc(list []*elasticbeanstalk.LaunchConfiguration) []string { 1202 strs := make([]string, 0, len(list)) 1203 for _, r := range list { 1204 if r.Name != nil { 1205 strs = append(strs, *r.Name) 1206 } 1207 } 1208 return strs 1209 } 1210 1211 func flattenBeanstalkElb(list []*elasticbeanstalk.LoadBalancer) []string { 1212 strs := make([]string, 0, len(list)) 1213 for _, r := range list { 1214 if r.Name != nil { 1215 strs = append(strs, *r.Name) 1216 } 1217 } 1218 return strs 1219 } 1220 1221 func flattenBeanstalkSqs(list []*elasticbeanstalk.Queue) []string { 1222 strs := make([]string, 0, len(list)) 1223 for _, r := range list { 1224 if r.URL != nil { 1225 strs = append(strs, *r.URL) 1226 } 1227 } 1228 return strs 1229 } 1230 1231 func flattenBeanstalkTrigger(list []*elasticbeanstalk.Trigger) []string { 1232 strs := make([]string, 0, len(list)) 1233 for _, r := range list { 1234 if r.Name != nil { 1235 strs = append(strs, *r.Name) 1236 } 1237 } 1238 return strs 1239 } 1240 1241 // There are several parts of the AWS API that will sort lists of strings, 1242 // causing diffs inbetweeen resources that use lists. This avoids a bit of 1243 // code duplication for pre-sorts that can be used for things like hash 1244 // functions, etc. 1245 func sortInterfaceSlice(in []interface{}) []interface{} { 1246 a := []string{} 1247 b := []interface{}{} 1248 for _, v := range in { 1249 a = append(a, v.(string)) 1250 } 1251 1252 sort.Strings(a) 1253 1254 for _, v := range a { 1255 b = append(b, v) 1256 } 1257 1258 return b 1259 } 1260 1261 func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) []map[string]interface{} { 1262 result := make([]map[string]interface{}, 0, 1) 1263 1264 if settings != nil { 1265 r := make(map[string]interface{}) 1266 if settings.BurstLimit != nil { 1267 r["burst_limit"] = *settings.BurstLimit 1268 } 1269 1270 if settings.RateLimit != nil { 1271 r["rate_limit"] = *settings.RateLimit 1272 } 1273 1274 result = append(result, r) 1275 } 1276 1277 return result 1278 }