github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/builtin/providers/aws/structure.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/aws/aws-sdk-go/aws"
    13  	"github.com/aws/aws-sdk-go/service/apigateway"
    14  	"github.com/aws/aws-sdk-go/service/autoscaling"
    15  	"github.com/aws/aws-sdk-go/service/cloudformation"
    16  	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
    17  	"github.com/aws/aws-sdk-go/service/directoryservice"
    18  	"github.com/aws/aws-sdk-go/service/ec2"
    19  	"github.com/aws/aws-sdk-go/service/ecs"
    20  	"github.com/aws/aws-sdk-go/service/elasticache"
    21  	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
    22  	elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
    23  	"github.com/aws/aws-sdk-go/service/elb"
    24  	"github.com/aws/aws-sdk-go/service/lambda"
    25  	"github.com/aws/aws-sdk-go/service/rds"
    26  	"github.com/aws/aws-sdk-go/service/redshift"
    27  	"github.com/aws/aws-sdk-go/service/route53"
    28  	"github.com/hashicorp/terraform/helper/schema"
    29  )
    30  
    31  // Takes the result of flatmap.Expand for an array of listeners and
    32  // returns ELB API compatible objects
    33  func expandListeners(configured []interface{}) ([]*elb.Listener, error) {
    34  	listeners := make([]*elb.Listener, 0, len(configured))
    35  
    36  	// Loop over our configured listeners and create
    37  	// an array of aws-sdk-go compatabile objects
    38  	for _, lRaw := range configured {
    39  		data := lRaw.(map[string]interface{})
    40  
    41  		ip := int64(data["instance_port"].(int))
    42  		lp := int64(data["lb_port"].(int))
    43  		l := &elb.Listener{
    44  			InstancePort:     &ip,
    45  			InstanceProtocol: aws.String(data["instance_protocol"].(string)),
    46  			LoadBalancerPort: &lp,
    47  			Protocol:         aws.String(data["lb_protocol"].(string)),
    48  		}
    49  
    50  		if v, ok := data["ssl_certificate_id"]; ok {
    51  			l.SSLCertificateId = aws.String(v.(string))
    52  		}
    53  
    54  		var valid bool
    55  		if l.SSLCertificateId != nil && *l.SSLCertificateId != "" {
    56  			// validate the protocol is correct
    57  			for _, p := range []string{"https", "ssl"} {
    58  				if (strings.ToLower(*l.InstanceProtocol) == p) || (strings.ToLower(*l.Protocol) == p) {
    59  					valid = true
    60  				}
    61  			}
    62  		} else {
    63  			valid = true
    64  		}
    65  
    66  		if valid {
    67  			listeners = append(listeners, l)
    68  		} else {
    69  			return nil, fmt.Errorf("[ERR] ELB Listener: ssl_certificate_id may be set only when protocol is 'https' or 'ssl'")
    70  		}
    71  	}
    72  
    73  	return listeners, nil
    74  }
    75  
    76  // Takes the result of flatmap. Expand for an array of listeners and
    77  // returns ECS Volume compatible objects
    78  func expandEcsVolumes(configured []interface{}) ([]*ecs.Volume, error) {
    79  	volumes := make([]*ecs.Volume, 0, len(configured))
    80  
    81  	// Loop over our configured volumes and create
    82  	// an array of aws-sdk-go compatible objects
    83  	for _, lRaw := range configured {
    84  		data := lRaw.(map[string]interface{})
    85  
    86  		l := &ecs.Volume{
    87  			Name: aws.String(data["name"].(string)),
    88  		}
    89  
    90  		hostPath := data["host_path"].(string)
    91  		if hostPath != "" {
    92  			l.Host = &ecs.HostVolumeProperties{
    93  				SourcePath: aws.String(hostPath),
    94  			}
    95  		}
    96  
    97  		volumes = append(volumes, l)
    98  	}
    99  
   100  	return volumes, nil
   101  }
   102  
   103  // Takes JSON in a string. Decodes JSON into
   104  // an array of ecs.ContainerDefinition compatible objects
   105  func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) {
   106  	var definitions []*ecs.ContainerDefinition
   107  
   108  	err := json.Unmarshal([]byte(rawDefinitions), &definitions)
   109  	if err != nil {
   110  		return nil, fmt.Errorf("Error decoding JSON: %s", err)
   111  	}
   112  
   113  	return definitions, nil
   114  }
   115  
   116  // Takes the result of flatmap. Expand for an array of load balancers and
   117  // returns ecs.LoadBalancer compatible objects
   118  func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer {
   119  	loadBalancers := make([]*ecs.LoadBalancer, 0, len(configured))
   120  
   121  	// Loop over our configured load balancers and create
   122  	// an array of aws-sdk-go compatible objects
   123  	for _, lRaw := range configured {
   124  		data := lRaw.(map[string]interface{})
   125  
   126  		l := &ecs.LoadBalancer{
   127  			ContainerName:    aws.String(data["container_name"].(string)),
   128  			ContainerPort:    aws.Int64(int64(data["container_port"].(int))),
   129  			LoadBalancerName: aws.String(data["elb_name"].(string)),
   130  		}
   131  
   132  		loadBalancers = append(loadBalancers, l)
   133  	}
   134  
   135  	return loadBalancers
   136  }
   137  
   138  // Takes the result of flatmap.Expand for an array of ingress/egress security
   139  // group rules and returns EC2 API compatible objects. This function will error
   140  // if it finds invalid permissions input, namely a protocol of "-1" with either
   141  // to_port or from_port set to a non-zero value.
   142  func expandIPPerms(
   143  	group *ec2.SecurityGroup, configured []interface{}) ([]*ec2.IpPermission, error) {
   144  	vpc := group.VpcId != nil && *group.VpcId != ""
   145  
   146  	perms := make([]*ec2.IpPermission, len(configured))
   147  	for i, mRaw := range configured {
   148  		var perm ec2.IpPermission
   149  		m := mRaw.(map[string]interface{})
   150  
   151  		perm.FromPort = aws.Int64(int64(m["from_port"].(int)))
   152  		perm.ToPort = aws.Int64(int64(m["to_port"].(int)))
   153  		perm.IpProtocol = aws.String(m["protocol"].(string))
   154  
   155  		// When protocol is "-1", AWS won't store any ports for the
   156  		// rule, but also won't error if the user specifies ports other
   157  		// than '0'. Force the user to make a deliberate '0' port
   158  		// choice when specifying a "-1" protocol, and tell them about
   159  		// AWS's behavior in the error message.
   160  		if *perm.IpProtocol == "-1" && (*perm.FromPort != 0 || *perm.ToPort != 0) {
   161  			return nil, fmt.Errorf(
   162  				"from_port (%d) and to_port (%d) must both be 0 to use the the 'ALL' \"-1\" protocol!",
   163  				*perm.FromPort, *perm.ToPort)
   164  		}
   165  
   166  		var groups []string
   167  		if raw, ok := m["security_groups"]; ok {
   168  			list := raw.(*schema.Set).List()
   169  			for _, v := range list {
   170  				groups = append(groups, v.(string))
   171  			}
   172  		}
   173  		if v, ok := m["self"]; ok && v.(bool) {
   174  			if vpc {
   175  				groups = append(groups, *group.GroupId)
   176  			} else {
   177  				groups = append(groups, *group.GroupName)
   178  			}
   179  		}
   180  
   181  		if len(groups) > 0 {
   182  			perm.UserIdGroupPairs = make([]*ec2.UserIdGroupPair, len(groups))
   183  			for i, name := range groups {
   184  				ownerId, id := "", name
   185  				if items := strings.Split(id, "/"); len(items) > 1 {
   186  					ownerId, id = items[0], items[1]
   187  				}
   188  
   189  				perm.UserIdGroupPairs[i] = &ec2.UserIdGroupPair{
   190  					GroupId: aws.String(id),
   191  				}
   192  
   193  				if ownerId != "" {
   194  					perm.UserIdGroupPairs[i].UserId = aws.String(ownerId)
   195  				}
   196  
   197  				if !vpc {
   198  					perm.UserIdGroupPairs[i].GroupId = nil
   199  					perm.UserIdGroupPairs[i].GroupName = aws.String(id)
   200  				}
   201  			}
   202  		}
   203  
   204  		if raw, ok := m["cidr_blocks"]; ok {
   205  			list := raw.([]interface{})
   206  			for _, v := range list {
   207  				perm.IpRanges = append(perm.IpRanges, &ec2.IpRange{CidrIp: aws.String(v.(string))})
   208  			}
   209  		}
   210  
   211  		if raw, ok := m["prefix_list_ids"]; ok {
   212  			list := raw.([]interface{})
   213  			for _, v := range list {
   214  				perm.PrefixListIds = append(perm.PrefixListIds, &ec2.PrefixListId{PrefixListId: aws.String(v.(string))})
   215  			}
   216  		}
   217  
   218  		perms[i] = &perm
   219  	}
   220  
   221  	return perms, nil
   222  }
   223  
   224  // Takes the result of flatmap.Expand for an array of parameters and
   225  // returns Parameter API compatible objects
   226  func expandParameters(configured []interface{}) ([]*rds.Parameter, error) {
   227  	var parameters []*rds.Parameter
   228  
   229  	// Loop over our configured parameters and create
   230  	// an array of aws-sdk-go compatabile objects
   231  	for _, pRaw := range configured {
   232  		data := pRaw.(map[string]interface{})
   233  
   234  		if data["name"].(string) == "" {
   235  			continue
   236  		}
   237  
   238  		p := &rds.Parameter{
   239  			ApplyMethod:    aws.String(data["apply_method"].(string)),
   240  			ParameterName:  aws.String(data["name"].(string)),
   241  			ParameterValue: aws.String(data["value"].(string)),
   242  		}
   243  
   244  		parameters = append(parameters, p)
   245  	}
   246  
   247  	return parameters, nil
   248  }
   249  
   250  func expandRedshiftParameters(configured []interface{}) ([]*redshift.Parameter, error) {
   251  	var parameters []*redshift.Parameter
   252  
   253  	// Loop over our configured parameters and create
   254  	// an array of aws-sdk-go compatabile objects
   255  	for _, pRaw := range configured {
   256  		data := pRaw.(map[string]interface{})
   257  
   258  		if data["name"].(string) == "" {
   259  			continue
   260  		}
   261  
   262  		p := &redshift.Parameter{
   263  			ParameterName:  aws.String(data["name"].(string)),
   264  			ParameterValue: aws.String(data["value"].(string)),
   265  		}
   266  
   267  		parameters = append(parameters, p)
   268  	}
   269  
   270  	return parameters, nil
   271  }
   272  
   273  func expandOptionConfiguration(configured []interface{}) ([]*rds.OptionConfiguration, error) {
   274  	var option []*rds.OptionConfiguration
   275  
   276  	for _, pRaw := range configured {
   277  		data := pRaw.(map[string]interface{})
   278  
   279  		o := &rds.OptionConfiguration{
   280  			OptionName: aws.String(data["option_name"].(string)),
   281  		}
   282  
   283  		if raw, ok := data["port"]; ok {
   284  			port := raw.(int)
   285  			if port != 0 {
   286  				o.Port = aws.Int64(int64(port))
   287  			}
   288  		}
   289  
   290  		if raw, ok := data["db_security_group_memberships"]; ok {
   291  			memberships := expandStringList(raw.(*schema.Set).List())
   292  			if len(memberships) > 0 {
   293  				o.DBSecurityGroupMemberships = memberships
   294  			}
   295  		}
   296  
   297  		if raw, ok := data["vpc_security_group_memberships"]; ok {
   298  			memberships := expandStringList(raw.(*schema.Set).List())
   299  			if len(memberships) > 0 {
   300  				o.VpcSecurityGroupMemberships = memberships
   301  			}
   302  		}
   303  
   304  		if raw, ok := data["option_settings"]; ok {
   305  			o.OptionSettings = expandOptionSetting(raw.(*schema.Set).List())
   306  		}
   307  
   308  		option = append(option, o)
   309  	}
   310  
   311  	return option, nil
   312  }
   313  
   314  func expandOptionSetting(list []interface{}) []*rds.OptionSetting {
   315  	options := make([]*rds.OptionSetting, 0, len(list))
   316  
   317  	for _, oRaw := range list {
   318  		data := oRaw.(map[string]interface{})
   319  
   320  		o := &rds.OptionSetting{
   321  			Name:  aws.String(data["name"].(string)),
   322  			Value: aws.String(data["value"].(string)),
   323  		}
   324  
   325  		options = append(options, o)
   326  	}
   327  
   328  	return options
   329  }
   330  
   331  // Takes the result of flatmap.Expand for an array of parameters and
   332  // returns Parameter API compatible objects
   333  func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) {
   334  	parameters := make([]*elasticache.ParameterNameValue, 0, len(configured))
   335  
   336  	// Loop over our configured parameters and create
   337  	// an array of aws-sdk-go compatabile objects
   338  	for _, pRaw := range configured {
   339  		data := pRaw.(map[string]interface{})
   340  
   341  		p := &elasticache.ParameterNameValue{
   342  			ParameterName:  aws.String(data["name"].(string)),
   343  			ParameterValue: aws.String(data["value"].(string)),
   344  		}
   345  
   346  		parameters = append(parameters, p)
   347  	}
   348  
   349  	return parameters, nil
   350  }
   351  
   352  // Flattens an access log into something that flatmap.Flatten() can handle
   353  func flattenAccessLog(l *elb.AccessLog) []map[string]interface{} {
   354  	result := make([]map[string]interface{}, 0, 1)
   355  
   356  	if l != nil && *l.Enabled {
   357  		r := make(map[string]interface{})
   358  		if l.S3BucketName != nil {
   359  			r["bucket"] = *l.S3BucketName
   360  		}
   361  
   362  		if l.S3BucketPrefix != nil {
   363  			r["bucket_prefix"] = *l.S3BucketPrefix
   364  		}
   365  
   366  		if l.EmitInterval != nil {
   367  			r["interval"] = *l.EmitInterval
   368  		}
   369  
   370  		result = append(result, r)
   371  	}
   372  
   373  	return result
   374  }
   375  
   376  // Takes the result of flatmap.Expand for an array of step adjustments and
   377  // returns a []*autoscaling.StepAdjustment.
   378  func expandStepAdjustments(configured []interface{}) ([]*autoscaling.StepAdjustment, error) {
   379  	var adjustments []*autoscaling.StepAdjustment
   380  
   381  	// Loop over our configured step adjustments and create an array
   382  	// of aws-sdk-go compatible objects. We're forced to convert strings
   383  	// to floats here because there's no way to detect whether or not
   384  	// an uninitialized, optional schema element is "0.0" deliberately.
   385  	// With strings, we can test for "", which is definitely an empty
   386  	// struct value.
   387  	for _, raw := range configured {
   388  		data := raw.(map[string]interface{})
   389  		a := &autoscaling.StepAdjustment{
   390  			ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))),
   391  		}
   392  		if data["metric_interval_lower_bound"] != "" {
   393  			bound := data["metric_interval_lower_bound"]
   394  			switch bound := bound.(type) {
   395  			case string:
   396  				f, err := strconv.ParseFloat(bound, 64)
   397  				if err != nil {
   398  					return nil, fmt.Errorf(
   399  						"metric_interval_lower_bound must be a float value represented as a string")
   400  				}
   401  				a.MetricIntervalLowerBound = aws.Float64(f)
   402  			default:
   403  				return nil, fmt.Errorf(
   404  					"metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.")
   405  			}
   406  		}
   407  		if data["metric_interval_upper_bound"] != "" {
   408  			bound := data["metric_interval_upper_bound"]
   409  			switch bound := bound.(type) {
   410  			case string:
   411  				f, err := strconv.ParseFloat(bound, 64)
   412  				if err != nil {
   413  					return nil, fmt.Errorf(
   414  						"metric_interval_upper_bound must be a float value represented as a string")
   415  				}
   416  				a.MetricIntervalUpperBound = aws.Float64(f)
   417  			default:
   418  				return nil, fmt.Errorf(
   419  					"metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.")
   420  			}
   421  		}
   422  		adjustments = append(adjustments, a)
   423  	}
   424  
   425  	return adjustments, nil
   426  }
   427  
   428  // Flattens a health check into something that flatmap.Flatten()
   429  // can handle
   430  func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
   431  	result := make([]map[string]interface{}, 0, 1)
   432  
   433  	chk := make(map[string]interface{})
   434  	chk["unhealthy_threshold"] = *check.UnhealthyThreshold
   435  	chk["healthy_threshold"] = *check.HealthyThreshold
   436  	chk["target"] = *check.Target
   437  	chk["timeout"] = *check.Timeout
   438  	chk["interval"] = *check.Interval
   439  
   440  	result = append(result, chk)
   441  
   442  	return result
   443  }
   444  
   445  // Flattens an array of UserSecurityGroups into a []*ec2.GroupIdentifier
   446  func flattenSecurityGroups(list []*ec2.UserIdGroupPair, ownerId *string) []*ec2.GroupIdentifier {
   447  	result := make([]*ec2.GroupIdentifier, 0, len(list))
   448  	for _, g := range list {
   449  		var userId *string
   450  		if g.UserId != nil && *g.UserId != "" && (ownerId == nil || *ownerId != *g.UserId) {
   451  			userId = g.UserId
   452  		}
   453  		// userid nil here for same vpc groups
   454  
   455  		vpc := g.GroupName == nil || *g.GroupName == ""
   456  		var id *string
   457  		if vpc {
   458  			id = g.GroupId
   459  		} else {
   460  			id = g.GroupName
   461  		}
   462  
   463  		// id is groupid for vpcs
   464  		// id is groupname for non vpc (classic)
   465  
   466  		if userId != nil {
   467  			id = aws.String(*userId + "/" + *id)
   468  		}
   469  
   470  		if vpc {
   471  			result = append(result, &ec2.GroupIdentifier{
   472  				GroupId: id,
   473  			})
   474  		} else {
   475  			result = append(result, &ec2.GroupIdentifier{
   476  				GroupId:   g.GroupId,
   477  				GroupName: id,
   478  			})
   479  		}
   480  	}
   481  	return result
   482  }
   483  
   484  // Flattens an array of Instances into a []string
   485  func flattenInstances(list []*elb.Instance) []string {
   486  	result := make([]string, 0, len(list))
   487  	for _, i := range list {
   488  		result = append(result, *i.InstanceId)
   489  	}
   490  	return result
   491  }
   492  
   493  // Expands an array of String Instance IDs into a []Instances
   494  func expandInstanceString(list []interface{}) []*elb.Instance {
   495  	result := make([]*elb.Instance, 0, len(list))
   496  	for _, i := range list {
   497  		result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))})
   498  	}
   499  	return result
   500  }
   501  
   502  // Flattens an array of Backend Descriptions into a a map of instance_port to policy names.
   503  func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string {
   504  	policies := make(map[int64][]string)
   505  	for _, i := range backends {
   506  		for _, p := range i.PolicyNames {
   507  			policies[*i.InstancePort] = append(policies[*i.InstancePort], *p)
   508  		}
   509  		sort.Strings(policies[*i.InstancePort])
   510  	}
   511  	return policies
   512  }
   513  
   514  // Flattens an array of Listeners into a []map[string]interface{}
   515  func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} {
   516  	result := make([]map[string]interface{}, 0, len(list))
   517  	for _, i := range list {
   518  		l := map[string]interface{}{
   519  			"instance_port":     *i.Listener.InstancePort,
   520  			"instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol),
   521  			"lb_port":           *i.Listener.LoadBalancerPort,
   522  			"lb_protocol":       strings.ToLower(*i.Listener.Protocol),
   523  		}
   524  		// SSLCertificateID is optional, and may be nil
   525  		if i.Listener.SSLCertificateId != nil {
   526  			l["ssl_certificate_id"] = *i.Listener.SSLCertificateId
   527  		}
   528  		result = append(result, l)
   529  	}
   530  	return result
   531  }
   532  
   533  // Flattens an array of Volumes into a []map[string]interface{}
   534  func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} {
   535  	result := make([]map[string]interface{}, 0, len(list))
   536  	for _, volume := range list {
   537  		l := map[string]interface{}{
   538  			"name": *volume.Name,
   539  		}
   540  
   541  		if volume.Host.SourcePath != nil {
   542  			l["host_path"] = *volume.Host.SourcePath
   543  		}
   544  
   545  		result = append(result, l)
   546  	}
   547  	return result
   548  }
   549  
   550  // Flattens an array of ECS LoadBalancers into a []map[string]interface{}
   551  func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} {
   552  	result := make([]map[string]interface{}, 0, len(list))
   553  	for _, loadBalancer := range list {
   554  		l := map[string]interface{}{
   555  			"elb_name":       *loadBalancer.LoadBalancerName,
   556  			"container_name": *loadBalancer.ContainerName,
   557  			"container_port": *loadBalancer.ContainerPort,
   558  		}
   559  		result = append(result, l)
   560  	}
   561  	return result
   562  }
   563  
   564  // Encodes an array of ecs.ContainerDefinitions into a JSON string
   565  func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) {
   566  	byteArray, err := json.Marshal(definitions)
   567  	if err != nil {
   568  		return "", fmt.Errorf("Error encoding to JSON: %s", err)
   569  	}
   570  
   571  	n := bytes.Index(byteArray, []byte{0})
   572  	return string(byteArray[:n]), nil
   573  }
   574  
   575  // Flattens an array of Options into a []map[string]interface{}
   576  func flattenOptions(list []*rds.Option) []map[string]interface{} {
   577  	result := make([]map[string]interface{}, 0, len(list))
   578  	for _, i := range list {
   579  		if i.OptionName != nil {
   580  			r := make(map[string]interface{})
   581  			r["option_name"] = strings.ToLower(*i.OptionName)
   582  			// Default empty string, guard against nil parameter values
   583  			r["port"] = ""
   584  			if i.Port != nil {
   585  				r["port"] = int(*i.Port)
   586  			}
   587  			if i.VpcSecurityGroupMemberships != nil {
   588  				vpcs := make([]string, 0, len(i.VpcSecurityGroupMemberships))
   589  				for _, vpc := range i.VpcSecurityGroupMemberships {
   590  					id := vpc.VpcSecurityGroupId
   591  					vpcs = append(vpcs, *id)
   592  				}
   593  
   594  				r["vpc_security_group_memberships"] = vpcs
   595  			}
   596  			if i.DBSecurityGroupMemberships != nil {
   597  				dbs := make([]string, 0, len(i.DBSecurityGroupMemberships))
   598  				for _, db := range i.DBSecurityGroupMemberships {
   599  					id := db.DBSecurityGroupName
   600  					dbs = append(dbs, *id)
   601  				}
   602  
   603  				r["db_security_group_memberships"] = dbs
   604  			}
   605  			if i.OptionSettings != nil {
   606  				settings := make([]map[string]interface{}, 0, len(i.OptionSettings))
   607  				for _, j := range i.OptionSettings {
   608  					settings = append(settings, map[string]interface{}{
   609  						"name":  *j.Name,
   610  						"value": *j.Value,
   611  					})
   612  				}
   613  
   614  				r["option_settings"] = settings
   615  			}
   616  			result = append(result, r)
   617  		}
   618  	}
   619  	return result
   620  }
   621  
   622  // Flattens an array of Parameters into a []map[string]interface{}
   623  func flattenParameters(list []*rds.Parameter) []map[string]interface{} {
   624  	result := make([]map[string]interface{}, 0, len(list))
   625  	for _, i := range list {
   626  		if i.ParameterName != nil {
   627  			r := make(map[string]interface{})
   628  			r["name"] = strings.ToLower(*i.ParameterName)
   629  			// Default empty string, guard against nil parameter values
   630  			r["value"] = ""
   631  			if i.ParameterValue != nil {
   632  				r["value"] = strings.ToLower(*i.ParameterValue)
   633  			}
   634  			result = append(result, r)
   635  		}
   636  	}
   637  	return result
   638  }
   639  
   640  // Flattens an array of Redshift Parameters into a []map[string]interface{}
   641  func flattenRedshiftParameters(list []*redshift.Parameter) []map[string]interface{} {
   642  	result := make([]map[string]interface{}, 0, len(list))
   643  	for _, i := range list {
   644  		result = append(result, map[string]interface{}{
   645  			"name":  strings.ToLower(*i.ParameterName),
   646  			"value": strings.ToLower(*i.ParameterValue),
   647  		})
   648  	}
   649  	return result
   650  }
   651  
   652  // Flattens an array of Parameters into a []map[string]interface{}
   653  func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} {
   654  	result := make([]map[string]interface{}, 0, len(list))
   655  	for _, i := range list {
   656  		if i.ParameterValue != nil {
   657  			result = append(result, map[string]interface{}{
   658  				"name":  strings.ToLower(*i.ParameterName),
   659  				"value": strings.ToLower(*i.ParameterValue),
   660  			})
   661  		}
   662  	}
   663  	return result
   664  }
   665  
   666  // Takes the result of flatmap.Expand for an array of strings
   667  // and returns a []*string
   668  func expandStringList(configured []interface{}) []*string {
   669  	vs := make([]*string, 0, len(configured))
   670  	for _, v := range configured {
   671  		vs = append(vs, aws.String(v.(string)))
   672  	}
   673  	return vs
   674  }
   675  
   676  // Takes the result of schema.Set of strings and returns a []*string
   677  func expandStringSet(configured *schema.Set) []*string {
   678  	return expandStringList(configured.List())
   679  }
   680  
   681  // Takes list of pointers to strings. Expand to an array
   682  // of raw strings and returns a []interface{}
   683  // to keep compatibility w/ schema.NewSetschema.NewSet
   684  func flattenStringList(list []*string) []interface{} {
   685  	vs := make([]interface{}, 0, len(list))
   686  	for _, v := range list {
   687  		vs = append(vs, *v)
   688  	}
   689  	return vs
   690  }
   691  
   692  //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0"
   693  func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string {
   694  	ips := make([]string, 0, len(dtos))
   695  	for _, v := range dtos {
   696  		ip := *v.PrivateIpAddress
   697  		ips = append(ips, ip)
   698  	}
   699  	return ips
   700  }
   701  
   702  //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs
   703  func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string {
   704  	ids := make([]string, 0, len(dtos))
   705  	for _, v := range dtos {
   706  		group_id := *v.GroupId
   707  		ids = append(ids, group_id)
   708  	}
   709  	return ids
   710  }
   711  
   712  //Expands an array of IPs into a ec2 Private IP Address Spec
   713  func expandPrivateIPAddresses(ips []interface{}) []*ec2.PrivateIpAddressSpecification {
   714  	dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips))
   715  	for i, v := range ips {
   716  		new_private_ip := &ec2.PrivateIpAddressSpecification{
   717  			PrivateIpAddress: aws.String(v.(string)),
   718  		}
   719  
   720  		new_private_ip.Primary = aws.Bool(i == 0)
   721  
   722  		dtos = append(dtos, new_private_ip)
   723  	}
   724  	return dtos
   725  }
   726  
   727  //Flattens network interface attachment into a map[string]interface
   728  func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} {
   729  	att := make(map[string]interface{})
   730  	if a.InstanceId != nil {
   731  		att["instance"] = *a.InstanceId
   732  	}
   733  	att["device_index"] = *a.DeviceIndex
   734  	att["attachment_id"] = *a.AttachmentId
   735  	return att
   736  }
   737  
   738  // Flattens step adjustments into a list of map[string]interface.
   739  func flattenStepAdjustments(adjustments []*autoscaling.StepAdjustment) []map[string]interface{} {
   740  	result := make([]map[string]interface{}, 0, len(adjustments))
   741  	for _, raw := range adjustments {
   742  		a := map[string]interface{}{
   743  			"scaling_adjustment": *raw.ScalingAdjustment,
   744  		}
   745  		if raw.MetricIntervalUpperBound != nil {
   746  			a["metric_interval_upper_bound"] = *raw.MetricIntervalUpperBound
   747  		}
   748  		if raw.MetricIntervalLowerBound != nil {
   749  			a["metric_interval_lower_bound"] = *raw.MetricIntervalLowerBound
   750  		}
   751  		result = append(result, a)
   752  	}
   753  	return result
   754  }
   755  
   756  func flattenResourceRecords(recs []*route53.ResourceRecord) []string {
   757  	strs := make([]string, 0, len(recs))
   758  	for _, r := range recs {
   759  		if r.Value != nil {
   760  			s := strings.Replace(*r.Value, "\"", "", 2)
   761  			strs = append(strs, s)
   762  		}
   763  	}
   764  	return strs
   765  }
   766  
   767  func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord {
   768  	records := make([]*route53.ResourceRecord, 0, len(recs))
   769  	for _, r := range recs {
   770  		s := r.(string)
   771  		switch typeStr {
   772  		case "TXT", "SPF":
   773  			str := fmt.Sprintf("\"%s\"", s)
   774  			records = append(records, &route53.ResourceRecord{Value: aws.String(str)})
   775  		default:
   776  			records = append(records, &route53.ResourceRecord{Value: aws.String(s)})
   777  		}
   778  	}
   779  	return records
   780  }
   781  
   782  func expandESClusterConfig(m map[string]interface{}) *elasticsearch.ElasticsearchClusterConfig {
   783  	config := elasticsearch.ElasticsearchClusterConfig{}
   784  
   785  	if v, ok := m["dedicated_master_enabled"]; ok {
   786  		isEnabled := v.(bool)
   787  		config.DedicatedMasterEnabled = aws.Bool(isEnabled)
   788  
   789  		if isEnabled {
   790  			if v, ok := m["dedicated_master_count"]; ok && v.(int) > 0 {
   791  				config.DedicatedMasterCount = aws.Int64(int64(v.(int)))
   792  			}
   793  			if v, ok := m["dedicated_master_type"]; ok && v.(string) != "" {
   794  				config.DedicatedMasterType = aws.String(v.(string))
   795  			}
   796  		}
   797  	}
   798  
   799  	if v, ok := m["instance_count"]; ok {
   800  		config.InstanceCount = aws.Int64(int64(v.(int)))
   801  	}
   802  	if v, ok := m["instance_type"]; ok {
   803  		config.InstanceType = aws.String(v.(string))
   804  	}
   805  
   806  	if v, ok := m["zone_awareness_enabled"]; ok {
   807  		config.ZoneAwarenessEnabled = aws.Bool(v.(bool))
   808  	}
   809  
   810  	return &config
   811  }
   812  
   813  func flattenESClusterConfig(c *elasticsearch.ElasticsearchClusterConfig) []map[string]interface{} {
   814  	m := map[string]interface{}{}
   815  
   816  	if c.DedicatedMasterCount != nil {
   817  		m["dedicated_master_count"] = *c.DedicatedMasterCount
   818  	}
   819  	if c.DedicatedMasterEnabled != nil {
   820  		m["dedicated_master_enabled"] = *c.DedicatedMasterEnabled
   821  	}
   822  	if c.DedicatedMasterType != nil {
   823  		m["dedicated_master_type"] = *c.DedicatedMasterType
   824  	}
   825  	if c.InstanceCount != nil {
   826  		m["instance_count"] = *c.InstanceCount
   827  	}
   828  	if c.InstanceType != nil {
   829  		m["instance_type"] = *c.InstanceType
   830  	}
   831  	if c.ZoneAwarenessEnabled != nil {
   832  		m["zone_awareness_enabled"] = *c.ZoneAwarenessEnabled
   833  	}
   834  
   835  	return []map[string]interface{}{m}
   836  }
   837  
   838  func flattenESEBSOptions(o *elasticsearch.EBSOptions) []map[string]interface{} {
   839  	m := map[string]interface{}{}
   840  
   841  	if o.EBSEnabled != nil {
   842  		m["ebs_enabled"] = *o.EBSEnabled
   843  	}
   844  	if o.Iops != nil {
   845  		m["iops"] = *o.Iops
   846  	}
   847  	if o.VolumeSize != nil {
   848  		m["volume_size"] = *o.VolumeSize
   849  	}
   850  	if o.VolumeType != nil {
   851  		m["volume_type"] = *o.VolumeType
   852  	}
   853  
   854  	return []map[string]interface{}{m}
   855  }
   856  
   857  func expandESEBSOptions(m map[string]interface{}) *elasticsearch.EBSOptions {
   858  	options := elasticsearch.EBSOptions{}
   859  
   860  	if v, ok := m["ebs_enabled"]; ok {
   861  		options.EBSEnabled = aws.Bool(v.(bool))
   862  	}
   863  	if v, ok := m["iops"]; ok && v.(int) > 0 {
   864  		options.Iops = aws.Int64(int64(v.(int)))
   865  	}
   866  	if v, ok := m["volume_size"]; ok && v.(int) > 0 {
   867  		options.VolumeSize = aws.Int64(int64(v.(int)))
   868  	}
   869  	if v, ok := m["volume_type"]; ok && v.(string) != "" {
   870  		options.VolumeType = aws.String(v.(string))
   871  	}
   872  
   873  	return &options
   874  }
   875  
   876  func pointersMapToStringList(pointers map[string]*string) map[string]interface{} {
   877  	list := make(map[string]interface{}, len(pointers))
   878  	for i, v := range pointers {
   879  		list[i] = *v
   880  	}
   881  	return list
   882  }
   883  
   884  func stringMapToPointers(m map[string]interface{}) map[string]*string {
   885  	list := make(map[string]*string, len(m))
   886  	for i, v := range m {
   887  		list[i] = aws.String(v.(string))
   888  	}
   889  	return list
   890  }
   891  
   892  func flattenDSVpcSettings(
   893  	s *directoryservice.DirectoryVpcSettingsDescription) []map[string]interface{} {
   894  	settings := make(map[string]interface{}, 0)
   895  
   896  	if s == nil {
   897  		return nil
   898  	}
   899  
   900  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   901  	settings["vpc_id"] = *s.VpcId
   902  
   903  	return []map[string]interface{}{settings}
   904  }
   905  
   906  func flattenLambdaVpcConfigResponse(s *lambda.VpcConfigResponse) []map[string]interface{} {
   907  	settings := make(map[string]interface{}, 0)
   908  
   909  	if s == nil {
   910  		return nil
   911  	}
   912  
   913  	if len(s.SubnetIds) == 0 && len(s.SecurityGroupIds) == 0 && s.VpcId == nil {
   914  		return nil
   915  	}
   916  
   917  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   918  	settings["security_group_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SecurityGroupIds))
   919  	if s.VpcId != nil {
   920  		settings["vpc_id"] = *s.VpcId
   921  	}
   922  
   923  	return []map[string]interface{}{settings}
   924  }
   925  
   926  func flattenDSConnectSettings(
   927  	customerDnsIps []*string,
   928  	s *directoryservice.DirectoryConnectSettingsDescription) []map[string]interface{} {
   929  	if s == nil {
   930  		return nil
   931  	}
   932  
   933  	settings := make(map[string]interface{}, 0)
   934  
   935  	settings["customer_dns_ips"] = schema.NewSet(schema.HashString, flattenStringList(customerDnsIps))
   936  	settings["connect_ips"] = schema.NewSet(schema.HashString, flattenStringList(s.ConnectIps))
   937  	settings["customer_username"] = *s.CustomerUserName
   938  	settings["subnet_ids"] = schema.NewSet(schema.HashString, flattenStringList(s.SubnetIds))
   939  	settings["vpc_id"] = *s.VpcId
   940  
   941  	return []map[string]interface{}{settings}
   942  }
   943  
   944  func expandCloudFormationParameters(params map[string]interface{}) []*cloudformation.Parameter {
   945  	var cfParams []*cloudformation.Parameter
   946  	for k, v := range params {
   947  		cfParams = append(cfParams, &cloudformation.Parameter{
   948  			ParameterKey:   aws.String(k),
   949  			ParameterValue: aws.String(v.(string)),
   950  		})
   951  	}
   952  
   953  	return cfParams
   954  }
   955  
   956  // flattenCloudFormationParameters is flattening list of
   957  // *cloudformation.Parameters and only returning existing
   958  // parameters to avoid clash with default values
   959  func flattenCloudFormationParameters(cfParams []*cloudformation.Parameter,
   960  	originalParams map[string]interface{}) map[string]interface{} {
   961  	params := make(map[string]interface{}, len(cfParams))
   962  	for _, p := range cfParams {
   963  		_, isConfigured := originalParams[*p.ParameterKey]
   964  		if isConfigured {
   965  			params[*p.ParameterKey] = *p.ParameterValue
   966  		}
   967  	}
   968  	return params
   969  }
   970  
   971  func expandCloudFormationTags(tags map[string]interface{}) []*cloudformation.Tag {
   972  	var cfTags []*cloudformation.Tag
   973  	for k, v := range tags {
   974  		cfTags = append(cfTags, &cloudformation.Tag{
   975  			Key:   aws.String(k),
   976  			Value: aws.String(v.(string)),
   977  		})
   978  	}
   979  	return cfTags
   980  }
   981  
   982  func flattenCloudFormationTags(cfTags []*cloudformation.Tag) map[string]string {
   983  	tags := make(map[string]string, len(cfTags))
   984  	for _, t := range cfTags {
   985  		tags[*t.Key] = *t.Value
   986  	}
   987  	return tags
   988  }
   989  
   990  func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string]string {
   991  	outputs := make(map[string]string, len(cfOutputs))
   992  	for _, o := range cfOutputs {
   993  		outputs[*o.OutputKey] = *o.OutputValue
   994  	}
   995  	return outputs
   996  }
   997  
   998  func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string {
   999  	strs := make([]string, 0, len(list))
  1000  	for _, r := range list {
  1001  		if r.Metric != nil {
  1002  			strs = append(strs, *r.Metric)
  1003  		}
  1004  	}
  1005  	return strs
  1006  }
  1007  
  1008  func flattenApiGatewayStageKeys(keys []*string) []map[string]interface{} {
  1009  	stageKeys := make([]map[string]interface{}, 0, len(keys))
  1010  	for _, o := range keys {
  1011  		key := make(map[string]interface{})
  1012  		parts := strings.Split(*o, "/")
  1013  		key["stage_name"] = parts[1]
  1014  		key["rest_api_id"] = parts[0]
  1015  
  1016  		stageKeys = append(stageKeys, key)
  1017  	}
  1018  	return stageKeys
  1019  }
  1020  
  1021  func expandApiGatewayStageKeys(d *schema.ResourceData) []*apigateway.StageKey {
  1022  	var stageKeys []*apigateway.StageKey
  1023  
  1024  	if stageKeyData, ok := d.GetOk("stage_key"); ok {
  1025  		params := stageKeyData.(*schema.Set).List()
  1026  		for k := range params {
  1027  			data := params[k].(map[string]interface{})
  1028  			stageKeys = append(stageKeys, &apigateway.StageKey{
  1029  				RestApiId: aws.String(data["rest_api_id"].(string)),
  1030  				StageName: aws.String(data["stage_name"].(string)),
  1031  			})
  1032  		}
  1033  	}
  1034  
  1035  	return stageKeys
  1036  }
  1037  
  1038  func expandApiGatewayRequestResponseModelOperations(d *schema.ResourceData, key string, prefix string) []*apigateway.PatchOperation {
  1039  	operations := make([]*apigateway.PatchOperation, 0)
  1040  
  1041  	oldModels, newModels := d.GetChange(key)
  1042  	oldModelMap := oldModels.(map[string]interface{})
  1043  	newModelMap := newModels.(map[string]interface{})
  1044  
  1045  	for k, _ := range oldModelMap {
  1046  		operation := apigateway.PatchOperation{
  1047  			Op:   aws.String("remove"),
  1048  			Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
  1049  		}
  1050  
  1051  		for nK, nV := range newModelMap {
  1052  			if nK == k {
  1053  				operation.Op = aws.String("replace")
  1054  				operation.Value = aws.String(nV.(string))
  1055  			}
  1056  		}
  1057  
  1058  		operations = append(operations, &operation)
  1059  	}
  1060  
  1061  	for nK, nV := range newModelMap {
  1062  		exists := false
  1063  		for k, _ := range oldModelMap {
  1064  			if k == nK {
  1065  				exists = true
  1066  			}
  1067  		}
  1068  		if !exists {
  1069  			operation := apigateway.PatchOperation{
  1070  				Op:    aws.String("add"),
  1071  				Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(nK, "/", "~1", -1))),
  1072  				Value: aws.String(nV.(string)),
  1073  			}
  1074  			operations = append(operations, &operation)
  1075  		}
  1076  	}
  1077  
  1078  	return operations
  1079  }
  1080  
  1081  func expandApiGatewayMethodParametersJSONOperations(d *schema.ResourceData, key string, prefix string) ([]*apigateway.PatchOperation, error) {
  1082  	operations := make([]*apigateway.PatchOperation, 0)
  1083  
  1084  	oldParameters, newParameters := d.GetChange(key)
  1085  	oldParametersMap := make(map[string]interface{})
  1086  	newParametersMap := make(map[string]interface{})
  1087  
  1088  	if err := json.Unmarshal([]byte(oldParameters.(string)), &oldParametersMap); err != nil {
  1089  		err := fmt.Errorf("Error unmarshaling old %s: %s", key, err)
  1090  		return operations, err
  1091  	}
  1092  
  1093  	if err := json.Unmarshal([]byte(newParameters.(string)), &newParametersMap); err != nil {
  1094  		err := fmt.Errorf("Error unmarshaling new %s: %s", key, err)
  1095  		return operations, err
  1096  	}
  1097  
  1098  	for k, _ := range oldParametersMap {
  1099  		operation := apigateway.PatchOperation{
  1100  			Op:   aws.String("remove"),
  1101  			Path: aws.String(fmt.Sprintf("/%s/%s", prefix, k)),
  1102  		}
  1103  
  1104  		for nK, nV := range newParametersMap {
  1105  			if nK == k {
  1106  				operation.Op = aws.String("replace")
  1107  				operation.Value = aws.String(strconv.FormatBool(nV.(bool)))
  1108  			}
  1109  		}
  1110  
  1111  		operations = append(operations, &operation)
  1112  	}
  1113  
  1114  	for nK, nV := range newParametersMap {
  1115  		exists := false
  1116  		for k, _ := range oldParametersMap {
  1117  			if k == nK {
  1118  				exists = true
  1119  			}
  1120  		}
  1121  		if !exists {
  1122  			operation := apigateway.PatchOperation{
  1123  				Op:    aws.String("add"),
  1124  				Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, nK)),
  1125  				Value: aws.String(strconv.FormatBool(nV.(bool))),
  1126  			}
  1127  			operations = append(operations, &operation)
  1128  		}
  1129  	}
  1130  
  1131  	return operations, nil
  1132  }
  1133  
  1134  func expandApiGatewayStageKeyOperations(d *schema.ResourceData) []*apigateway.PatchOperation {
  1135  	operations := make([]*apigateway.PatchOperation, 0)
  1136  
  1137  	prev, curr := d.GetChange("stage_key")
  1138  	prevList := prev.(*schema.Set).List()
  1139  	currList := curr.(*schema.Set).List()
  1140  
  1141  	for i := range prevList {
  1142  		p := prevList[i].(map[string]interface{})
  1143  		exists := false
  1144  
  1145  		for j := range currList {
  1146  			c := currList[j].(map[string]interface{})
  1147  			if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) {
  1148  				exists = true
  1149  			}
  1150  		}
  1151  
  1152  		if !exists {
  1153  			operations = append(operations, &apigateway.PatchOperation{
  1154  				Op:    aws.String("remove"),
  1155  				Path:  aws.String("/stages"),
  1156  				Value: aws.String(fmt.Sprintf("%s/%s", p["rest_api_id"].(string), p["stage_name"].(string))),
  1157  			})
  1158  		}
  1159  	}
  1160  
  1161  	for i := range currList {
  1162  		c := currList[i].(map[string]interface{})
  1163  		exists := false
  1164  
  1165  		for j := range prevList {
  1166  			p := prevList[j].(map[string]interface{})
  1167  			if c["rest_api_id"].(string) == p["rest_api_id"].(string) && c["stage_name"].(string) == p["stage_name"].(string) {
  1168  				exists = true
  1169  			}
  1170  		}
  1171  
  1172  		if !exists {
  1173  			operations = append(operations, &apigateway.PatchOperation{
  1174  				Op:    aws.String("add"),
  1175  				Path:  aws.String("/stages"),
  1176  				Value: aws.String(fmt.Sprintf("%s/%s", c["rest_api_id"].(string), c["stage_name"].(string))),
  1177  			})
  1178  		}
  1179  	}
  1180  
  1181  	return operations
  1182  }
  1183  
  1184  func expandCloudWachLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation {
  1185  	transformation := cloudwatchlogs.MetricTransformation{
  1186  		MetricName:      aws.String(m["name"].(string)),
  1187  		MetricNamespace: aws.String(m["namespace"].(string)),
  1188  		MetricValue:     aws.String(m["value"].(string)),
  1189  	}
  1190  
  1191  	return []*cloudwatchlogs.MetricTransformation{&transformation}
  1192  }
  1193  
  1194  func flattenCloudWachLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) map[string]string {
  1195  	m := make(map[string]string, 0)
  1196  
  1197  	m["name"] = *ts[0].MetricName
  1198  	m["namespace"] = *ts[0].MetricNamespace
  1199  	m["value"] = *ts[0].MetricValue
  1200  
  1201  	return m
  1202  }
  1203  
  1204  func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string {
  1205  	strs := make([]string, 0, len(list))
  1206  	for _, r := range list {
  1207  		if r.Name != nil {
  1208  			strs = append(strs, *r.Name)
  1209  		}
  1210  	}
  1211  	return strs
  1212  }
  1213  
  1214  func flattenBeanstalkInstances(list []*elasticbeanstalk.Instance) []string {
  1215  	strs := make([]string, 0, len(list))
  1216  	for _, r := range list {
  1217  		if r.Id != nil {
  1218  			strs = append(strs, *r.Id)
  1219  		}
  1220  	}
  1221  	return strs
  1222  }
  1223  
  1224  func flattenBeanstalkLc(list []*elasticbeanstalk.LaunchConfiguration) []string {
  1225  	strs := make([]string, 0, len(list))
  1226  	for _, r := range list {
  1227  		if r.Name != nil {
  1228  			strs = append(strs, *r.Name)
  1229  		}
  1230  	}
  1231  	return strs
  1232  }
  1233  
  1234  func flattenBeanstalkElb(list []*elasticbeanstalk.LoadBalancer) []string {
  1235  	strs := make([]string, 0, len(list))
  1236  	for _, r := range list {
  1237  		if r.Name != nil {
  1238  			strs = append(strs, *r.Name)
  1239  		}
  1240  	}
  1241  	return strs
  1242  }
  1243  
  1244  func flattenBeanstalkSqs(list []*elasticbeanstalk.Queue) []string {
  1245  	strs := make([]string, 0, len(list))
  1246  	for _, r := range list {
  1247  		if r.URL != nil {
  1248  			strs = append(strs, *r.URL)
  1249  		}
  1250  	}
  1251  	return strs
  1252  }
  1253  
  1254  func flattenBeanstalkTrigger(list []*elasticbeanstalk.Trigger) []string {
  1255  	strs := make([]string, 0, len(list))
  1256  	for _, r := range list {
  1257  		if r.Name != nil {
  1258  			strs = append(strs, *r.Name)
  1259  		}
  1260  	}
  1261  	return strs
  1262  }
  1263  
  1264  // There are several parts of the AWS API that will sort lists of strings,
  1265  // causing diffs inbetweeen resources that use lists. This avoids a bit of
  1266  // code duplication for pre-sorts that can be used for things like hash
  1267  // functions, etc.
  1268  func sortInterfaceSlice(in []interface{}) []interface{} {
  1269  	a := []string{}
  1270  	b := []interface{}{}
  1271  	for _, v := range in {
  1272  		a = append(a, v.(string))
  1273  	}
  1274  
  1275  	sort.Strings(a)
  1276  
  1277  	for _, v := range a {
  1278  		b = append(b, v)
  1279  	}
  1280  
  1281  	return b
  1282  }
  1283  
  1284  func flattenApiGatewayThrottleSettings(settings *apigateway.ThrottleSettings) []map[string]interface{} {
  1285  	result := make([]map[string]interface{}, 0, 1)
  1286  
  1287  	if settings != nil {
  1288  		r := make(map[string]interface{})
  1289  		if settings.BurstLimit != nil {
  1290  			r["burst_limit"] = *settings.BurstLimit
  1291  		}
  1292  
  1293  		if settings.RateLimit != nil {
  1294  			r["rate_limit"] = *settings.RateLimit
  1295  		}
  1296  
  1297  		result = append(result, r)
  1298  	}
  1299  
  1300  	return result
  1301  }
  1302  
  1303  // TODO: refactor some of these helper functions and types in the terraform/helper packages
  1304  
  1305  // getStringPtr returns a *string version of the value taken from m, where m
  1306  // can be a map[string]interface{} or a *schema.ResourceData. If the key isn't
  1307  // present or is empty, getNilString returns nil.
  1308  func getStringPtr(m interface{}, key string) *string {
  1309  	switch m := m.(type) {
  1310  	case map[string]interface{}:
  1311  		v := m[key]
  1312  
  1313  		if v == nil {
  1314  			return nil
  1315  		}
  1316  
  1317  		s := v.(string)
  1318  		if s == "" {
  1319  			return nil
  1320  		}
  1321  
  1322  		return &s
  1323  
  1324  	case *schema.ResourceData:
  1325  		if v, ok := m.GetOk(key); ok {
  1326  			if v == nil || v.(string) == "" {
  1327  				return nil
  1328  			}
  1329  			s := v.(string)
  1330  			return &s
  1331  		}
  1332  
  1333  	default:
  1334  		panic("unknown type in getStringPtr")
  1335  	}
  1336  
  1337  	return nil
  1338  }
  1339  
  1340  // getStringPtrList returns a []*string version of the map value. If the key
  1341  // isn't present, getNilStringList returns nil.
  1342  func getStringPtrList(m map[string]interface{}, key string) []*string {
  1343  	if v, ok := m[key]; ok {
  1344  		var stringList []*string
  1345  		for _, i := range v.([]interface{}) {
  1346  			s := i.(string)
  1347  			stringList = append(stringList, &s)
  1348  		}
  1349  
  1350  		return stringList
  1351  	}
  1352  
  1353  	return nil
  1354  }
  1355  
  1356  // a convenience wrapper type for the schema.Set map[string]interface{}
  1357  // Set operations only alter the underlying map if the value is not nil
  1358  type setMap map[string]interface{}
  1359  
  1360  // SetString sets m[key] = *value only if `value != nil`
  1361  func (s setMap) SetString(key string, value *string) {
  1362  	if value == nil {
  1363  		return
  1364  	}
  1365  
  1366  	s[key] = *value
  1367  }
  1368  
  1369  // SetStringMap sets key to value as a map[string]interface{}, stripping any nil
  1370  // values. The value parameter can be a map[string]interface{}, a
  1371  // map[string]*string, or a map[string]string.
  1372  func (s setMap) SetStringMap(key string, value interface{}) {
  1373  	// because these methods are meant to be chained without intermediate
  1374  	// checks for nil, we are likely to get interfaces with dynamic types but
  1375  	// a nil value.
  1376  	if reflect.ValueOf(value).IsNil() {
  1377  		return
  1378  	}
  1379  
  1380  	m := make(map[string]interface{})
  1381  
  1382  	switch value := value.(type) {
  1383  	case map[string]string:
  1384  		for k, v := range value {
  1385  			m[k] = v
  1386  		}
  1387  	case map[string]*string:
  1388  		for k, v := range value {
  1389  			if v == nil {
  1390  				continue
  1391  			}
  1392  			m[k] = *v
  1393  		}
  1394  	case map[string]interface{}:
  1395  		for k, v := range value {
  1396  			if v == nil {
  1397  				continue
  1398  			}
  1399  
  1400  			switch v := v.(type) {
  1401  			case string:
  1402  				m[k] = v
  1403  			case *string:
  1404  				if v != nil {
  1405  					m[k] = *v
  1406  				}
  1407  			default:
  1408  				panic(fmt.Sprintf("unknown type for SetString: %T", v))
  1409  			}
  1410  		}
  1411  	}
  1412  
  1413  	// catch the case where the interface wasn't nil, but we had no non-nil values
  1414  	if len(m) > 0 {
  1415  		s[key] = m
  1416  	}
  1417  }
  1418  
  1419  // Set assigns value to s[key] if value isn't nil
  1420  func (s setMap) Set(key string, value interface{}) {
  1421  	if reflect.ValueOf(value).IsNil() {
  1422  		return
  1423  	}
  1424  
  1425  	s[key] = value
  1426  }
  1427  
  1428  // Map returns the raw map type for a shorter type conversion
  1429  func (s setMap) Map() map[string]interface{} {
  1430  	return map[string]interface{}(s)
  1431  }
  1432  
  1433  // MapList returns the map[string]interface{} as a single element in a slice to
  1434  // match the schema.Set data type used for structs.
  1435  func (s setMap) MapList() []map[string]interface{} {
  1436  	return []map[string]interface{}{s.Map()}
  1437  }