github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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  		result = append(result, map[string]interface{}{
   403  			"name":  strings.ToLower(*i.ParameterName),
   404  			"value": strings.ToLower(*i.ParameterValue),
   405  		})
   406  	}
   407  	return result
   408  }
   409  
   410  // Flattens an array of Parameters into a []map[string]interface{}
   411  func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} {
   412  	result := make([]map[string]interface{}, 0, len(list))
   413  	for _, i := range list {
   414  		result = append(result, map[string]interface{}{
   415  			"name":  strings.ToLower(*i.ParameterName),
   416  			"value": strings.ToLower(*i.ParameterValue),
   417  		})
   418  	}
   419  	return result
   420  }
   421  
   422  // Takes the result of flatmap.Expand for an array of strings
   423  // and returns a []*string
   424  func expandStringList(configured []interface{}) []*string {
   425  	vs := make([]*string, 0, len(configured))
   426  	for _, v := range configured {
   427  		vs = append(vs, aws.String(v.(string)))
   428  	}
   429  	return vs
   430  }
   431  
   432  // Takes list of pointers to strings. Expand to an array
   433  // of raw strings and returns a []interface{}
   434  // to keep compatibility w/ schema.NewSetschema.NewSet
   435  func flattenStringList(list []*string) []interface{} {
   436  	vs := make([]interface{}, 0, len(list))
   437  	for _, v := range list {
   438  		vs = append(vs, *v)
   439  	}
   440  	return vs
   441  }
   442  
   443  //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0"
   444  func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string {
   445  	ips := make([]string, 0, len(dtos))
   446  	for _, v := range dtos {
   447  		ip := *v.PrivateIpAddress
   448  		ips = append(ips, ip)
   449  	}
   450  	return ips
   451  }
   452  
   453  //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs
   454  func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string {
   455  	ids := make([]string, 0, len(dtos))
   456  	for _, v := range dtos {
   457  		group_id := *v.GroupId
   458  		ids = append(ids, group_id)
   459  	}
   460  	return ids
   461  }
   462  
   463  //Expands an array of IPs into a ec2 Private IP Address Spec
   464  func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification {
   465  	dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips))
   466  	for i, v := range ips {
   467  		new_private_ip := &ec2.PrivateIpAddressSpecification{
   468  			PrivateIpAddress: aws.String(v.(string)),
   469  		}
   470  
   471  		new_private_ip.Primary = aws.Bool(i == 0)
   472  
   473  		dtos = append(dtos, new_private_ip)
   474  	}
   475  	return dtos
   476  }
   477  
   478  //Flattens network interface attachment into a map[string]interface
   479  func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} {
   480  	att := make(map[string]interface{})
   481  	att["instance"] = *a.InstanceId
   482  	att["device_index"] = *a.DeviceIndex
   483  	att["attachment_id"] = *a.AttachmentId
   484  	return att
   485  }
   486  
   487  func flattenResourceRecords(recs []*route53.ResourceRecord) []string {
   488  	strs := make([]string, 0, len(recs))
   489  	for _, r := range recs {
   490  		if r.Value != nil {
   491  			s := strings.Replace(*r.Value, "\"", "", 2)
   492  			strs = append(strs, s)
   493  		}
   494  	}
   495  	return strs
   496  }
   497  
   498  func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord {
   499  	records := make([]*route53.ResourceRecord, 0, len(recs))
   500  	for _, r := range recs {
   501  		s := r.(string)
   502  		switch typeStr {
   503  		case "TXT", "SPF":
   504  			str := fmt.Sprintf("\"%s\"", s)
   505  			records = append(records, &route53.ResourceRecord{Value: aws.String(str)})
   506  		default:
   507  			records = append(records, &route53.ResourceRecord{Value: aws.String(s)})
   508  		}
   509  	}
   510  	return records
   511  }
   512  
   513  func validateRdsId(v interface{}, k string) (ws []string, errors []error) {
   514  	value := v.(string)
   515  	if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
   516  		errors = append(errors, fmt.Errorf(
   517  			"only lowercase alphanumeric characters and hyphens allowed in %q", k))
   518  	}
   519  	if !regexp.MustCompile(`^[a-z]`).MatchString(value) {
   520  		errors = append(errors, fmt.Errorf(
   521  			"first character of %q must be a letter", k))
   522  	}
   523  	if regexp.MustCompile(`--`).MatchString(value) {
   524  		errors = append(errors, fmt.Errorf(
   525  			"%q cannot contain two consecutive hyphens", k))
   526  	}
   527  	if regexp.MustCompile(`-$`).MatchString(value) {
   528  		errors = append(errors, fmt.Errorf(
   529  			"%q cannot end with a hyphen", k))
   530  	}
   531  	return
   532  }
   533  
   534  func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig {
   535  	config := elasticsearch.ElasticsearchClusterConfig{}
   536  
   537  	if v, ok := m["dedicated_master_enabled"]; ok {
   538  		isEnabled := v.(bool)
   539  		config.DedicatedMasterEnabled = aws.Bool(isEnabled)
   540  
   541  		if isEnabled {
   542  			if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 {
   543  				config.DedicatedMasterCount = aws.Int64(int64(v.(int)))
   544  			}
   545  			if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" {
   546  				config.DedicatedMasterType = aws.String(v.(string))
   547  			}
   548  		}
   549  	}
   550  
   551  	if v, ok := m["instance_count"]; ok {
   552  		config.InstanceCount = aws.Int64(int64(v.(int)))
   553  	}
   554  	if v, ok := m["instance_type"]; ok {
   555  		config.InstanceType = aws.String(v.(string))
   556  	}
   557  
   558  	if v, ok := m["zone_awareness_enabled"]; ok {
   559  		config.ZoneAwarenessEnabled = aws.Bool(v.(bool))
   560  	}
   561  
   562  	return &config
   563  }
   564  
   565  func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} {
   566  	m := map[string]interface{}{}
   567  
   568  	if c.DedicatedMasterCount != nil {
   569  		m["dedicated_master_count"] = *c.DedicatedMasterCount
   570  	}
   571  	if c.DedicatedMasterEnabled != nil {
   572  		m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled
   573  	}
   574  	if c.DedicatedMasterType != nil {
   575  		m["dedicated_master_type"] = *c.DedicatedMasterType
   576  	}
   577  	if c.InstanceCount != nil {
   578  		m["instance_count"] = *c.InstanceCount
   579  	}
   580  	if c.InstanceType != nil {
   581  		m["instance_type"] = *c.InstanceType
   582  	}
   583  	if c.ZoneAwarenessEnabled != nil {
   584  		m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled
   585  	}
   586  
   587  	return []map[string]interface{}{m}
   588  }
   589  
   590  func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} {
   591  	m := map[string]interface{}{}
   592  
   593  	if o.EBSEnabled != nil {
   594  		m["ebs_enabled"] = *o.EBSEnabled
   595  	}
   596  	if o.Iops != nil {
   597  		m["iops"] = *o.Iops
   598  	}
   599  	if o.VolumeSize != nil {
   600  		m["volume_size"] = *o.VolumeSize
   601  	}
   602  	if o.VolumeType != nil {
   603  		m["volume_type"] = *o.VolumeType
   604  	}
   605  
   606  	return []map[string]interface{}{m}
   607  }
   608  
   609  func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions {
   610  	options := elasticsearch.EBSOptions{}
   611  
   612  	if v, ok := m["ebs_enabled"]; ok {
   613  		options.EBSEnabled = aws.Bool(v.(bool))
   614  	}
   615  	if v, ok := m["iops"]; ok && v.(int) > 0 {
   616  		options.Iops = aws.Int64(int64(v.(int)))
   617  	}
   618  	if v, ok := m["volume_size"]; ok && v.(int) > 0 {
   619  		options.VolumeSize = aws.Int64(int64(v.(int)))
   620  	}
   621  	if v, ok := m["volume_type"]; ok && v.(string) != "" {
   622  		options.VolumeType = aws.String(v.(string))
   623  	}
   624  
   625  	return &options
   626  }
   627  
   628  func pointersMapToStringList(pointers map[string]*string) map[string]interface{} {
   629  	list := make(map[string]interface{}, len(pointers))
   630  	for i, v := range pointers {
   631  		list[i] = *v
   632  	}
   633  	return list
   634  }
   635  
   636  func stringMapToPointers(m map[string]interface{}) map[string]*string {
   637  	list := make(map[string]*string, len(m))
   638  	for i, v := range m {
   639  		list[i] = aws.String(v.(string))
   640  	}
   641  	return list
   642  }
   643  
   644  func flattenDSVpcSettings(
   645  	s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} {
   646  	settings := make(map[string]interface{}, 0)
   647  
   648  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   649  	settings["vpc_id"] = *s.VpcId
   650  
   651  	return []map[string]interface{}{settings}
   652  }
   653  
   654  func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter {
   655  	var cfParams []*cloudformation.Parameter
   656  	for k, v := range params {
   657  		cfParams = append(cfParams, &cloudformation.Parameter{
   658  			ParameterKey:   aws.String(k),
   659  			ParameterValue: aws.String(v.(string)),
   660  		})
   661  	}
   662  
   663  	return cfParams
   664  }
   665  
   666  // flattenCloudFormationParameters is flattening list of
   667  // *cloudformation.Parameters and only returning existing
   668  // parameters to avoid clash with default values
   669  func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter,
   670  	originalParams map[string]interface{}) map[string]interface{} {
   671  	params := make(map[string]interface{}, len(cfParams))
   672  	for _, p := range cfParams {
   673  		_, isConfigured := originalParams[*p.ParameterKey]
   674  		if isConfigured {
   675  			params[*p.ParameterKey] = *p.ParameterValue
   676  		}
   677  	}
   678  	return params
   679  }
   680  
   681  func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag {
   682  	var cfTags []*cloudformation.Tag
   683  	for k, v := range tags {
   684  		cfTags = append(cfTags, &cloudformation.Tag{
   685  			Key:   aws.String(k),
   686  			Value: aws.String(v.(string)),
   687  		})
   688  	}
   689  	return cfTags
   690  }
   691  
   692  func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string {
   693  	tags := make(map[string]string, len(cfTags))
   694  	for _, t := range cfTags {
   695  		tags[*t.Key] = *t.Value
   696  	}
   697  	return tags
   698  }
   699  
   700  func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string {
   701  	outputs := make(map[string]string, len(cfOutputs))
   702  	for _, o := range cfOutputs {
   703  		outputs[*o.OutputKey] = *o.OutputValue
   704  	}
   705  	return outputs
   706  }