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