github.com/shvar/terraform@v0.6.9-0.20151215234924-3365cd2231df/builtin/providers/aws/structure.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"regexp"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/service/cloudformation"
    13  	"github.com/aws/aws-sdk-go/service/directoryservice"
    14  	"github.com/aws/aws-sdk-go/service/ec2"
    15  	"github.com/aws/aws-sdk-go/service/ecs"
    16  	"github.com/aws/aws-sdk-go/service/elasticache"
    17  	elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
    18  	"github.com/aws/aws-sdk-go/service/elb"
    19  	"github.com/aws/aws-sdk-go/service/rds"
    20  	"github.com/aws/aws-sdk-go/service/route53"
    21  	"github.com/hashicorp/terraform/helper/schema"
    22  )
    23  
    24  // Takes the result of flatmap.Expand for an array of listeners and
    25  // returns ELB API compatible objects
    26  func expandListeners(configured []interface{}) ([]*elb.Listener, error) {
    27  	listeners := make([]*elb.Listener, 0, len(configured))
    28  
    29  	// Loop over our configured listeners and create
    30  	// an array of aws-sdk-go compatabile objects
    31  	for _, lRaw := range configured {
    32  		data := lRaw.(map[string]interface{})
    33  
    34  		ip := int64(data["instance_port"].(int))
    35  		lp := int64(data["lb_port"].(int))
    36  		l := &elb.Listener{
    37  			InstancePort:     &ip,
    38  			InstanceProtocol: aws.String(data["instance_protocol"].(string)),
    39  			LoadBalancerPort: &lp,
    40  			Protocol:         aws.String(data["lb_protocol"].(string)),
    41  		}
    42  
    43  		if v, ok := data["ssl_certificate_id"]; ok {
    44  			l.SSLCertificateId = aws.String(v.(string))
    45  		}
    46  
    47  		var valid bool
    48  		if l.SSLCertificateId != nil && *l.SSLCertificateId != "" {
    49  			// validate the protocol is correct
    50  			for _, p := range []string{"https", "ssl"} {
    51  				if (*l.InstanceProtocol == p) || (*l.Protocol == p) {
    52  					valid = true
    53  				}
    54  			}
    55  		} else {
    56  			valid = true
    57  		}
    58  
    59  		if valid {
    60  			listeners = append(listeners, l)
    61  		} else {
    62  			return nil, fmt.Errorf("[ERR] ELB Listener: ssl_certificate_id may be set only when protocol is 'https' or 'ssl'")
    63  		}
    64  	}
    65  
    66  	return listeners, nil
    67  }
    68  
    69  // Takes the result of flatmap. Expand for an array of listeners and
    70  // returns ECS Volume compatible objects
    71  func expandEcsVolumes(configured []interface{}) ([]*ecs.Volume, error) {
    72  	volumes := make([]*ecs.Volume, 0, len(configured))
    73  
    74  	// Loop over our configured volumes and create
    75  	// an array of aws-sdk-go compatible objects
    76  	for _, lRaw := range configured {
    77  		data := lRaw.(map[string]interface{})
    78  
    79  		l := &ecs.Volume{
    80  			Name: aws.String(data["name"].(string)),
    81  		}
    82  
    83  		hostPath := data["host_path"].(string)
    84  		if hostPath != "" {
    85  			l.Host = &ecs.HostVolumeProperties{
    86  				SourcePath: aws.String(hostPath),
    87  			}
    88  		}
    89  
    90  		volumes = append(volumes, l)
    91  	}
    92  
    93  	return volumes, nil
    94  }
    95  
    96  // Takes JSON in a string. Decodes JSON into
    97  // an array of ecs.ContainerDefinition compatible objects
    98  func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) {
    99  	var definitions []*ecs.ContainerDefinition
   100  
   101  	err := json.Unmarshal([]byte(rawDefinitions), &definitions)
   102  	if err != nil {
   103  		return nil, fmt.Errorf("Error decoding JSON: %s", err)
   104  	}
   105  
   106  	return definitions, nil
   107  }
   108  
   109  // Takes the result of flatmap. Expand for an array of load balancers and
   110  // returns ecs.LoadBalancer compatible objects
   111  func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer {
   112  	loadBalancers := make([]*ecs.LoadBalancer, 0, len(configured))
   113  
   114  	// Loop over our configured load balancers and create
   115  	// an array of aws-sdk-go compatible objects
   116  	for _, lRaw := range configured {
   117  		data := lRaw.(map[string]interface{})
   118  
   119  		l := &ecs.LoadBalancer{
   120  			ContainerName:    aws.String(data["container_name"].(string)),
   121  			ContainerPort:    aws.Int64(int64(data["container_port"].(int))),
   122  			LoadBalancerName: aws.String(data["elb_name"].(string)),
   123  		}
   124  
   125  		loadBalancers = append(loadBalancers, l)
   126  	}
   127  
   128  	return loadBalancers
   129  }
   130  
   131  // Takes the result of flatmap.Expand for an array of ingress/egress security
   132  // group rules and returns EC2 API compatible objects. This function will error
   133  // if it finds invalid permissions input, namely a protocol of "-1" with either
   134  // to_port or from_port set to a non-zero value.
   135  func expandIPPerms(
   136  	group *ec2.SecurityGroup, configured []interface{}) ([]*ec2.IpPermission, error) {
   137  	vpc := group.VpcId != nil
   138  
   139  	perms := make([]*ec2.IpPermission, len(configured))
   140  	for i, mRaw := range configured {
   141  		var perm ec2.IpPermission
   142  		m := mRaw.(map[string]interface{})
   143  
   144  		perm.FromPort = aws.Int64(int64(m["from_port"].(int)))
   145  		perm.ToPort = aws.Int64(int64(m["to_port"].(int)))
   146  		perm.IpProtocol = aws.String(m["protocol"].(string))
   147  
   148  		// When protocol is "-1", AWS won't store any ports for the
   149  		// rule, but also won't error if the user specifies ports other
   150  		// than '0'. Force the user to make a deliberate '0' port
   151  		// choice when specifying a "-1" protocol, and tell them about
   152  		// AWS's behavior in the error message.
   153  		if *perm.IpProtocol == "-1" && (*perm.FromPort != 0 || *perm.ToPort != 0) {
   154  			return nil, fmt.Errorf(
   155  				"from_port (%d) and to_port (%d) must both be 0 to use the the 'ALL' \"-1\" protocol!",
   156  				*perm.FromPort, *perm.ToPort)
   157  		}
   158  
   159  		var groups []string
   160  		if raw, ok := m["security_groups"]; ok {
   161  			list := raw.(*schema.Set).List()
   162  			for _, v := range list {
   163  				groups = append(groups, v.(string))
   164  			}
   165  		}
   166  		if v, ok := m["self"]; ok && v.(bool) {
   167  			if vpc {
   168  				groups = append(groups, *group.GroupId)
   169  			} else {
   170  				groups = append(groups, *group.GroupName)
   171  			}
   172  		}
   173  
   174  		if len(groups) > 0 {
   175  			perm.UserIdGroupPairs = make([]*ec2.UserIdGroupPair, len(groups))
   176  			for i, name := range groups {
   177  				ownerId, id := "", name
   178  				if items := strings.Split(id, "/"); len(items) > 1 {
   179  					ownerId, id = items[0], items[1]
   180  				}
   181  
   182  				perm.UserIdGroupPairs[i] = &ec2.UserIdGroupPair{
   183  					GroupId: aws.String(id),
   184  				}
   185  
   186  				if ownerId != "" {
   187  					perm.UserIdGroupPairs[i].UserId = aws.String(ownerId)
   188  				}
   189  
   190  				if !vpc {
   191  					perm.UserIdGroupPairs[i].GroupId = nil
   192  					perm.UserIdGroupPairs[i].GroupName = aws.String(id)
   193  				}
   194  			}
   195  		}
   196  
   197  		if raw, ok := m["cidr_blocks"]; ok {
   198  			list := raw.([]interface{})
   199  			for _, v := range list {
   200  				perm.IpRanges = append(perm.IpRanges, &ec2.IpRange{CidrIp: aws.String(v.(string))})
   201  			}
   202  		}
   203  
   204  		perms[i] = &perm
   205  	}
   206  
   207  	return perms, nil
   208  }
   209  
   210  // Takes the result of flatmap.Expand for an array of parameters and
   211  // returns Parameter API compatible objects
   212  func expandParameters(configured []interface{}) ([]*rds.Parameter, error) {
   213  	var parameters []*rds.Parameter
   214  
   215  	// Loop over our configured parameters and create
   216  	// an array of aws-sdk-go compatabile objects
   217  	for _, pRaw := range configured {
   218  		data := pRaw.(map[string]interface{})
   219  
   220  		if data["name"].(string) == "" {
   221  			continue
   222  		}
   223  
   224  		p := &rds.Parameter{
   225  			ApplyMethod:    aws.String(data["apply_method"].(string)),
   226  			ParameterName:  aws.String(data["name"].(string)),
   227  			ParameterValue: aws.String(data["value"].(string)),
   228  		}
   229  
   230  		parameters = append(parameters, p)
   231  	}
   232  
   233  	return parameters, nil
   234  }
   235  
   236  // Takes the result of flatmap.Expand for an array of parameters and
   237  // returns Parameter API compatible objects
   238  func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) {
   239  	parameters := make([]*elasticache.ParameterNameValue, 0, len(configured))
   240  
   241  	// Loop over our configured parameters and create
   242  	// an array of aws-sdk-go compatabile objects
   243  	for _, pRaw := range configured {
   244  		data := pRaw.(map[string]interface{})
   245  
   246  		p := &elasticache.ParameterNameValue{
   247  			ParameterName:  aws.String(data["name"].(string)),
   248  			ParameterValue: aws.String(data["value"].(string)),
   249  		}
   250  
   251  		parameters = append(parameters, p)
   252  	}
   253  
   254  	return parameters, nil
   255  }
   256  
   257  // Flattens an access log into something that flatmap.Flatten() can handle
   258  func flattenAccessLog(l *elb.AccessLog) []map[string]interface{} {
   259  	result := make([]map[string]interface{}, 0, 1)
   260  
   261  	if l != nil && *l.Enabled {
   262  		r := make(map[string]interface{})
   263  		if l.S3BucketName != nil {
   264  			r["bucket"] = *l.S3BucketName
   265  		}
   266  
   267  		if l.S3BucketPrefix != nil {
   268  			r["bucket_prefix"] = *l.S3BucketPrefix
   269  		}
   270  
   271  		if l.EmitInterval != nil {
   272  			r["interval"] = *l.EmitInterval
   273  		}
   274  
   275  		result = append(result, r)
   276  	}
   277  
   278  	return result
   279  }
   280  
   281  // Flattens a health check into something that flatmap.Flatten()
   282  // can handle
   283  func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
   284  	result := make([]map[string]interface{}, 0, 1)
   285  
   286  	chk := make(map[string]interface{})
   287  	chk["unhealthy_threshold"] = *check.UnhealthyThreshold
   288  	chk["healthy_threshold"] = *check.HealthyThreshold
   289  	chk["target"] = *check.Target
   290  	chk["timeout"] = *check.Timeout
   291  	chk["interval"] = *check.Interval
   292  
   293  	result = append(result, chk)
   294  
   295  	return result
   296  }
   297  
   298  // Flattens an array of UserSecurityGroups into a []string
   299  func flattenSecurityGroups(list []*ec2.UserIdGroupPair) []string {
   300  	result := make([]string, 0, len(list))
   301  	for _, g := range list {
   302  		result = append(result, *g.GroupId)
   303  	}
   304  	return result
   305  }
   306  
   307  // Flattens an array of Instances into a []string
   308  func flattenInstances(list []*elb.Instance) []string {
   309  	result := make([]string, 0, len(list))
   310  	for _, i := range list {
   311  		result = append(result, *i.InstanceId)
   312  	}
   313  	return result
   314  }
   315  
   316  // Expands an array of String Instance IDs into a []Instances
   317  func expandInstanceString(list []interface{}) []*elb.Instance {
   318  	result := make([]*elb.Instance, 0, len(list))
   319  	for _, i := range list {
   320  		result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))})
   321  	}
   322  	return result
   323  }
   324  
   325  // Flattens an array of Backend Descriptions into a a map of instance_port to policy names.
   326  func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string {
   327  	policies := make(map[int64][]string)
   328  	for _, i := range backends {
   329  		for _, p := range i.PolicyNames {
   330  			policies[*i.InstancePort] = append(policies[*i.InstancePort], *p)
   331  		}
   332  		sort.Strings(policies[*i.InstancePort])
   333  	}
   334  	return policies
   335  }
   336  
   337  // Flattens an array of Listeners into a []map[string]interface{}
   338  func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} {
   339  	result := make([]map[string]interface{}, 0, len(list))
   340  	for _, i := range list {
   341  		l := map[string]interface{}{
   342  			"instance_port":     *i.Listener.InstancePort,
   343  			"instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol),
   344  			"lb_port":           *i.Listener.LoadBalancerPort,
   345  			"lb_protocol":       strings.ToLower(*i.Listener.Protocol),
   346  		}
   347  		// SSLCertificateID is optional, and may be nil
   348  		if i.Listener.SSLCertificateId != nil {
   349  			l["ssl_certificate_id"] = *i.Listener.SSLCertificateId
   350  		}
   351  		result = append(result, l)
   352  	}
   353  	return result
   354  }
   355  
   356  // Flattens an array of Volumes into a []map[string]interface{}
   357  func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} {
   358  	result := make([]map[string]interface{}, 0, len(list))
   359  	for _, volume := range list {
   360  		l := map[string]interface{}{
   361  			"name": *volume.Name,
   362  		}
   363  
   364  		if volume.Host.SourcePath != nil {
   365  			l["host_path"] = *volume.Host.SourcePath
   366  		}
   367  
   368  		result = append(result, l)
   369  	}
   370  	return result
   371  }
   372  
   373  // Flattens an array of ECS LoadBalancers into a []map[string]interface{}
   374  func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} {
   375  	result := make([]map[string]interface{}, 0, len(list))
   376  	for _, loadBalancer := range list {
   377  		l := map[string]interface{}{
   378  			"elb_name":       *loadBalancer.LoadBalancerName,
   379  			"container_name": *loadBalancer.ContainerName,
   380  			"container_port": *loadBalancer.ContainerPort,
   381  		}
   382  		result = append(result, l)
   383  	}
   384  	return result
   385  }
   386  
   387  // Encodes an array of ecs.ContainerDefinitions into a JSON string
   388  func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) {
   389  	byteArray, err := json.Marshal(definitions)
   390  	if err != nil {
   391  		return "", fmt.Errorf("Error encoding to JSON: %s", err)
   392  	}
   393  
   394  	n := bytes.Index(byteArray, []byte{0})
   395  	return string(byteArray[:n]), nil
   396  }
   397  
   398  // Flattens an array of Parameters into a []map[string]interface{}
   399  func flattenParameters(list []*rds.Parameter) []map[string]interface{} {
   400  	result := make([]map[string]interface{}, 0, len(list))
   401  	for _, i := range list {
   402  		if i.ParameterName != nil {
   403  			r := make(map[string]interface{})
   404  			r["name"] = strings.ToLower(*i.ParameterName)
   405  			// Default empty string, guard against nil parameter values
   406  			r["value"] = ""
   407  			if i.ParameterValue != nil {
   408  				r["value"] = strings.ToLower(*i.ParameterValue)
   409  			}
   410  			result = append(result, r)
   411  		}
   412  	}
   413  	return result
   414  }
   415  
   416  // Flattens an array of Parameters into a []map[string]interface{}
   417  func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} {
   418  	result := make([]map[string]interface{}, 0, len(list))
   419  	for _, i := range list {
   420  		result = append(result, map[string]interface{}{
   421  			"name":  strings.ToLower(*i.ParameterName),
   422  			"value": strings.ToLower(*i.ParameterValue),
   423  		})
   424  	}
   425  	return result
   426  }
   427  
   428  // Takes the result of flatmap.Expand for an array of strings
   429  // and returns a []*string
   430  func expandStringList(configured []interface{}) []*string {
   431  	vs := make([]*string, 0, len(configured))
   432  	for _, v := range configured {
   433  		vs = append(vs, aws.String(v.(string)))
   434  	}
   435  	return vs
   436  }
   437  
   438  // Takes list of pointers to strings. Expand to an array
   439  // of raw strings and returns a []interface{}
   440  // to keep compatibility w/ schema.NewSetschema.NewSet
   441  func flattenStringList(list []*string) []interface{} {
   442  	vs := make([]interface{}, 0, len(list))
   443  	for _, v := range list {
   444  		vs = append(vs, *v)
   445  	}
   446  	return vs
   447  }
   448  
   449  //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0"
   450  func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string {
   451  	ips := make([]string, 0, len(dtos))
   452  	for _, v := range dtos {
   453  		ip := *v.PrivateIpAddress
   454  		ips = append(ips, ip)
   455  	}
   456  	return ips
   457  }
   458  
   459  //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs
   460  func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string {
   461  	ids := make([]string, 0, len(dtos))
   462  	for _, v := range dtos {
   463  		group_id := *v.GroupId
   464  		ids = append(ids, group_id)
   465  	}
   466  	return ids
   467  }
   468  
   469  //Expands an array of IPs into a ec2 Private IP Address Spec
   470  func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification {
   471  	dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips))
   472  	for i, v := range ips {
   473  		new_private_ip := &ec2.PrivateIpAddressSpecification{
   474  			PrivateIpAddress: aws.String(v.(string)),
   475  		}
   476  
   477  		new_private_ip.Primary = aws.Bool(i == 0)
   478  
   479  		dtos = append(dtos, new_private_ip)
   480  	}
   481  	return dtos
   482  }
   483  
   484  //Flattens network interface attachment into a map[string]interface
   485  func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} {
   486  	att := make(map[string]interface{})
   487  	att["instance"] = *a.InstanceId
   488  	att["device_index"] = *a.DeviceIndex
   489  	att["attachment_id"] = *a.AttachmentId
   490  	return att
   491  }
   492  
   493  func flattenResourceRecords(recs []*route53.ResourceRecord) []string {
   494  	strs := make([]string, 0, len(recs))
   495  	for _, r := range recs {
   496  		if r.Value != nil {
   497  			s := strings.Replace(*r.Value, "\"", "", 2)
   498  			strs = append(strs, s)
   499  		}
   500  	}
   501  	return strs
   502  }
   503  
   504  func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord {
   505  	records := make([]*route53.ResourceRecord, 0, len(recs))
   506  	for _, r := range recs {
   507  		s := r.(string)
   508  		switch typeStr {
   509  		case "TXT", "SPF":
   510  			str := fmt.Sprintf("\"%s\"", s)
   511  			records = append(records, &route53.ResourceRecord{Value: aws.String(str)})
   512  		default:
   513  			records = append(records, &route53.ResourceRecord{Value: aws.String(s)})
   514  		}
   515  	}
   516  	return records
   517  }
   518  
   519  func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
   520  	value := v.(string)
   521  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
   522  		errors = append(errors, fmt.Errorf(
   523  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
   524  	}
   525  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
   526  		errors = append(errors, fmt.Errorf(
   527  			"first character of %q must be a letter", k))
   528  	}
   529  	if regexp.MustCompile(`--`).MatchString(value) {
   530  		errors = append(errors, fmt.Errorf(
   531  			"%q cannot contain two consecutive hyphens", k))
   532  	}
   533  	if regexp.MustCompile(`-$`).MatchString(value) {
   534  		errors = append(errors, fmt.Errorf(
   535  			"%q cannot end with a hyphen", k))
   536  	}
   537  	return
   538  }
   539  
   540  func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig {
   541  	config := elasticsearch.ElasticsearchClusterConfig{}
   542  
   543  	if v, ok := m["dedicated_master_enabled"]; ok {
   544  		isEnabled := v.(bool)
   545  		config.DedicatedMasterEnabled = aws.Bool(isEnabled)
   546  
   547  		if isEnabled {
   548  			if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 {
   549  				config.DedicatedMasterCount = aws.Int64(int64(v.(int)))
   550  			}
   551  			if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" {
   552  				config.DedicatedMasterType = aws.String(v.(string))
   553  			}
   554  		}
   555  	}
   556  
   557  	if v, ok := m["instance_count"]; ok {
   558  		config.InstanceCount = aws.Int64(int64(v.(int)))
   559  	}
   560  	if v, ok := m["instance_type"]; ok {
   561  		config.InstanceType = aws.String(v.(string))
   562  	}
   563  
   564  	if v, ok := m["zone_awareness_enabled"]; ok {
   565  		config.ZoneAwarenessEnabled = aws.Bool(v.(bool))
   566  	}
   567  
   568  	return &config
   569  }
   570  
   571  func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} {
   572  	m := map[string]interface{}{}
   573  
   574  	if c.DedicatedMasterCount != nil {
   575  		m["dedicated_master_count"] = *c.DedicatedMasterCount
   576  	}
   577  	if c.DedicatedMasterEnabled != nil {
   578  		m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled
   579  	}
   580  	if c.DedicatedMasterType != nil {
   581  		m["dedicated_master_type"] = *c.DedicatedMasterType
   582  	}
   583  	if c.InstanceCount != nil {
   584  		m["instance_count"] = *c.InstanceCount
   585  	}
   586  	if c.InstanceType != nil {
   587  		m["instance_type"] = *c.InstanceType
   588  	}
   589  	if c.ZoneAwarenessEnabled != nil {
   590  		m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled
   591  	}
   592  
   593  	return []map[string]interface{}{m}
   594  }
   595  
   596  func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} {
   597  	m := map[string]interface{}{}
   598  
   599  	if o.EBSEnabled != nil {
   600  		m["ebs_enabled"] = *o.EBSEnabled
   601  	}
   602  	if o.Iops != nil {
   603  		m["iops"] = *o.Iops
   604  	}
   605  	if o.VolumeSize != nil {
   606  		m["volume_size"] = *o.VolumeSize
   607  	}
   608  	if o.VolumeType != nil {
   609  		m["volume_type"] = *o.VolumeType
   610  	}
   611  
   612  	return []map[string]interface{}{m}
   613  }
   614  
   615  func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions {
   616  	options := elasticsearch.EBSOptions{}
   617  
   618  	if v, ok := m["ebs_enabled"]; ok {
   619  		options.EBSEnabled = aws.Bool(v.(bool))
   620  	}
   621  	if v, ok := m["iops"]; ok && v.(int) > 0 {
   622  		options.Iops = aws.Int64(int64(v.(int)))
   623  	}
   624  	if v, ok := m["volume_size"]; ok && v.(int) > 0 {
   625  		options.VolumeSize = aws.Int64(int64(v.(int)))
   626  	}
   627  	if v, ok := m["volume_type"]; ok && v.(string) != "" {
   628  		options.VolumeType = aws.String(v.(string))
   629  	}
   630  
   631  	return &options
   632  }
   633  
   634  func pointersMapToStringList(pointers map[string]*string) map[string]interface{} {
   635  	list := make(map[string]interface{}, len(pointers))
   636  	for i, v := range pointers {
   637  		list[i] = *v
   638  	}
   639  	return list
   640  }
   641  
   642  func stringMapToPointers(m map[string]interface{}) map[string]*string {
   643  	list := make(map[string]*string, len(m))
   644  	for i, v := range m {
   645  		list[i] = aws.String(v.(string))
   646  	}
   647  	return list
   648  }
   649  
   650  func flattenDSVpcSettings(
   651  	s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} {
   652  	settings := make(map[string]interface{}, 0)
   653  
   654  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   655  	settings["vpc_id"] = *s.VpcId
   656  
   657  	return []map[string]interface{}{settings}
   658  }
   659  
   660  func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter {
   661  	var cfParams []*cloudformation.Parameter
   662  	for k, v := range params {
   663  		cfParams = append(cfParams, &cloudformation.Parameter{
   664  			ParameterKey:   aws.String(k),
   665  			ParameterValue: aws.String(v.(string)),
   666  		})
   667  	}
   668  
   669  	return cfParams
   670  }
   671  
   672  // flattenCloudFormationParameters is flattening list of
   673  // *cloudformation.Parameters and only returning existing
   674  // parameters to avoid clash with default values
   675  func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter,
   676  	originalParams map[string]interface{}) map[string]interface{} {
   677  	params := make(map[string]interface{}, len(cfParams))
   678  	for _, p := range cfParams {
   679  		_, isConfigured := originalParams[*p.ParameterKey]
   680  		if isConfigured {
   681  			params[*p.ParameterKey] = *p.ParameterValue
   682  		}
   683  	}
   684  	return params
   685  }
   686  
   687  func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag {
   688  	var cfTags []*cloudformation.Tag
   689  	for k, v := range tags {
   690  		cfTags = append(cfTags, &cloudformation.Tag{
   691  			Key:   aws.String(k),
   692  			Value: aws.String(v.(string)),
   693  		})
   694  	}
   695  	return cfTags
   696  }
   697  
   698  func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string {
   699  	tags := make(map[string]string, len(cfTags))
   700  	for _, t := range cfTags {
   701  		tags[*t.Key] = *t.Value
   702  	}
   703  	return tags
   704  }
   705  
   706  func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string {
   707  	outputs := make(map[string]string, len(cfOutputs))
   708  	for _, o := range cfOutputs {
   709  		outputs[*o.OutputKey] = *o.OutputValue
   710  	}
   711  	return outputs
   712  }