github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/builtin/providers/aws/structure.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/service/cloudformation"
    12  	"github.com/aws/aws-sdk-go/service/directoryservice"
    13  	"github.com/aws/aws-sdk-go/service/ec2"
    14  	"github.com/aws/aws-sdk-go/service/ecs"
    15  	"github.com/aws/aws-sdk-go/service/elasticache"
    16  	elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
    17  	"github.com/aws/aws-sdk-go/service/elb"
    18  	"github.com/aws/aws-sdk-go/service/rds"
    19  	"github.com/aws/aws-sdk-go/service/redshift"
    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  func expandRedshiftParameters(configured []interface{}) ([]*redshift.Parameter, error) {
   237  	var parameters []*redshift.Parameter
   238  
   239  	// Loop over our configured parameters and create
   240  	// an array of aws-sdk-go compatabile objects
   241  	for _, pRaw := range configured {
   242  		data := pRaw.(map[string]interface{})
   243  
   244  		if data["name"].(string) == "" {
   245  			continue
   246  		}
   247  
   248  		p := &redshift.Parameter{
   249  			ParameterName:  aws.String(data["name"].(string)),
   250  			ParameterValue: aws.String(data["value"].(string)),
   251  		}
   252  
   253  		parameters = append(parameters, p)
   254  	}
   255  
   256  	return parameters, nil
   257  }
   258  
   259  // Takes the result of flatmap.Expand for an array of parameters and
   260  // returns Parameter API compatible objects
   261  func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) {
   262  	parameters := make([]*elasticache.ParameterNameValue, 0, len(configured))
   263  
   264  	// Loop over our configured parameters and create
   265  	// an array of aws-sdk-go compatabile objects
   266  	for _, pRaw := range configured {
   267  		data := pRaw.(map[string]interface{})
   268  
   269  		p := &elasticache.ParameterNameValue{
   270  			ParameterName:  aws.String(data["name"].(string)),
   271  			ParameterValue: aws.String(data["value"].(string)),
   272  		}
   273  
   274  		parameters = append(parameters, p)
   275  	}
   276  
   277  	return parameters, nil
   278  }
   279  
   280  // Flattens an access log into something that flatmap.Flatten() can handle
   281  func flattenAccessLog(l *elb.AccessLog) []map[string]interface{} {
   282  	result := make([]map[string]interface{}, 0, 1)
   283  
   284  	if l != nil && *l.Enabled {
   285  		r := make(map[string]interface{})
   286  		if l.S3BucketName != nil {
   287  			r["bucket"] = *l.S3BucketName
   288  		}
   289  
   290  		if l.S3BucketPrefix != nil {
   291  			r["bucket_prefix"] = *l.S3BucketPrefix
   292  		}
   293  
   294  		if l.EmitInterval != nil {
   295  			r["interval"] = *l.EmitInterval
   296  		}
   297  
   298  		result = append(result, r)
   299  	}
   300  
   301  	return result
   302  }
   303  
   304  // Flattens a health check into something that flatmap.Flatten()
   305  // can handle
   306  func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
   307  	result := make([]map[string]interface{}, 0, 1)
   308  
   309  	chk := make(map[string]interface{})
   310  	chk["unhealthy_threshold"] = *check.UnhealthyThreshold
   311  	chk["healthy_threshold"] = *check.HealthyThreshold
   312  	chk["target"] = *check.Target
   313  	chk["timeout"] = *check.Timeout
   314  	chk["interval"] = *check.Interval
   315  
   316  	result = append(result, chk)
   317  
   318  	return result
   319  }
   320  
   321  // Flattens an array of UserSecurityGroups into a []string
   322  func flattenSecurityGroups(list []*ec2.UserIdGroupPair) []string {
   323  	result := make([]string, 0, len(list))
   324  	for _, g := range list {
   325  		result = append(result, *g.GroupId)
   326  	}
   327  	return result
   328  }
   329  
   330  // Flattens an array of Instances into a []string
   331  func flattenInstances(list []*elb.Instance) []string {
   332  	result := make([]string, 0, len(list))
   333  	for _, i := range list {
   334  		result = append(result, *i.InstanceId)
   335  	}
   336  	return result
   337  }
   338  
   339  // Expands an array of String Instance IDs into a []Instances
   340  func expandInstanceString(list []interface{}) []*elb.Instance {
   341  	result := make([]*elb.Instance, 0, len(list))
   342  	for _, i := range list {
   343  		result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))})
   344  	}
   345  	return result
   346  }
   347  
   348  // Flattens an array of Backend Descriptions into a a map of instance_port to policy names.
   349  func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string {
   350  	policies := make(map[int64][]string)
   351  	for _, i := range backends {
   352  		for _, p := range i.PolicyNames {
   353  			policies[*i.InstancePort] = append(policies[*i.InstancePort], *p)
   354  		}
   355  		sort.Strings(policies[*i.InstancePort])
   356  	}
   357  	return policies
   358  }
   359  
   360  // Flattens an array of Listeners into a []map[string]interface{}
   361  func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} {
   362  	result := make([]map[string]interface{}, 0, len(list))
   363  	for _, i := range list {
   364  		l := map[string]interface{}{
   365  			"instance_port":     *i.Listener.InstancePort,
   366  			"instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol),
   367  			"lb_port":           *i.Listener.LoadBalancerPort,
   368  			"lb_protocol":       strings.ToLower(*i.Listener.Protocol),
   369  		}
   370  		// SSLCertificateID is optional, and may be nil
   371  		if i.Listener.SSLCertificateId != nil {
   372  			l["ssl_certificate_id"] = *i.Listener.SSLCertificateId
   373  		}
   374  		result = append(result, l)
   375  	}
   376  	return result
   377  }
   378  
   379  // Flattens an array of Volumes into a []map[string]interface{}
   380  func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} {
   381  	result := make([]map[string]interface{}, 0, len(list))
   382  	for _, volume := range list {
   383  		l := map[string]interface{}{
   384  			"name": *volume.Name,
   385  		}
   386  
   387  		if volume.Host.SourcePath != nil {
   388  			l["host_path"] = *volume.Host.SourcePath
   389  		}
   390  
   391  		result = append(result, l)
   392  	}
   393  	return result
   394  }
   395  
   396  // Flattens an array of ECS LoadBalancers into a []map[string]interface{}
   397  func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} {
   398  	result := make([]map[string]interface{}, 0, len(list))
   399  	for _, loadBalancer := range list {
   400  		l := map[string]interface{}{
   401  			"elb_name":       *loadBalancer.LoadBalancerName,
   402  			"container_name": *loadBalancer.ContainerName,
   403  			"container_port": *loadBalancer.ContainerPort,
   404  		}
   405  		result = append(result, l)
   406  	}
   407  	return result
   408  }
   409  
   410  // Encodes an array of ecs.ContainerDefinitions into a JSON string
   411  func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) {
   412  	byteArray, err := json.Marshal(definitions)
   413  	if err != nil {
   414  		return "", fmt.Errorf("Error encoding to JSON: %s", err)
   415  	}
   416  
   417  	n := bytes.Index(byteArray, []byte{0})
   418  	return string(byteArray[:n]), nil
   419  }
   420  
   421  // Flattens an array of Parameters into a []map[string]interface{}
   422  func flattenParameters(list []*rds.Parameter) []map[string]interface{} {
   423  	result := make([]map[string]interface{}, 0, len(list))
   424  	for _, i := range list {
   425  		if i.ParameterName != nil {
   426  			r := make(map[string]interface{})
   427  			r["name"] = strings.ToLower(*i.ParameterName)
   428  			// Default empty string, guard against nil parameter values
   429  			r["value"] = ""
   430  			if i.ParameterValue != nil {
   431  				r["value"] = strings.ToLower(*i.ParameterValue)
   432  			}
   433  			result = append(result, r)
   434  		}
   435  	}
   436  	return result
   437  }
   438  
   439  // Flattens an array of Redshift Parameters into a []map[string]interface{}
   440  func flattenRedshiftParameters(list []*redshift.Parameter) []map[string]interface{} {
   441  	result := make([]map[string]interface{}, 0, len(list))
   442  	for _, i := range list {
   443  		result = append(result, map[string]interface{}{
   444  			"name":  strings.ToLower(*i.ParameterName),
   445  			"value": strings.ToLower(*i.ParameterValue),
   446  		})
   447  	}
   448  	return result
   449  }
   450  
   451  // Flattens an array of Parameters into a []map[string]interface{}
   452  func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} {
   453  	result := make([]map[string]interface{}, 0, len(list))
   454  	for _, i := range list {
   455  		result = append(result, map[string]interface{}{
   456  			"name":  strings.ToLower(*i.ParameterName),
   457  			"value": strings.ToLower(*i.ParameterValue),
   458  		})
   459  	}
   460  	return result
   461  }
   462  
   463  // Takes the result of flatmap.Expand for an array of strings
   464  // and returns a []*string
   465  func expandStringList(configured []interface{}) []*string {
   466  	vs := make([]*string, 0, len(configured))
   467  	for _, v := range configured {
   468  		vs = append(vs, aws.String(v.(string)))
   469  	}
   470  	return vs
   471  }
   472  
   473  // Takes list of pointers to strings. Expand to an array
   474  // of raw strings and returns a []interface{}
   475  // to keep compatibility w/ schema.NewSetschema.NewSet
   476  func flattenStringList(list []*string) []interface{} {
   477  	vs := make([]interface{}, 0, len(list))
   478  	for _, v := range list {
   479  		vs = append(vs, *v)
   480  	}
   481  	return vs
   482  }
   483  
   484  //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0"
   485  func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string {
   486  	ips := make([]string, 0, len(dtos))
   487  	for _, v := range dtos {
   488  		ip := *v.PrivateIpAddress
   489  		ips = append(ips, ip)
   490  	}
   491  	return ips
   492  }
   493  
   494  //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs
   495  func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string {
   496  	ids := make([]string, 0, len(dtos))
   497  	for _, v := range dtos {
   498  		group_id := *v.GroupId
   499  		ids = append(ids, group_id)
   500  	}
   501  	return ids
   502  }
   503  
   504  //Expands an array of IPs into a ec2 Private IP Address Spec
   505  func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification {
   506  	dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips))
   507  	for i, v := range ips {
   508  		new_private_ip := &ec2.PrivateIpAddressSpecification{
   509  			PrivateIpAddress: aws.String(v.(string)),
   510  		}
   511  
   512  		new_private_ip.Primary = aws.Bool(i == 0)
   513  
   514  		dtos = append(dtos, new_private_ip)
   515  	}
   516  	return dtos
   517  }
   518  
   519  //Flattens network interface attachment into a map[string]interface
   520  func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} {
   521  	att := make(map[string]interface{})
   522  	att["instance"] = *a.InstanceId
   523  	att["device_index"] = *a.DeviceIndex
   524  	att["attachment_id"] = *a.AttachmentId
   525  	return att
   526  }
   527  
   528  func flattenResourceRecords(recs []*route53.ResourceRecord) []string {
   529  	strs := make([]string, 0, len(recs))
   530  	for _, r := range recs {
   531  		if r.Value != nil {
   532  			s := strings.Replace(*r.Value, "\"", "", 2)
   533  			strs = append(strs, s)
   534  		}
   535  	}
   536  	return strs
   537  }
   538  
   539  func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord {
   540  	records := make([]*route53.ResourceRecord, 0, len(recs))
   541  	for _, r := range recs {
   542  		s := r.(string)
   543  		switch typeStr {
   544  		case "TXT", "SPF":
   545  			str := fmt.Sprintf("\"%s\"", s)
   546  			records = append(records, &route53.ResourceRecord{Value: aws.String(str)})
   547  		default:
   548  			records = append(records, &route53.ResourceRecord{Value: aws.String(s)})
   549  		}
   550  	}
   551  	return records
   552  }
   553  
   554  func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig {
   555  	config := elasticsearch.ElasticsearchClusterConfig{}
   556  
   557  	if v, ok := m["dedicated_master_enabled"]; ok {
   558  		isEnabled := v.(bool)
   559  		config.DedicatedMasterEnabled = aws.Bool(isEnabled)
   560  
   561  		if isEnabled {
   562  			if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 {
   563  				config.DedicatedMasterCount = aws.Int64(int64(v.(int)))
   564  			}
   565  			if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" {
   566  				config.DedicatedMasterType = aws.String(v.(string))
   567  			}
   568  		}
   569  	}
   570  
   571  	if v, ok := m["instance_count"]; ok {
   572  		config.InstanceCount = aws.Int64(int64(v.(int)))
   573  	}
   574  	if v, ok := m["instance_type"]; ok {
   575  		config.InstanceType = aws.String(v.(string))
   576  	}
   577  
   578  	if v, ok := m["zone_awareness_enabled"]; ok {
   579  		config.ZoneAwarenessEnabled = aws.Bool(v.(bool))
   580  	}
   581  
   582  	return &config
   583  }
   584  
   585  func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} {
   586  	m := map[string]interface{}{}
   587  
   588  	if c.DedicatedMasterCount != nil {
   589  		m["dedicated_master_count"] = *c.DedicatedMasterCount
   590  	}
   591  	if c.DedicatedMasterEnabled != nil {
   592  		m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled
   593  	}
   594  	if c.DedicatedMasterType != nil {
   595  		m["dedicated_master_type"] = *c.DedicatedMasterType
   596  	}
   597  	if c.InstanceCount != nil {
   598  		m["instance_count"] = *c.InstanceCount
   599  	}
   600  	if c.InstanceType != nil {
   601  		m["instance_type"] = *c.InstanceType
   602  	}
   603  	if c.ZoneAwarenessEnabled != nil {
   604  		m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled
   605  	}
   606  
   607  	return []map[string]interface{}{m}
   608  }
   609  
   610  func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} {
   611  	m := map[string]interface{}{}
   612  
   613  	if o.EBSEnabled != nil {
   614  		m["ebs_enabled"] = *o.EBSEnabled
   615  	}
   616  	if o.Iops != nil {
   617  		m["iops"] = *o.Iops
   618  	}
   619  	if o.VolumeSize != nil {
   620  		m["volume_size"] = *o.VolumeSize
   621  	}
   622  	if o.VolumeType != nil {
   623  		m["volume_type"] = *o.VolumeType
   624  	}
   625  
   626  	return []map[string]interface{}{m}
   627  }
   628  
   629  func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions {
   630  	options := elasticsearch.EBSOptions{}
   631  
   632  	if v, ok := m["ebs_enabled"]; ok {
   633  		options.EBSEnabled = aws.Bool(v.(bool))
   634  	}
   635  	if v, ok := m["iops"]; ok && v.(int) > 0 {
   636  		options.Iops = aws.Int64(int64(v.(int)))
   637  	}
   638  	if v, ok := m["volume_size"]; ok && v.(int) > 0 {
   639  		options.VolumeSize = aws.Int64(int64(v.(int)))
   640  	}
   641  	if v, ok := m["volume_type"]; ok && v.(string) != "" {
   642  		options.VolumeType = aws.String(v.(string))
   643  	}
   644  
   645  	return &options
   646  }
   647  
   648  func pointersMapToStringList(pointers map[string]*string) map[string]interface{} {
   649  	list := make(map[string]interface{}, len(pointers))
   650  	for i, v := range pointers {
   651  		list[i] = *v
   652  	}
   653  	return list
   654  }
   655  
   656  func stringMapToPointers(m map[string]interface{}) map[string]*string {
   657  	list := make(map[string]*string, len(m))
   658  	for i, v := range m {
   659  		list[i] = aws.String(v.(string))
   660  	}
   661  	return list
   662  }
   663  
   664  func flattenDSVpcSettings(
   665  	s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} {
   666  	settings := make(map[string]interface{}, 0)
   667  
   668  	if s == nil {
   669  		return nil
   670  	}
   671  
   672  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   673  	settings["vpc_id"] = *s.VpcId
   674  
   675  	return []map[string]interface{}{settings}
   676  }
   677  
   678  func flattenDSConnectSettings(
   679  	customerDnsIps []*string,
   680  	s *directoryservice.DirectoryConnectSettingsDescription) []map[string]interface{} {
   681  	if s == nil {
   682  		return nil
   683  	}
   684  
   685  	settings := make(map[string]interface{}, 0)
   686  
   687  	settings["customer_dns_ips"] = schema.NewSet(schema.HashString, flattenStringList(customerDnsIps))
   688  	settings["connect_ips"] = schema.NewSet(schema.HashString, flattenStringList(s.ConnectIps))
   689  	settings["customer_username"] = *s.CustomerUserName
   690  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   691  	settings["vpc_id"] = *s.VpcId
   692  
   693  	return []map[string]interface{}{settings}
   694  }
   695  
   696  func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter {
   697  	var cfParams []*cloudformation.Parameter
   698  	for k, v := range params {
   699  		cfParams = append(cfParams, &cloudformation.Parameter{
   700  			ParameterKey:   aws.String(k),
   701  			ParameterValue: aws.String(v.(string)),
   702  		})
   703  	}
   704  
   705  	return cfParams
   706  }
   707  
   708  // flattenCloudFormationParameters is flattening list of
   709  // *cloudformation.Parameters and only returning existing
   710  // parameters to avoid clash with default values
   711  func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter,
   712  	originalParams map[string]interface{}) map[string]interface{} {
   713  	params := make(map[string]interface{}, len(cfParams))
   714  	for _, p := range cfParams {
   715  		_, isConfigured := originalParams[*p.ParameterKey]
   716  		if isConfigured {
   717  			params[*p.ParameterKey] = *p.ParameterValue
   718  		}
   719  	}
   720  	return params
   721  }
   722  
   723  func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag {
   724  	var cfTags []*cloudformation.Tag
   725  	for k, v := range tags {
   726  		cfTags = append(cfTags, &cloudformation.Tag{
   727  			Key:   aws.String(k),
   728  			Value: aws.String(v.(string)),
   729  		})
   730  	}
   731  	return cfTags
   732  }
   733  
   734  func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string {
   735  	tags := make(map[string]string, len(cfTags))
   736  	for _, t := range cfTags {
   737  		tags[*t.Key] = *t.Value
   738  	}
   739  	return tags
   740  }
   741  
   742  func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string {
   743  	outputs := make(map[string]string, len(cfOutputs))
   744  	for _, o := range cfOutputs {
   745  		outputs[*o.OutputKey] = *o.OutputValue
   746  	}
   747  	return outputs
   748  }