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