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