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