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