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