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