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