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