github.com/rjeczalik/terraform@v0.6.7-0.20160812060014-e251d5c7bd39/builtin/providers/aws/structure.go (about)

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