github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/cloudfront_distribution_configuration_structure.go (about)

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