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