github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/cloudfront_distribution_configuration_structure.go (about)

     1  // CloudFront DistributionConfig structure helpers.
     2  //
     3  // These functions assist in pulling in data from Terraform resource
     4  // configuration for the aws_cloudfront_distribution resource, as there are
     5  // several sub-fields that require their own data type, and do not necessarily
     6  // 1-1 translate to resource configuration.
     7  
     8  package aws
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	"reflect"
    14  	"sort"
    15  	"strconv"
    16  	"time"
    17  
    18  	"github.com/aws/aws-sdk-go/aws"
    19  	"github.com/aws/aws-sdk-go/service/cloudfront"
    20  	"github.com/hashicorp/terraform/flatmap"
    21  	"github.com/hashicorp/terraform/helper/hashcode"
    22  	"github.com/hashicorp/terraform/helper/schema"
    23  )
    24  
    25  // cloudFrontRoute53ZoneID defines the route 53 zone ID for CloudFront. This
    26  // is used to set the zone_id attribute.
    27  const cloudFrontRoute53ZoneID = "Z2FDTNDATAQYW2"
    28  
    29  // Define Sort interface for []*string so we can ensure the order of
    30  // geo_restrictions.locations
    31  type StringPtrSlice []*string
    32  
    33  func (p StringPtrSlice) Len() int           { return len(p) }
    34  func (p StringPtrSlice) Less(i, j int) bool { return *p[i] < *p[j] }
    35  func (p StringPtrSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
    36  
    37  // Assemble the *cloudfront.DistributionConfig variable. Calls out to various
    38  // expander functions to convert attributes and sub-attributes to the various
    39  // complex structures which are necessary to properly build the
    40  // DistributionConfig structure.
    41  //
    42  // Used by the aws_cloudfront_distribution Create and Update functions.
    43  func expandDistributionConfig(d *schema.ResourceData) *cloudfront.DistributionConfig {
    44  	distributionConfig := &cloudfront.DistributionConfig{
    45  		CacheBehaviors:       expandCacheBehaviors(d.Get("cache_behavior").(*schema.Set)),
    46  		CustomErrorResponses: expandCustomErrorResponses(d.Get("custom_error_response").(*schema.Set)),
    47  		DefaultCacheBehavior: expandDefaultCacheBehavior(d.Get("default_cache_behavior").(*schema.Set).List()[0].(map[string]interface{})),
    48  		Enabled:              aws.Bool(d.Get("enabled").(bool)),
    49  		IsIPV6Enabled:        aws.Bool(d.Get("is_ipv6_enabled").(bool)),
    50  		HttpVersion:          aws.String(d.Get("http_version").(string)),
    51  		Origins:              expandOrigins(d.Get("origin").(*schema.Set)),
    52  		PriceClass:           aws.String(d.Get("price_class").(string)),
    53  	}
    54  	// This sets CallerReference if it's still pending computation (ie: new resource)
    55  	if v, ok := d.GetOk("caller_reference"); ok == false {
    56  		distributionConfig.CallerReference = aws.String(time.Now().Format(time.RFC3339Nano))
    57  	} else {
    58  		distributionConfig.CallerReference = aws.String(v.(string))
    59  	}
    60  	if v, ok := d.GetOk("comment"); ok {
    61  		distributionConfig.Comment = aws.String(v.(string))
    62  	} else {
    63  		distributionConfig.Comment = aws.String("")
    64  	}
    65  	if v, ok := d.GetOk("default_root_object"); ok {
    66  		distributionConfig.DefaultRootObject = aws.String(v.(string))
    67  	} else {
    68  		distributionConfig.DefaultRootObject = aws.String("")
    69  	}
    70  	if v, ok := d.GetOk("logging_config"); ok {
    71  		distributionConfig.Logging = expandLoggingConfig(v.(*schema.Set).List()[0].(map[string]interface{}))
    72  	} else {
    73  		distributionConfig.Logging = expandLoggingConfig(nil)
    74  	}
    75  	if v, ok := d.GetOk("aliases"); ok {
    76  		distributionConfig.Aliases = expandAliases(v.(*schema.Set))
    77  	} else {
    78  		distributionConfig.Aliases = expandAliases(schema.NewSet(aliasesHash, []interface{}{}))
    79  	}
    80  	if v, ok := d.GetOk("restrictions"); ok {
    81  		distributionConfig.Restrictions = expandRestrictions(v.(*schema.Set).List()[0].(map[string]interface{}))
    82  	}
    83  	if v, ok := d.GetOk("viewer_certificate"); ok {
    84  		distributionConfig.ViewerCertificate = expandViewerCertificate(v.(*schema.Set).List()[0].(map[string]interface{}))
    85  	}
    86  	if v, ok := d.GetOk("web_acl_id"); ok {
    87  		distributionConfig.WebACLId = aws.String(v.(string))
    88  	} else {
    89  		distributionConfig.WebACLId = aws.String("")
    90  	}
    91  
    92  	return distributionConfig
    93  }
    94  
    95  // Unpack the *cloudfront.DistributionConfig variable and set resource data.
    96  // Calls out to flatten functions to convert the DistributionConfig
    97  // sub-structures to their respective attributes in the
    98  // aws_cloudfront_distribution resource.
    99  //
   100  // Used by the aws_cloudfront_distribution Read function.
   101  func flattenDistributionConfig(d *schema.ResourceData, distributionConfig *cloudfront.DistributionConfig) error {
   102  	var err error
   103  
   104  	d.Set("enabled", distributionConfig.Enabled)
   105  	d.Set("is_ipv6_enabled", distributionConfig.IsIPV6Enabled)
   106  	d.Set("price_class", distributionConfig.PriceClass)
   107  	d.Set("hosted_zone_id", cloudFrontRoute53ZoneID)
   108  
   109  	err = d.Set("default_cache_behavior", flattenDefaultCacheBehavior(distributionConfig.DefaultCacheBehavior))
   110  	if err != nil {
   111  		return err
   112  	}
   113  	err = d.Set("viewer_certificate", flattenViewerCertificate(distributionConfig.ViewerCertificate))
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	if distributionConfig.CallerReference != nil {
   119  		d.Set("caller_reference", distributionConfig.CallerReference)
   120  	}
   121  	if distributionConfig.Comment != nil {
   122  		if *distributionConfig.Comment != "" {
   123  			d.Set("comment", distributionConfig.Comment)
   124  		}
   125  	}
   126  	if distributionConfig.DefaultRootObject != nil {
   127  		d.Set("default_root_object", distributionConfig.DefaultRootObject)
   128  	}
   129  	if distributionConfig.HttpVersion != nil {
   130  		d.Set("http_version", distributionConfig.HttpVersion)
   131  	}
   132  	if distributionConfig.WebACLId != nil {
   133  		d.Set("web_acl_id", distributionConfig.WebACLId)
   134  	}
   135  
   136  	if distributionConfig.CustomErrorResponses != nil {
   137  		err = d.Set("custom_error_response", flattenCustomErrorResponses(distributionConfig.CustomErrorResponses))
   138  		if err != nil {
   139  			return err
   140  		}
   141  	}
   142  	if distributionConfig.CacheBehaviors != nil {
   143  		err = d.Set("cache_behavior", flattenCacheBehaviors(distributionConfig.CacheBehaviors))
   144  		if err != nil {
   145  			return err
   146  		}
   147  	}
   148  
   149  	if distributionConfig.Logging != nil && *distributionConfig.Logging.Enabled {
   150  		err = d.Set("logging_config", flattenLoggingConfig(distributionConfig.Logging))
   151  	} else {
   152  		err = d.Set("logging_config", schema.NewSet(loggingConfigHash, []interface{}{}))
   153  	}
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	if distributionConfig.Aliases != nil {
   159  		err = d.Set("aliases", flattenAliases(distributionConfig.Aliases))
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  	if distributionConfig.Restrictions != nil {
   165  		err = d.Set("restrictions", flattenRestrictions(distributionConfig.Restrictions))
   166  		if err != nil {
   167  			return err
   168  		}
   169  	}
   170  	if *distributionConfig.Origins.Quantity > 0 {
   171  		err = d.Set("origin", flattenOrigins(distributionConfig.Origins))
   172  		if err != nil {
   173  			return err
   174  		}
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  func expandDefaultCacheBehavior(m map[string]interface{}) *cloudfront.DefaultCacheBehavior {
   181  	cb := expandCacheBehavior(m)
   182  	var dcb cloudfront.DefaultCacheBehavior
   183  
   184  	simpleCopyStruct(cb, &dcb)
   185  	return &dcb
   186  }
   187  
   188  func flattenDefaultCacheBehavior(dcb *cloudfront.DefaultCacheBehavior) *schema.Set {
   189  	m := make(map[string]interface{})
   190  	var cb cloudfront.CacheBehavior
   191  
   192  	simpleCopyStruct(dcb, &cb)
   193  	m = flattenCacheBehavior(&cb)
   194  	return schema.NewSet(defaultCacheBehaviorHash, []interface{}{m})
   195  }
   196  
   197  // Assemble the hash for the aws_cloudfront_distribution default_cache_behavior
   198  // TypeSet attribute.
   199  func defaultCacheBehaviorHash(v interface{}) int {
   200  	var buf bytes.Buffer
   201  	m := v.(map[string]interface{})
   202  	buf.WriteString(fmt.Sprintf("%t-", m["compress"].(bool)))
   203  	buf.WriteString(fmt.Sprintf("%s-", m["viewer_protocol_policy"].(string)))
   204  	buf.WriteString(fmt.Sprintf("%s-", m["target_origin_id"].(string)))
   205  	buf.WriteString(fmt.Sprintf("%d-", forwardedValuesHash(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{}))))
   206  	buf.WriteString(fmt.Sprintf("%d-", m["min_ttl"].(int)))
   207  	if d, ok := m["trusted_signers"]; ok {
   208  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   209  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   210  		}
   211  	}
   212  	if d, ok := m["max_ttl"]; ok {
   213  		buf.WriteString(fmt.Sprintf("%d-", d.(int)))
   214  	}
   215  	if d, ok := m["smooth_streaming"]; ok {
   216  		buf.WriteString(fmt.Sprintf("%t-", d.(bool)))
   217  	}
   218  	if d, ok := m["default_ttl"]; ok {
   219  		buf.WriteString(fmt.Sprintf("%d-", d.(int)))
   220  	}
   221  	if d, ok := m["allowed_methods"]; ok {
   222  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   223  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   224  		}
   225  	}
   226  	if d, ok := m["cached_methods"]; ok {
   227  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   228  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   229  		}
   230  	}
   231  	if d, ok := m["lambda_function_association"]; ok {
   232  		var associations []interface{}
   233  		switch d.(type) {
   234  		case *schema.Set:
   235  			associations = d.(*schema.Set).List()
   236  		default:
   237  			associations = d.([]interface{})
   238  		}
   239  		for _, lfa := range associations {
   240  			buf.WriteString(fmt.Sprintf("%d-", lambdaFunctionAssociationHash(lfa.(map[string]interface{}))))
   241  		}
   242  	}
   243  	return hashcode.String(buf.String())
   244  }
   245  
   246  func expandCacheBehaviors(s *schema.Set) *cloudfront.CacheBehaviors {
   247  	var qty int64
   248  	var items []*cloudfront.CacheBehavior
   249  	for _, v := range s.List() {
   250  		items = append(items, expandCacheBehavior(v.(map[string]interface{})))
   251  		qty++
   252  	}
   253  	return &cloudfront.CacheBehaviors{
   254  		Quantity: aws.Int64(qty),
   255  		Items:    items,
   256  	}
   257  }
   258  
   259  func flattenCacheBehaviors(cbs *cloudfront.CacheBehaviors) *schema.Set {
   260  	s := []interface{}{}
   261  	for _, v := range cbs.Items {
   262  		s = append(s, flattenCacheBehavior(v))
   263  	}
   264  	return schema.NewSet(cacheBehaviorHash, s)
   265  }
   266  
   267  func expandCacheBehavior(m map[string]interface{}) *cloudfront.CacheBehavior {
   268  	cb := &cloudfront.CacheBehavior{
   269  		Compress:             aws.Bool(m["compress"].(bool)),
   270  		ViewerProtocolPolicy: aws.String(m["viewer_protocol_policy"].(string)),
   271  		TargetOriginId:       aws.String(m["target_origin_id"].(string)),
   272  		ForwardedValues:      expandForwardedValues(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{})),
   273  		MinTTL:               aws.Int64(int64(m["min_ttl"].(int))),
   274  		MaxTTL:               aws.Int64(int64(m["max_ttl"].(int))),
   275  		DefaultTTL:           aws.Int64(int64(m["default_ttl"].(int))),
   276  	}
   277  	if v, ok := m["trusted_signers"]; ok {
   278  		cb.TrustedSigners = expandTrustedSigners(v.([]interface{}))
   279  	} else {
   280  		cb.TrustedSigners = expandTrustedSigners([]interface{}{})
   281  	}
   282  
   283  	if v, ok := m["lambda_function_association"]; ok {
   284  		cb.LambdaFunctionAssociations = expandLambdaFunctionAssociations(v.(*schema.Set).List())
   285  	}
   286  
   287  	if v, ok := m["smooth_streaming"]; ok {
   288  		cb.SmoothStreaming = aws.Bool(v.(bool))
   289  	}
   290  	if v, ok := m["allowed_methods"]; ok {
   291  		cb.AllowedMethods = expandAllowedMethods(v.([]interface{}))
   292  	}
   293  	if v, ok := m["cached_methods"]; ok {
   294  		cb.AllowedMethods.CachedMethods = expandCachedMethods(v.([]interface{}))
   295  	}
   296  	if v, ok := m["path_pattern"]; ok {
   297  		cb.PathPattern = aws.String(v.(string))
   298  	}
   299  	return cb
   300  }
   301  
   302  func flattenCacheBehavior(cb *cloudfront.CacheBehavior) map[string]interface{} {
   303  	m := make(map[string]interface{})
   304  
   305  	m["compress"] = *cb.Compress
   306  	m["viewer_protocol_policy"] = *cb.ViewerProtocolPolicy
   307  	m["target_origin_id"] = *cb.TargetOriginId
   308  	m["forwarded_values"] = schema.NewSet(forwardedValuesHash, []interface{}{flattenForwardedValues(cb.ForwardedValues)})
   309  	m["min_ttl"] = int(*cb.MinTTL)
   310  
   311  	if len(cb.TrustedSigners.Items) > 0 {
   312  		m["trusted_signers"] = flattenTrustedSigners(cb.TrustedSigners)
   313  	}
   314  	if len(cb.LambdaFunctionAssociations.Items) > 0 {
   315  		m["lambda_function_association"] = flattenLambdaFunctionAssociations(cb.LambdaFunctionAssociations)
   316  	}
   317  	if cb.MaxTTL != nil {
   318  		m["max_ttl"] = int(*cb.MaxTTL)
   319  	}
   320  	if cb.SmoothStreaming != nil {
   321  		m["smooth_streaming"] = *cb.SmoothStreaming
   322  	}
   323  	if cb.DefaultTTL != nil {
   324  		m["default_ttl"] = int(*cb.DefaultTTL)
   325  	}
   326  	if cb.AllowedMethods != nil {
   327  		m["allowed_methods"] = flattenAllowedMethods(cb.AllowedMethods)
   328  	}
   329  	if cb.AllowedMethods.CachedMethods != nil {
   330  		m["cached_methods"] = flattenCachedMethods(cb.AllowedMethods.CachedMethods)
   331  	}
   332  	if cb.PathPattern != nil {
   333  		m["path_pattern"] = *cb.PathPattern
   334  	}
   335  	return m
   336  }
   337  
   338  // Assemble the hash for the aws_cloudfront_distribution cache_behavior
   339  // TypeSet attribute.
   340  func cacheBehaviorHash(v interface{}) int {
   341  	var buf bytes.Buffer
   342  	m := v.(map[string]interface{})
   343  	buf.WriteString(fmt.Sprintf("%t-", m["compress"].(bool)))
   344  	buf.WriteString(fmt.Sprintf("%s-", m["viewer_protocol_policy"].(string)))
   345  	buf.WriteString(fmt.Sprintf("%s-", m["target_origin_id"].(string)))
   346  	buf.WriteString(fmt.Sprintf("%d-", forwardedValuesHash(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{}))))
   347  	buf.WriteString(fmt.Sprintf("%d-", m["min_ttl"].(int)))
   348  	if d, ok := m["trusted_signers"]; ok {
   349  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   350  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   351  		}
   352  	}
   353  	if d, ok := m["max_ttl"]; ok {
   354  		buf.WriteString(fmt.Sprintf("%d-", d.(int)))
   355  	}
   356  	if d, ok := m["smooth_streaming"]; ok {
   357  		buf.WriteString(fmt.Sprintf("%t-", d.(bool)))
   358  	}
   359  	if d, ok := m["default_ttl"]; ok {
   360  		buf.WriteString(fmt.Sprintf("%d-", d.(int)))
   361  	}
   362  	if d, ok := m["allowed_methods"]; ok {
   363  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   364  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   365  		}
   366  	}
   367  	if d, ok := m["cached_methods"]; ok {
   368  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   369  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   370  		}
   371  	}
   372  	if d, ok := m["path_pattern"]; ok {
   373  		buf.WriteString(fmt.Sprintf("%s-", d))
   374  	}
   375  	if d, ok := m["lambda_function_association"]; ok {
   376  		var associations []interface{}
   377  		switch d.(type) {
   378  		case *schema.Set:
   379  			associations = d.(*schema.Set).List()
   380  		default:
   381  			associations = d.([]interface{})
   382  		}
   383  		for _, lfa := range associations {
   384  			buf.WriteString(fmt.Sprintf("%d-", lambdaFunctionAssociationHash(lfa.(map[string]interface{}))))
   385  		}
   386  	}
   387  	return hashcode.String(buf.String())
   388  }
   389  
   390  func expandTrustedSigners(s []interface{}) *cloudfront.TrustedSigners {
   391  	var ts cloudfront.TrustedSigners
   392  	if len(s) > 0 {
   393  		ts.Quantity = aws.Int64(int64(len(s)))
   394  		ts.Items = expandStringList(s)
   395  		ts.Enabled = aws.Bool(true)
   396  	} else {
   397  		ts.Quantity = aws.Int64(0)
   398  		ts.Enabled = aws.Bool(false)
   399  	}
   400  	return &ts
   401  }
   402  
   403  func flattenTrustedSigners(ts *cloudfront.TrustedSigners) []interface{} {
   404  	if ts.Items != nil {
   405  		return flattenStringList(ts.Items)
   406  	}
   407  	return []interface{}{}
   408  }
   409  
   410  func lambdaFunctionAssociationHash(v interface{}) int {
   411  	var buf bytes.Buffer
   412  	m := v.(map[string]interface{})
   413  	buf.WriteString(fmt.Sprintf("%s-", m["event_type"].(string)))
   414  	buf.WriteString(fmt.Sprintf("%s", m["lambda_arn"].(string)))
   415  	return hashcode.String(buf.String())
   416  }
   417  
   418  func expandLambdaFunctionAssociations(v interface{}) *cloudfront.LambdaFunctionAssociations {
   419  	if v == nil {
   420  		return &cloudfront.LambdaFunctionAssociations{
   421  			Quantity: aws.Int64(0),
   422  		}
   423  	}
   424  
   425  	s := v.([]interface{})
   426  	var lfa cloudfront.LambdaFunctionAssociations
   427  	lfa.Quantity = aws.Int64(int64(len(s)))
   428  	lfa.Items = make([]*cloudfront.LambdaFunctionAssociation, len(s))
   429  	for i, lf := range s {
   430  		lfa.Items[i] = expandLambdaFunctionAssociation(lf.(map[string]interface{}))
   431  	}
   432  	return &lfa
   433  }
   434  
   435  func expandLambdaFunctionAssociation(lf map[string]interface{}) *cloudfront.LambdaFunctionAssociation {
   436  	var lfa cloudfront.LambdaFunctionAssociation
   437  	if v, ok := lf["event_type"]; ok {
   438  		lfa.EventType = aws.String(v.(string))
   439  	}
   440  	if v, ok := lf["lambda_arn"]; ok {
   441  		lfa.LambdaFunctionARN = aws.String(v.(string))
   442  	}
   443  	return &lfa
   444  }
   445  
   446  func flattenLambdaFunctionAssociations(lfa *cloudfront.LambdaFunctionAssociations) []interface{} {
   447  	s := make([]interface{}, len(lfa.Items))
   448  	for i, v := range lfa.Items {
   449  		s[i] = flattenLambdaFunctionAssociation(v)
   450  	}
   451  	return s
   452  }
   453  
   454  func flattenLambdaFunctionAssociation(lfa *cloudfront.LambdaFunctionAssociation) map[string]interface{} {
   455  	m := map[string]interface{}{}
   456  	if lfa != nil {
   457  		m["event_type"] = *lfa.EventType
   458  		m["lambda_arn"] = *lfa.LambdaFunctionARN
   459  	}
   460  	return m
   461  }
   462  
   463  func expandForwardedValues(m map[string]interface{}) *cloudfront.ForwardedValues {
   464  	fv := &cloudfront.ForwardedValues{
   465  		QueryString: aws.Bool(m["query_string"].(bool)),
   466  	}
   467  	if v, ok := m["cookies"]; ok && v.(*schema.Set).Len() > 0 {
   468  		fv.Cookies = expandCookiePreference(v.(*schema.Set).List()[0].(map[string]interface{}))
   469  	}
   470  	if v, ok := m["headers"]; ok {
   471  		fv.Headers = expandHeaders(v.([]interface{}))
   472  	}
   473  	if v, ok := m["query_string_cache_keys"]; ok {
   474  		fv.QueryStringCacheKeys = expandQueryStringCacheKeys(v.([]interface{}))
   475  	}
   476  	return fv
   477  }
   478  
   479  func flattenForwardedValues(fv *cloudfront.ForwardedValues) map[string]interface{} {
   480  	m := make(map[string]interface{})
   481  	m["query_string"] = *fv.QueryString
   482  	if fv.Cookies != nil {
   483  		m["cookies"] = schema.NewSet(cookiePreferenceHash, []interface{}{flattenCookiePreference(fv.Cookies)})
   484  	}
   485  	if fv.Headers != nil {
   486  		m["headers"] = flattenHeaders(fv.Headers)
   487  	}
   488  	if fv.QueryStringCacheKeys != nil {
   489  		m["query_string_cache_keys"] = flattenQueryStringCacheKeys(fv.QueryStringCacheKeys)
   490  	}
   491  	return m
   492  }
   493  
   494  // Assemble the hash for the aws_cloudfront_distribution forwarded_values
   495  // TypeSet attribute.
   496  func forwardedValuesHash(v interface{}) int {
   497  	var buf bytes.Buffer
   498  	m := v.(map[string]interface{})
   499  	buf.WriteString(fmt.Sprintf("%t-", m["query_string"].(bool)))
   500  	if d, ok := m["cookies"]; ok && d.(*schema.Set).Len() > 0 {
   501  		buf.WriteString(fmt.Sprintf("%d-", cookiePreferenceHash(d.(*schema.Set).List()[0].(map[string]interface{}))))
   502  	}
   503  	if d, ok := m["headers"]; ok {
   504  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   505  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   506  		}
   507  	}
   508  	if d, ok := m["query_string_cache_keys"]; ok {
   509  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   510  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   511  		}
   512  	}
   513  	return hashcode.String(buf.String())
   514  }
   515  
   516  func expandHeaders(d []interface{}) *cloudfront.Headers {
   517  	return &cloudfront.Headers{
   518  		Quantity: aws.Int64(int64(len(d))),
   519  		Items:    expandStringList(d),
   520  	}
   521  }
   522  
   523  func flattenHeaders(h *cloudfront.Headers) []interface{} {
   524  	if h.Items != nil {
   525  		return flattenStringList(h.Items)
   526  	}
   527  	return []interface{}{}
   528  }
   529  
   530  func expandQueryStringCacheKeys(d []interface{}) *cloudfront.QueryStringCacheKeys {
   531  	return &cloudfront.QueryStringCacheKeys{
   532  		Quantity: aws.Int64(int64(len(d))),
   533  		Items:    expandStringList(d),
   534  	}
   535  }
   536  
   537  func flattenQueryStringCacheKeys(k *cloudfront.QueryStringCacheKeys) []interface{} {
   538  	if k.Items != nil {
   539  		return flattenStringList(k.Items)
   540  	}
   541  	return []interface{}{}
   542  }
   543  
   544  func expandCookiePreference(m map[string]interface{}) *cloudfront.CookiePreference {
   545  	cp := &cloudfront.CookiePreference{
   546  		Forward: aws.String(m["forward"].(string)),
   547  	}
   548  	if v, ok := m["whitelisted_names"]; ok {
   549  		cp.WhitelistedNames = expandCookieNames(v.([]interface{}))
   550  	}
   551  	return cp
   552  }
   553  
   554  func flattenCookiePreference(cp *cloudfront.CookiePreference) map[string]interface{} {
   555  	m := make(map[string]interface{})
   556  	m["forward"] = *cp.Forward
   557  	if cp.WhitelistedNames != nil {
   558  		m["whitelisted_names"] = flattenCookieNames(cp.WhitelistedNames)
   559  	}
   560  	return m
   561  }
   562  
   563  // Assemble the hash for the aws_cloudfront_distribution cookies
   564  // TypeSet attribute.
   565  func cookiePreferenceHash(v interface{}) int {
   566  	var buf bytes.Buffer
   567  	m := v.(map[string]interface{})
   568  	buf.WriteString(fmt.Sprintf("%s-", m["forward"].(string)))
   569  	if d, ok := m["whitelisted_names"]; ok {
   570  		for _, e := range sortInterfaceSlice(d.([]interface{})) {
   571  			buf.WriteString(fmt.Sprintf("%s-", e.(string)))
   572  		}
   573  	}
   574  	return hashcode.String(buf.String())
   575  }
   576  
   577  func expandCookieNames(d []interface{}) *cloudfront.CookieNames {
   578  	return &cloudfront.CookieNames{
   579  		Quantity: aws.Int64(int64(len(d))),
   580  		Items:    expandStringList(d),
   581  	}
   582  }
   583  
   584  func flattenCookieNames(cn *cloudfront.CookieNames) []interface{} {
   585  	if cn.Items != nil {
   586  		return flattenStringList(cn.Items)
   587  	}
   588  	return []interface{}{}
   589  }
   590  
   591  func expandAllowedMethods(s []interface{}) *cloudfront.AllowedMethods {
   592  	return &cloudfront.AllowedMethods{
   593  		Quantity: aws.Int64(int64(len(s))),
   594  		Items:    expandStringList(s),
   595  	}
   596  }
   597  
   598  func flattenAllowedMethods(am *cloudfront.AllowedMethods) []interface{} {
   599  	if am.Items != nil {
   600  		return flattenStringList(am.Items)
   601  	}
   602  	return []interface{}{}
   603  }
   604  
   605  func expandCachedMethods(s []interface{}) *cloudfront.CachedMethods {
   606  	return &cloudfront.CachedMethods{
   607  		Quantity: aws.Int64(int64(len(s))),
   608  		Items:    expandStringList(s),
   609  	}
   610  }
   611  
   612  func flattenCachedMethods(cm *cloudfront.CachedMethods) []interface{} {
   613  	if cm.Items != nil {
   614  		return flattenStringList(cm.Items)
   615  	}
   616  	return []interface{}{}
   617  }
   618  
   619  func expandOrigins(s *schema.Set) *cloudfront.Origins {
   620  	qty := 0
   621  	items := []*cloudfront.Origin{}
   622  	for _, v := range s.List() {
   623  		items = append(items, expandOrigin(v.(map[string]interface{})))
   624  		qty++
   625  	}
   626  	return &cloudfront.Origins{
   627  		Quantity: aws.Int64(int64(qty)),
   628  		Items:    items,
   629  	}
   630  }
   631  
   632  func flattenOrigins(ors *cloudfront.Origins) *schema.Set {
   633  	s := []interface{}{}
   634  	for _, v := range ors.Items {
   635  		s = append(s, flattenOrigin(v))
   636  	}
   637  	return schema.NewSet(originHash, s)
   638  }
   639  
   640  func expandOrigin(m map[string]interface{}) *cloudfront.Origin {
   641  	origin := &cloudfront.Origin{
   642  		Id:         aws.String(m["origin_id"].(string)),
   643  		DomainName: aws.String(m["domain_name"].(string)),
   644  	}
   645  	if v, ok := m["custom_header"]; ok {
   646  		origin.CustomHeaders = expandCustomHeaders(v.(*schema.Set))
   647  	}
   648  	if v, ok := m["custom_origin_config"]; ok {
   649  		if s := v.(*schema.Set).List(); len(s) > 0 {
   650  			origin.CustomOriginConfig = expandCustomOriginConfig(s[0].(map[string]interface{}))
   651  		}
   652  	}
   653  	if v, ok := m["origin_path"]; ok {
   654  		origin.OriginPath = aws.String(v.(string))
   655  	}
   656  	if v, ok := m["s3_origin_config"]; ok {
   657  		if s := v.(*schema.Set).List(); len(s) > 0 {
   658  			origin.S3OriginConfig = expandS3OriginConfig(s[0].(map[string]interface{}))
   659  		}
   660  	}
   661  
   662  	// if both custom and s3 origin are missing, add an empty s3 origin
   663  	// One or the other must be specified, but the S3 origin can be "empty"
   664  	if origin.S3OriginConfig == nil && origin.CustomOriginConfig == nil {
   665  		origin.S3OriginConfig = &cloudfront.S3OriginConfig{
   666  			OriginAccessIdentity: aws.String(""),
   667  		}
   668  	}
   669  
   670  	return origin
   671  }
   672  
   673  func flattenOrigin(or *cloudfront.Origin) map[string]interface{} {
   674  	m := make(map[string]interface{})
   675  	m["origin_id"] = *or.Id
   676  	m["domain_name"] = *or.DomainName
   677  	if or.CustomHeaders != nil {
   678  		m["custom_header"] = flattenCustomHeaders(or.CustomHeaders)
   679  	}
   680  	if or.CustomOriginConfig != nil {
   681  		m["custom_origin_config"] = schema.NewSet(customOriginConfigHash, []interface{}{flattenCustomOriginConfig(or.CustomOriginConfig)})
   682  	}
   683  	if or.OriginPath != nil {
   684  		m["origin_path"] = *or.OriginPath
   685  	}
   686  	if or.S3OriginConfig != nil {
   687  		if or.S3OriginConfig.OriginAccessIdentity != nil && *or.S3OriginConfig.OriginAccessIdentity != "" {
   688  			m["s3_origin_config"] = schema.NewSet(s3OriginConfigHash, []interface{}{flattenS3OriginConfig(or.S3OriginConfig)})
   689  		}
   690  	}
   691  	return m
   692  }
   693  
   694  // Assemble the hash for the aws_cloudfront_distribution origin
   695  // TypeSet attribute.
   696  func originHash(v interface{}) int {
   697  	var buf bytes.Buffer
   698  	m := v.(map[string]interface{})
   699  	buf.WriteString(fmt.Sprintf("%s-", m["origin_id"].(string)))
   700  	buf.WriteString(fmt.Sprintf("%s-", m["domain_name"].(string)))
   701  	if v, ok := m["custom_header"]; ok {
   702  		buf.WriteString(fmt.Sprintf("%d-", customHeadersHash(v.(*schema.Set))))
   703  	}
   704  	if v, ok := m["custom_origin_config"]; ok {
   705  		if s := v.(*schema.Set).List(); len(s) > 0 {
   706  			buf.WriteString(fmt.Sprintf("%d-", customOriginConfigHash((s[0].(map[string]interface{})))))
   707  		}
   708  	}
   709  	if v, ok := m["origin_path"]; ok {
   710  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   711  	}
   712  	if v, ok := m["s3_origin_config"]; ok {
   713  		if s := v.(*schema.Set).List(); len(s) > 0 {
   714  			buf.WriteString(fmt.Sprintf("%d-", s3OriginConfigHash((s[0].(map[string]interface{})))))
   715  		}
   716  	}
   717  	return hashcode.String(buf.String())
   718  }
   719  
   720  func expandCustomHeaders(s *schema.Set) *cloudfront.CustomHeaders {
   721  	qty := 0
   722  	items := []*cloudfront.OriginCustomHeader{}
   723  	for _, v := range s.List() {
   724  		items = append(items, expandOriginCustomHeader(v.(map[string]interface{})))
   725  		qty++
   726  	}
   727  	return &cloudfront.CustomHeaders{
   728  		Quantity: aws.Int64(int64(qty)),
   729  		Items:    items,
   730  	}
   731  }
   732  
   733  func flattenCustomHeaders(chs *cloudfront.CustomHeaders) *schema.Set {
   734  	s := []interface{}{}
   735  	for _, v := range chs.Items {
   736  		s = append(s, flattenOriginCustomHeader(v))
   737  	}
   738  	return schema.NewSet(originCustomHeaderHash, s)
   739  }
   740  
   741  func expandOriginCustomHeader(m map[string]interface{}) *cloudfront.OriginCustomHeader {
   742  	return &cloudfront.OriginCustomHeader{
   743  		HeaderName:  aws.String(m["name"].(string)),
   744  		HeaderValue: aws.String(m["value"].(string)),
   745  	}
   746  }
   747  
   748  func flattenOriginCustomHeader(och *cloudfront.OriginCustomHeader) map[string]interface{} {
   749  	return map[string]interface{}{
   750  		"name":  *och.HeaderName,
   751  		"value": *och.HeaderValue,
   752  	}
   753  }
   754  
   755  // Helper function used by originHash to get a composite hash for all
   756  // aws_cloudfront_distribution custom_header attributes.
   757  func customHeadersHash(s *schema.Set) int {
   758  	var buf bytes.Buffer
   759  	for _, v := range s.List() {
   760  		buf.WriteString(fmt.Sprintf("%d-", originCustomHeaderHash(v)))
   761  	}
   762  	return hashcode.String(buf.String())
   763  }
   764  
   765  // Assemble the hash for the aws_cloudfront_distribution custom_header
   766  // TypeSet attribute.
   767  func originCustomHeaderHash(v interface{}) int {
   768  	var buf bytes.Buffer
   769  	m := v.(map[string]interface{})
   770  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   771  	buf.WriteString(fmt.Sprintf("%s-", m["value"].(string)))
   772  	return hashcode.String(buf.String())
   773  }
   774  
   775  func expandCustomOriginConfig(m map[string]interface{}) *cloudfront.CustomOriginConfig {
   776  	return &cloudfront.CustomOriginConfig{
   777  		OriginProtocolPolicy: aws.String(m["origin_protocol_policy"].(string)),
   778  		HTTPPort:             aws.Int64(int64(m["http_port"].(int))),
   779  		HTTPSPort:            aws.Int64(int64(m["https_port"].(int))),
   780  		OriginSslProtocols:   expandCustomOriginConfigSSL(m["origin_ssl_protocols"].([]interface{})),
   781  	}
   782  }
   783  
   784  func flattenCustomOriginConfig(cor *cloudfront.CustomOriginConfig) map[string]interface{} {
   785  	return map[string]interface{}{
   786  		"origin_protocol_policy": *cor.OriginProtocolPolicy,
   787  		"http_port":              int(*cor.HTTPPort),
   788  		"https_port":             int(*cor.HTTPSPort),
   789  		"origin_ssl_protocols":   flattenCustomOriginConfigSSL(cor.OriginSslProtocols),
   790  	}
   791  }
   792  
   793  // Assemble the hash for the aws_cloudfront_distribution custom_origin_config
   794  // TypeSet attribute.
   795  func customOriginConfigHash(v interface{}) int {
   796  	var buf bytes.Buffer
   797  	m := v.(map[string]interface{})
   798  	buf.WriteString(fmt.Sprintf("%s-", m["origin_protocol_policy"].(string)))
   799  	buf.WriteString(fmt.Sprintf("%d-", m["http_port"].(int)))
   800  	buf.WriteString(fmt.Sprintf("%d-", m["https_port"].(int)))
   801  	for _, v := range sortInterfaceSlice(m["origin_ssl_protocols"].([]interface{})) {
   802  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   803  	}
   804  	return hashcode.String(buf.String())
   805  }
   806  
   807  func expandCustomOriginConfigSSL(s []interface{}) *cloudfront.OriginSslProtocols {
   808  	items := expandStringList(s)
   809  	return &cloudfront.OriginSslProtocols{
   810  		Quantity: aws.Int64(int64(len(items))),
   811  		Items:    items,
   812  	}
   813  }
   814  
   815  func flattenCustomOriginConfigSSL(osp *cloudfront.OriginSslProtocols) []interface{} {
   816  	return flattenStringList(osp.Items)
   817  }
   818  
   819  func expandS3OriginConfig(m map[string]interface{}) *cloudfront.S3OriginConfig {
   820  	return &cloudfront.S3OriginConfig{
   821  		OriginAccessIdentity: aws.String(m["origin_access_identity"].(string)),
   822  	}
   823  }
   824  
   825  func flattenS3OriginConfig(s3o *cloudfront.S3OriginConfig) map[string]interface{} {
   826  	return map[string]interface{}{
   827  		"origin_access_identity": *s3o.OriginAccessIdentity,
   828  	}
   829  }
   830  
   831  // Assemble the hash for the aws_cloudfront_distribution s3_origin_config
   832  // TypeSet attribute.
   833  func s3OriginConfigHash(v interface{}) int {
   834  	var buf bytes.Buffer
   835  	m := v.(map[string]interface{})
   836  	buf.WriteString(fmt.Sprintf("%s-", m["origin_access_identity"].(string)))
   837  	return hashcode.String(buf.String())
   838  }
   839  
   840  func expandCustomErrorResponses(s *schema.Set) *cloudfront.CustomErrorResponses {
   841  	qty := 0
   842  	items := []*cloudfront.CustomErrorResponse{}
   843  	for _, v := range s.List() {
   844  		items = append(items, expandCustomErrorResponse(v.(map[string]interface{})))
   845  		qty++
   846  	}
   847  	return &cloudfront.CustomErrorResponses{
   848  		Quantity: aws.Int64(int64(qty)),
   849  		Items:    items,
   850  	}
   851  }
   852  
   853  func flattenCustomErrorResponses(ers *cloudfront.CustomErrorResponses) *schema.Set {
   854  	s := []interface{}{}
   855  	for _, v := range ers.Items {
   856  		s = append(s, flattenCustomErrorResponse(v))
   857  	}
   858  	return schema.NewSet(customErrorResponseHash, s)
   859  }
   860  
   861  func expandCustomErrorResponse(m map[string]interface{}) *cloudfront.CustomErrorResponse {
   862  	er := cloudfront.CustomErrorResponse{
   863  		ErrorCode: aws.Int64(int64(m["error_code"].(int))),
   864  	}
   865  	if v, ok := m["error_caching_min_ttl"]; ok {
   866  		er.ErrorCachingMinTTL = aws.Int64(int64(v.(int)))
   867  	}
   868  	if v, ok := m["response_code"]; ok && v.(int) != 0 {
   869  		er.ResponseCode = aws.String(strconv.Itoa(v.(int)))
   870  	} else {
   871  		er.ResponseCode = aws.String("")
   872  	}
   873  	if v, ok := m["response_page_path"]; ok {
   874  		er.ResponsePagePath = aws.String(v.(string))
   875  	}
   876  
   877  	return &er
   878  }
   879  
   880  func flattenCustomErrorResponse(er *cloudfront.CustomErrorResponse) map[string]interface{} {
   881  	m := make(map[string]interface{})
   882  	m["error_code"] = int(*er.ErrorCode)
   883  	if er.ErrorCachingMinTTL != nil {
   884  		m["error_caching_min_ttl"] = int(*er.ErrorCachingMinTTL)
   885  	}
   886  	if er.ResponseCode != nil {
   887  		m["response_code"], _ = strconv.Atoi(*er.ResponseCode)
   888  	}
   889  	if er.ResponsePagePath != nil {
   890  		m["response_page_path"] = *er.ResponsePagePath
   891  	}
   892  	return m
   893  }
   894  
   895  // Assemble the hash for the aws_cloudfront_distribution custom_error_response
   896  // TypeSet attribute.
   897  func customErrorResponseHash(v interface{}) int {
   898  	var buf bytes.Buffer
   899  	m := v.(map[string]interface{})
   900  	buf.WriteString(fmt.Sprintf("%d-", m["error_code"].(int)))
   901  	if v, ok := m["error_caching_min_ttl"]; ok {
   902  		buf.WriteString(fmt.Sprintf("%d-", v.(int)))
   903  	}
   904  	if v, ok := m["response_code"]; ok {
   905  		buf.WriteString(fmt.Sprintf("%d-", v.(int)))
   906  	}
   907  	if v, ok := m["response_page_path"]; ok {
   908  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   909  	}
   910  	return hashcode.String(buf.String())
   911  }
   912  
   913  func expandLoggingConfig(m map[string]interface{}) *cloudfront.LoggingConfig {
   914  	var lc cloudfront.LoggingConfig
   915  	if m != nil {
   916  		lc.Prefix = aws.String(m["prefix"].(string))
   917  		lc.Bucket = aws.String(m["bucket"].(string))
   918  		lc.IncludeCookies = aws.Bool(m["include_cookies"].(bool))
   919  		lc.Enabled = aws.Bool(true)
   920  	} else {
   921  		lc.Prefix = aws.String("")
   922  		lc.Bucket = aws.String("")
   923  		lc.IncludeCookies = aws.Bool(false)
   924  		lc.Enabled = aws.Bool(false)
   925  	}
   926  	return &lc
   927  }
   928  
   929  func flattenLoggingConfig(lc *cloudfront.LoggingConfig) *schema.Set {
   930  	m := make(map[string]interface{})
   931  	m["prefix"] = *lc.Prefix
   932  	m["bucket"] = *lc.Bucket
   933  	m["include_cookies"] = *lc.IncludeCookies
   934  	return schema.NewSet(loggingConfigHash, []interface{}{m})
   935  }
   936  
   937  // Assemble the hash for the aws_cloudfront_distribution logging_config
   938  // TypeSet attribute.
   939  func loggingConfigHash(v interface{}) int {
   940  	var buf bytes.Buffer
   941  	m := v.(map[string]interface{})
   942  	buf.WriteString(fmt.Sprintf("%s-", m["prefix"].(string)))
   943  	buf.WriteString(fmt.Sprintf("%s-", m["bucket"].(string)))
   944  	buf.WriteString(fmt.Sprintf("%t-", m["include_cookies"].(bool)))
   945  	return hashcode.String(buf.String())
   946  }
   947  
   948  func expandAliases(as *schema.Set) *cloudfront.Aliases {
   949  	s := as.List()
   950  	var aliases cloudfront.Aliases
   951  	if len(s) > 0 {
   952  		aliases.Quantity = aws.Int64(int64(len(s)))
   953  		aliases.Items = expandStringList(s)
   954  	} else {
   955  		aliases.Quantity = aws.Int64(0)
   956  	}
   957  	return &aliases
   958  }
   959  
   960  func flattenAliases(aliases *cloudfront.Aliases) *schema.Set {
   961  	if aliases.Items != nil {
   962  		return schema.NewSet(aliasesHash, flattenStringList(aliases.Items))
   963  	}
   964  	return schema.NewSet(aliasesHash, []interface{}{})
   965  }
   966  
   967  // Assemble the hash for the aws_cloudfront_distribution aliases
   968  // TypeSet attribute.
   969  func aliasesHash(v interface{}) int {
   970  	return hashcode.String(v.(string))
   971  }
   972  
   973  func expandRestrictions(m map[string]interface{}) *cloudfront.Restrictions {
   974  	return &cloudfront.Restrictions{
   975  		GeoRestriction: expandGeoRestriction(m["geo_restriction"].(*schema.Set).List()[0].(map[string]interface{})),
   976  	}
   977  }
   978  
   979  func flattenRestrictions(r *cloudfront.Restrictions) *schema.Set {
   980  	m := make(map[string]interface{})
   981  	s := schema.NewSet(geoRestrictionHash, []interface{}{flattenGeoRestriction(r.GeoRestriction)})
   982  	m["geo_restriction"] = s
   983  	return schema.NewSet(restrictionsHash, []interface{}{m})
   984  }
   985  
   986  // Assemble the hash for the aws_cloudfront_distribution restrictions
   987  // TypeSet attribute.
   988  func restrictionsHash(v interface{}) int {
   989  	var buf bytes.Buffer
   990  	m := v.(map[string]interface{})
   991  	buf.WriteString(fmt.Sprintf("%d-", geoRestrictionHash(m["geo_restriction"].(*schema.Set).List()[0].(map[string]interface{}))))
   992  	return hashcode.String(buf.String())
   993  }
   994  
   995  func expandGeoRestriction(m map[string]interface{}) *cloudfront.GeoRestriction {
   996  	gr := cloudfront.GeoRestriction{
   997  		RestrictionType: aws.String(m["restriction_type"].(string)),
   998  	}
   999  	if v, ok := m["locations"]; ok {
  1000  		gr.Quantity = aws.Int64(int64(len(v.([]interface{}))))
  1001  		gr.Items = expandStringList(v.([]interface{}))
  1002  		sort.Sort(StringPtrSlice(gr.Items))
  1003  	} else {
  1004  		gr.Quantity = aws.Int64(0)
  1005  	}
  1006  	return &gr
  1007  }
  1008  
  1009  func flattenGeoRestriction(gr *cloudfront.GeoRestriction) map[string]interface{} {
  1010  	m := make(map[string]interface{})
  1011  
  1012  	m["restriction_type"] = *gr.RestrictionType
  1013  	if gr.Items != nil {
  1014  		sort.Sort(StringPtrSlice(gr.Items))
  1015  		m["locations"] = flattenStringList(gr.Items)
  1016  	}
  1017  	return m
  1018  }
  1019  
  1020  // Assemble the hash for the aws_cloudfront_distribution geo_restriction
  1021  // TypeSet attribute.
  1022  func geoRestrictionHash(v interface{}) int {
  1023  	var buf bytes.Buffer
  1024  	m := v.(map[string]interface{})
  1025  	// All keys added in alphabetical order.
  1026  	buf.WriteString(fmt.Sprintf("%s-", m["restriction_type"].(string)))
  1027  	if v, ok := m["locations"]; ok {
  1028  		for _, w := range sortInterfaceSlice(v.([]interface{})) {
  1029  			buf.WriteString(fmt.Sprintf("%s-", w.(string)))
  1030  		}
  1031  	}
  1032  	return hashcode.String(buf.String())
  1033  }
  1034  
  1035  func expandViewerCertificate(m map[string]interface{}) *cloudfront.ViewerCertificate {
  1036  	var vc cloudfront.ViewerCertificate
  1037  	if v, ok := m["iam_certificate_id"]; ok && v != "" {
  1038  		vc.IAMCertificateId = aws.String(v.(string))
  1039  		vc.SSLSupportMethod = aws.String(m["ssl_support_method"].(string))
  1040  	} else if v, ok := m["acm_certificate_arn"]; ok && v != "" {
  1041  		vc.ACMCertificateArn = aws.String(v.(string))
  1042  		vc.SSLSupportMethod = aws.String(m["ssl_support_method"].(string))
  1043  	} else {
  1044  		vc.CloudFrontDefaultCertificate = aws.Bool(m["cloudfront_default_certificate"].(bool))
  1045  	}
  1046  	if v, ok := m["minimum_protocol_version"]; ok && v != "" {
  1047  		vc.MinimumProtocolVersion = aws.String(v.(string))
  1048  	}
  1049  	return &vc
  1050  }
  1051  
  1052  func flattenViewerCertificate(vc *cloudfront.ViewerCertificate) *schema.Set {
  1053  	m := make(map[string]interface{})
  1054  
  1055  	if vc.IAMCertificateId != nil {
  1056  		m["iam_certificate_id"] = *vc.IAMCertificateId
  1057  		m["ssl_support_method"] = *vc.SSLSupportMethod
  1058  	}
  1059  	if vc.ACMCertificateArn != nil {
  1060  		m["acm_certificate_arn"] = *vc.ACMCertificateArn
  1061  		m["ssl_support_method"] = *vc.SSLSupportMethod
  1062  	}
  1063  	if vc.CloudFrontDefaultCertificate != nil {
  1064  		m["cloudfront_default_certificate"] = *vc.CloudFrontDefaultCertificate
  1065  	}
  1066  	if vc.MinimumProtocolVersion != nil {
  1067  		m["minimum_protocol_version"] = *vc.MinimumProtocolVersion
  1068  	}
  1069  	return schema.NewSet(viewerCertificateHash, []interface{}{m})
  1070  }
  1071  
  1072  // Assemble the hash for the aws_cloudfront_distribution viewer_certificate
  1073  // TypeSet attribute.
  1074  func viewerCertificateHash(v interface{}) int {
  1075  	var buf bytes.Buffer
  1076  	m := v.(map[string]interface{})
  1077  	if v, ok := m["iam_certificate_id"]; ok && v.(string) != "" {
  1078  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1079  		buf.WriteString(fmt.Sprintf("%s-", m["ssl_support_method"].(string)))
  1080  	} else if v, ok := m["acm_certificate_arn"]; ok && v.(string) != "" {
  1081  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1082  		buf.WriteString(fmt.Sprintf("%s-", m["ssl_support_method"].(string)))
  1083  	} else {
  1084  		buf.WriteString(fmt.Sprintf("%t-", m["cloudfront_default_certificate"].(bool)))
  1085  	}
  1086  	if v, ok := m["minimum_protocol_version"]; ok && v.(string) != "" {
  1087  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1088  	}
  1089  	return hashcode.String(buf.String())
  1090  }
  1091  
  1092  // Do a top-level copy of struct fields from one struct to another. Used to
  1093  // copy fields between CacheBehavior and DefaultCacheBehavior structs.
  1094  func simpleCopyStruct(src, dst interface{}) {
  1095  	s := reflect.ValueOf(src).Elem()
  1096  	d := reflect.ValueOf(dst).Elem()
  1097  
  1098  	for i := 0; i < s.NumField(); i++ {
  1099  		if s.Field(i).CanSet() == true {
  1100  			if s.Field(i).Interface() != nil {
  1101  				for j := 0; j < d.NumField(); j++ {
  1102  					if d.Type().Field(j).Name == s.Type().Field(i).Name {
  1103  						d.Field(j).Set(s.Field(i))
  1104  					}
  1105  				}
  1106  			}
  1107  		}
  1108  	}
  1109  }
  1110  
  1111  // Convert *cloudfront.ActiveTrustedSigners to a flatmap.Map type, which ensures
  1112  // it can probably be inserted into the schema.TypeMap type used by the
  1113  // active_trusted_signers attribute.
  1114  func flattenActiveTrustedSigners(ats *cloudfront.ActiveTrustedSigners) flatmap.Map {
  1115  	m := make(map[string]interface{})
  1116  	s := []interface{}{}
  1117  	m["enabled"] = *ats.Enabled
  1118  
  1119  	for _, v := range ats.Items {
  1120  		signer := make(map[string]interface{})
  1121  		signer["aws_account_number"] = *v.AwsAccountNumber
  1122  		signer["key_pair_ids"] = aws.StringValueSlice(v.KeyPairIds.Items)
  1123  		s = append(s, signer)
  1124  	}
  1125  	m["items"] = s
  1126  	return flatmap.Flatten(m)
  1127  }