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