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