From 8afddbf387a503ba0486da528a0418bd5951f52a Mon Sep 17 00:00:00 2001 From: Chris Marchesi Date: Thu, 4 Feb 2016 12:33:24 -0800 Subject: [PATCH] Refactor - new resource: aws_cloudfront_distribution * Includes a complete re-write of the old aws_cloudfront_web_distribution resource to bring it to feature parity with API and CloudFormation. * Also includes the aws_cloudfront_origin_access_identity resource to generate origin access identities for use with S3. --- ...nt_distribution_configuration_structure.go | 935 +++++++++++++++++ ...stribution_configuration_structure_test.go | 944 ++++++++++++++++++ builtin/providers/aws/provider.go | 235 ++--- .../resource_aws_cloudfront_distribution.go | 578 +++++++++++ ...source_aws_cloudfront_distribution_test.go | 392 ++++++++ ...e_aws_cloudfront_origin_access_identity.go | 128 +++ ..._cloudfront_origin_access_identity_test.go | 89 ++ ...esource_aws_cloudfront_web_distribution.go | 587 ----------- ...ce_aws_cloudfront_web_distribution_test.go | 124 --- builtin/providers/aws/structure.go | 20 + .../r/cloudfront_distribution.html.markdown | 195 ++++ ...front_origin_access_identity.html.markdown | 58 ++ .../cloudfront_web_distribution.html.markdown | 64 -- website/source/layouts/aws.erb | 7 +- 14 files changed, 3462 insertions(+), 894 deletions(-) create mode 100644 builtin/providers/aws/cloudfront_distribution_configuration_structure.go create mode 100644 builtin/providers/aws/cloudfront_distribution_configuration_structure_test.go create mode 100644 builtin/providers/aws/resource_aws_cloudfront_distribution.go create mode 100644 builtin/providers/aws/resource_aws_cloudfront_distribution_test.go create mode 100644 builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go create mode 100644 builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go delete mode 100644 builtin/providers/aws/resource_aws_cloudfront_web_distribution.go delete mode 100644 builtin/providers/aws/resource_aws_cloudfront_web_distribution_test.go create mode 100644 website/source/docs/providers/aws/r/cloudfront_distribution.html.markdown create mode 100644 website/source/docs/providers/aws/r/cloudfront_origin_access_identity.html.markdown delete mode 100644 website/source/docs/providers/aws/r/cloudfront_web_distribution.html.markdown diff --git a/builtin/providers/aws/cloudfront_distribution_configuration_structure.go b/builtin/providers/aws/cloudfront_distribution_configuration_structure.go new file mode 100644 index 000000000000..37a628f9f96a --- /dev/null +++ b/builtin/providers/aws/cloudfront_distribution_configuration_structure.go @@ -0,0 +1,935 @@ +// CloudFront DistributionConfig structure helpers. +// +// These functions assist in pulling in data from Terraform resource +// configuration for the aws_cloudfront_distribution resource, as there are +// several sub-fields that require their own data type, and do not necessarily +// 1-1 translate to resource configuration. + +package aws + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform/flatmap" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" +) + +// Assemble the *cloudfront.DistributionConfig variable. Calls out to various +// expander functions to convert attributes and sub-attributes to the various +// complex structures which are necessary to properly build the +// DistributionConfig structure. +// +// Used by the aws_cloudfront_distribution Create and Update functions. +func expandDistributionConfig(d *schema.ResourceData) *cloudfront.DistributionConfig { + distributionConfig := &cloudfront.DistributionConfig{ + CacheBehaviors: expandCacheBehaviors(d.Get("cache_behavior").(*schema.Set)), + CustomErrorResponses: expandCustomErrorResponses(d.Get("custom_error_response").(*schema.Set)), + DefaultCacheBehavior: expandDefaultCacheBehavior(d.Get("default_cache_behavior").(*schema.Set).List()[0].(map[string]interface{})), + Enabled: aws.Bool(d.Get("enabled").(bool)), + Origins: expandOrigins(d.Get("origin").(*schema.Set)), + } + // This sets CallerReference if it's still pending computation (ie: new resource) + if v, ok := d.GetOk("caller_reference"); ok == false { + distributionConfig.CallerReference = aws.String(time.Now().Format(time.RFC3339Nano)) + } else { + distributionConfig.CallerReference = aws.String(v.(string)) + } + if v, ok := d.GetOk("comment"); ok { + distributionConfig.Comment = aws.String(v.(string)) + } else { + distributionConfig.Comment = aws.String("") + } + if v, ok := d.GetOk("default_root_object"); ok { + distributionConfig.DefaultRootObject = aws.String(v.(string)) + } + if v, ok := d.GetOk("logging_config"); ok { + distributionConfig.Logging = expandLoggingConfig(v.(*schema.Set).List()[0].(map[string]interface{})) + } else { + distributionConfig.Logging = expandLoggingConfig(nil) + } + if v, ok := d.GetOk("aliases"); ok { + distributionConfig.Aliases = expandAliases(v.(*schema.Set)) + } + if v, ok := d.GetOk("price_class"); ok { + distributionConfig.PriceClass = aws.String(v.(string)) + } + if v, ok := d.GetOk("restrictions"); ok { + distributionConfig.Restrictions = expandRestrictions(v.(*schema.Set).List()[0].(map[string]interface{})) + } + if v, ok := d.GetOk("viewer_certificate"); ok { + distributionConfig.ViewerCertificate = expandViewerCertificate(v.(*schema.Set).List()[0].(map[string]interface{})) + } + if v, ok := d.GetOk("web_acl_id"); ok { + distributionConfig.WebACLId = aws.String(v.(string)) + } else { + distributionConfig.WebACLId = aws.String("") + } + return distributionConfig +} + +// Unpack the *cloudfront.DistributionConfig variable and set resource data. +// Calls out to flatten functions to convert the DistributionConfig +// sub-structures to their respective attributes in the +// aws_cloudfront_distribution resource. +// +// Used by the aws_cloudfront_distribution Read function. +func flattenDistributionConfig(d *schema.ResourceData, distributionConfig *cloudfront.DistributionConfig) { + d.Set("origins", flattenOrigins(distributionConfig.Origins)) + d.Set("enabled", *distributionConfig.Enabled) + d.Set("default_cache_behavior", flattenDefaultCacheBehavior(distributionConfig.DefaultCacheBehavior)) + + if distributionConfig.CallerReference != nil { + d.Set("caller_reference", *distributionConfig.CallerReference) + } + if distributionConfig.Comment != nil { + if *distributionConfig.Comment != "" { + d.Set("comment", *distributionConfig.Comment) + } + } + if distributionConfig.DefaultRootObject != nil { + d.Set("default_root_object", *distributionConfig.DefaultRootObject) + } + if distributionConfig.CustomErrorResponses != nil { + d.Set("custom_error_response", flattenCustomErrorResponses(distributionConfig.CustomErrorResponses)) + } + if distributionConfig.CacheBehaviors != nil { + d.Set("cache_behavior", flattenCacheBehaviors(distributionConfig.CacheBehaviors)) + } + if distributionConfig.Logging != nil && *distributionConfig.Logging.Enabled { + d.Set("logging_config", flattenLoggingConfig(distributionConfig.Logging)) + } + if distributionConfig.Aliases != nil { + d.Set("aliases", flattenAliases(distributionConfig.Aliases)) + } + if distributionConfig.PriceClass != nil { + d.Set("price_class", *distributionConfig.PriceClass) + } + if distributionConfig.Restrictions != nil { + d.Set("restrictions", flattenRestrictions(distributionConfig.Restrictions)) + } + if distributionConfig.ViewerCertificate != nil { + d.Set("viewer_certificate", flattenViewerCertificate(distributionConfig.ViewerCertificate)) + } + if distributionConfig.WebACLId != nil { + d.Set("web_acl_id", *distributionConfig.WebACLId) + } +} + +func expandDefaultCacheBehavior(m map[string]interface{}) *cloudfront.DefaultCacheBehavior { + cb := expandCacheBehavior(m) + var dcb cloudfront.DefaultCacheBehavior + + simpleCopyStruct(cb, &dcb) + return &dcb +} + +func flattenDefaultCacheBehavior(dcb *cloudfront.DefaultCacheBehavior) *schema.Set { + m := make(map[string]interface{}) + var cb cloudfront.CacheBehavior + + simpleCopyStruct(dcb, &cb) + m = flattenCacheBehavior(&cb) + return schema.NewSet(defaultCacheBehaviorHash, []interface{}{m}) +} + +// Assemble the hash for the aws_cloudfront_distribution default_cache_behavior +// TypeSet attribute. +func defaultCacheBehaviorHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%t-", m["compress"].(bool))) + buf.WriteString(fmt.Sprintf("%s-", m["viewer_protocol_policy"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["target_origin_id"].(string))) + buf.WriteString(fmt.Sprintf("%d-", forwardedValuesHash(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{})))) + buf.WriteString(fmt.Sprintf("%d-", m["min_ttl"].(int))) + if d, ok := m["trusted_signers"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + if d, ok := m["max_ttl"]; ok { + buf.WriteString(fmt.Sprintf("%d-", d.(int))) + } + if d, ok := m["smooth_streaming"]; ok { + buf.WriteString(fmt.Sprintf("%t-", d.(bool))) + } + if d, ok := m["default_ttl"]; ok { + buf.WriteString(fmt.Sprintf("%d-", d.(int))) + } + if d, ok := m["allowed_methods"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + if d, ok := m["cached_methods"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + return hashcode.String(buf.String()) +} + +func expandCacheBehaviors(s *schema.Set) *cloudfront.CacheBehaviors { + var qty int64 + var items []*cloudfront.CacheBehavior + for _, v := range s.List() { + items = append(items, expandCacheBehavior(v.(map[string]interface{}))) + qty++ + } + return &cloudfront.CacheBehaviors{ + Quantity: aws.Int64(qty), + Items: items, + } +} + +func flattenCacheBehaviors(cbs *cloudfront.CacheBehaviors) *schema.Set { + s := []interface{}{} + for _, v := range cbs.Items { + s = append(s, flattenCacheBehavior(v)) + } + return schema.NewSet(cacheBehaviorHash, s) +} + +func expandCacheBehavior(m map[string]interface{}) *cloudfront.CacheBehavior { + cb := &cloudfront.CacheBehavior{ + Compress: aws.Bool(m["compress"].(bool)), + ViewerProtocolPolicy: aws.String(m["viewer_protocol_policy"].(string)), + TargetOriginId: aws.String(m["target_origin_id"].(string)), + ForwardedValues: expandForwardedValues(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{})), + MinTTL: aws.Int64(int64(m["min_ttl"].(int))), + MaxTTL: aws.Int64(int64(m["max_ttl"].(int))), + DefaultTTL: aws.Int64(int64(m["default_ttl"].(int))), + } + if v, ok := m["trusted_signers"]; ok { + cb.TrustedSigners = expandTrustedSigners(v.([]interface{})) + } else { + cb.TrustedSigners = expandTrustedSigners([]interface{}{}) + } + if v, ok := m["smooth_streaming"]; ok { + cb.SmoothStreaming = aws.Bool(v.(bool)) + } + if v, ok := m["allowed_methods"]; ok { + cb.AllowedMethods = expandAllowedMethods(v.([]interface{})) + } + if v, ok := m["cached_methods"]; ok { + cb.AllowedMethods.CachedMethods = expandCachedMethods(v.([]interface{})) + } + if v, ok := m["path_pattern"]; ok { + cb.PathPattern = aws.String(v.(string)) + } + return cb +} + +func flattenCacheBehavior(cb *cloudfront.CacheBehavior) map[string]interface{} { + m := make(map[string]interface{}) + + m["compress"] = *cb.Compress + m["viewer_protocol_policy"] = *cb.ViewerProtocolPolicy + m["target_origin_id"] = *cb.TargetOriginId + m["forwarded_values"] = schema.NewSet(forwardedValuesHash, []interface{}{flattenForwardedValues(cb.ForwardedValues)}) + m["min_ttl"] = int(*cb.MinTTL) + + if len(cb.TrustedSigners.Items) > 0 { + m["trusted_signers"] = flattenTrustedSigners(cb.TrustedSigners) + } + if cb.MaxTTL != nil { + m["max_ttl"] = int(*cb.MaxTTL) + } + if cb.SmoothStreaming != nil { + m["smooth_streaming"] = *cb.SmoothStreaming + } + if cb.DefaultTTL != nil { + m["default_ttl"] = int(*cb.DefaultTTL) + } + if cb.AllowedMethods != nil { + m["allowed_methods"] = flattenAllowedMethods(cb.AllowedMethods) + } + if cb.AllowedMethods.CachedMethods != nil { + m["cached_methods"] = flattenCachedMethods(cb.AllowedMethods.CachedMethods) + } + if cb.PathPattern != nil { + m["path_pattern"] = *cb.PathPattern + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution cache_behavior +// TypeSet attribute. +func cacheBehaviorHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%t-", m["compress"].(bool))) + buf.WriteString(fmt.Sprintf("%s-", m["viewer_protocol_policy"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["target_origin_id"].(string))) + buf.WriteString(fmt.Sprintf("%d-", forwardedValuesHash(m["forwarded_values"].(*schema.Set).List()[0].(map[string]interface{})))) + buf.WriteString(fmt.Sprintf("%d-", m["min_ttl"].(int))) + if d, ok := m["trusted_signers"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + if d, ok := m["max_ttl"]; ok { + buf.WriteString(fmt.Sprintf("%d-", d.(int))) + } + if d, ok := m["smooth_streaming"]; ok { + buf.WriteString(fmt.Sprintf("%t-", d.(bool))) + } + if d, ok := m["default_ttl"]; ok { + buf.WriteString(fmt.Sprintf("%d-", d.(int))) + } + if d, ok := m["allowed_methods"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + if d, ok := m["cached_methods"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + if d, ok := m["path_pattern"]; ok { + buf.WriteString(fmt.Sprintf("%s-", d)) + } + return hashcode.String(buf.String()) +} + +func expandTrustedSigners(s []interface{}) *cloudfront.TrustedSigners { + var ts cloudfront.TrustedSigners + if len(s) > 0 { + ts.Quantity = aws.Int64(int64(len(s))) + ts.Items = expandStringList(s) + ts.Enabled = aws.Bool(true) + } else { + ts.Quantity = aws.Int64(0) + ts.Enabled = aws.Bool(false) + } + return &ts +} + +func flattenTrustedSigners(ts *cloudfront.TrustedSigners) []interface{} { + if ts.Items != nil { + return flattenStringList(ts.Items) + } + return []interface{}{} +} + +func expandForwardedValues(m map[string]interface{}) *cloudfront.ForwardedValues { + fv := &cloudfront.ForwardedValues{ + QueryString: aws.Bool(m["query_string"].(bool)), + } + if v, ok := m["cookies"]; ok { + fv.Cookies = expandCookiePreference(v.(*schema.Set).List()[0].(map[string]interface{})) + } + if v, ok := m["headers"]; ok { + fv.Headers = expandHeaders(v.([]interface{})) + } + return fv +} + +func flattenForwardedValues(fv *cloudfront.ForwardedValues) map[string]interface{} { + m := make(map[string]interface{}) + m["query_string"] = *fv.QueryString + if fv.Cookies != nil { + m["cookies"] = schema.NewSet(cookiePreferenceHash, []interface{}{flattenCookiePreference(fv.Cookies)}) + } + if fv.Headers != nil { + m["headers"] = flattenHeaders(fv.Headers) + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution forwarded_values +// TypeSet attribute. +func forwardedValuesHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%t-", m["query_string"].(bool))) + if d, ok := m["cookies"]; ok { + buf.WriteString(fmt.Sprintf("%d-", cookiePreferenceHash(d.(*schema.Set).List()[0].(map[string]interface{})))) + } + if d, ok := m["headers"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + return hashcode.String(buf.String()) +} + +func expandHeaders(d []interface{}) *cloudfront.Headers { + return &cloudfront.Headers{ + Quantity: aws.Int64(int64(len(d))), + Items: expandStringList(d), + } +} + +func flattenHeaders(h *cloudfront.Headers) []interface{} { + if h.Items != nil { + return flattenStringList(h.Items) + } + return []interface{}{} +} + +func expandCookiePreference(m map[string]interface{}) *cloudfront.CookiePreference { + cp := &cloudfront.CookiePreference{ + Forward: aws.String(m["forward"].(string)), + } + if v, ok := m["whitelisted_names"]; ok { + cp.WhitelistedNames = expandCookieNames(v.([]interface{})) + } + return cp +} + +func flattenCookiePreference(cp *cloudfront.CookiePreference) map[string]interface{} { + m := make(map[string]interface{}) + m["forward"] = *cp.Forward + if cp.WhitelistedNames != nil { + m["whitelisted_names"] = flattenCookieNames(cp.WhitelistedNames) + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution cookies +// TypeSet attribute. +func cookiePreferenceHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["forward"].(string))) + if d, ok := m["whitelisted_names"]; ok { + for _, e := range sortInterfaceSlice(d.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", e.(string))) + } + } + return hashcode.String(buf.String()) +} + +func expandCookieNames(d []interface{}) *cloudfront.CookieNames { + return &cloudfront.CookieNames{ + Quantity: aws.Int64(int64(len(d))), + Items: expandStringList(d), + } +} + +func flattenCookieNames(cn *cloudfront.CookieNames) []interface{} { + if cn.Items != nil { + return flattenStringList(cn.Items) + } + return []interface{}{} +} + +func expandAllowedMethods(s []interface{}) *cloudfront.AllowedMethods { + return &cloudfront.AllowedMethods{ + Quantity: aws.Int64(int64(len(s))), + Items: expandStringList(s), + } +} + +func flattenAllowedMethods(am *cloudfront.AllowedMethods) []interface{} { + if am.Items != nil { + return flattenStringList(am.Items) + } + return []interface{}{} +} + +func expandCachedMethods(s []interface{}) *cloudfront.CachedMethods { + return &cloudfront.CachedMethods{ + Quantity: aws.Int64(int64(len(s))), + Items: expandStringList(s), + } +} + +func flattenCachedMethods(cm *cloudfront.CachedMethods) []interface{} { + if cm.Items != nil { + return flattenStringList(cm.Items) + } + return []interface{}{} +} + +func expandOrigins(s *schema.Set) *cloudfront.Origins { + qty := 0 + items := []*cloudfront.Origin{} + for _, v := range s.List() { + items = append(items, expandOrigin(v.(map[string]interface{}))) + qty++ + } + return &cloudfront.Origins{ + Quantity: aws.Int64(int64(qty)), + Items: items, + } +} + +func flattenOrigins(ors *cloudfront.Origins) *schema.Set { + s := []interface{}{} + for _, v := range ors.Items { + s = append(s, flattenOrigin(v)) + } + return schema.NewSet(originHash, s) +} + +func expandOrigin(m map[string]interface{}) *cloudfront.Origin { + origin := &cloudfront.Origin{ + Id: aws.String(m["origin_id"].(string)), + DomainName: aws.String(m["domain_name"].(string)), + } + if v, ok := m["custom_header"]; ok { + origin.CustomHeaders = expandCustomHeaders(v.(*schema.Set)) + } + if v, ok := m["custom_origin_config"]; ok { + if s := v.(*schema.Set).List(); len(s) > 0 { + origin.CustomOriginConfig = expandCustomOriginConfig(s[0].(map[string]interface{})) + } + } + if v, ok := m["origin_path"]; ok { + origin.OriginPath = aws.String(v.(string)) + } + if v, ok := m["s3_origin_config"]; ok { + if s := v.(*schema.Set).List(); len(s) > 0 { + origin.S3OriginConfig = expandS3OriginConfig(s[0].(map[string]interface{})) + } + } + return origin +} + +func flattenOrigin(or *cloudfront.Origin) map[string]interface{} { + m := make(map[string]interface{}) + m["origin_id"] = *or.Id + m["domain_name"] = *or.DomainName + if or.CustomHeaders != nil { + m["custom_header"] = flattenCustomHeaders(or.CustomHeaders) + } + if or.CustomOriginConfig != nil { + m["custom_origin_config"] = schema.NewSet(customOriginConfigHash, []interface{}{flattenCustomOriginConfig(or.CustomOriginConfig)}) + } + if or.OriginPath != nil { + m["origin_path"] = *or.OriginPath + } + if or.S3OriginConfig != nil { + m["s3_origin_config"] = schema.NewSet(s3OriginConfigHash, []interface{}{flattenS3OriginConfig(or.S3OriginConfig)}) + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution origin +// TypeSet attribute. +func originHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["origin_id"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["domain_name"].(string))) + if v, ok := m["custom_header"]; ok { + buf.WriteString(fmt.Sprintf("%d-", customHeadersHash(v.(*schema.Set)))) + } + if v, ok := m["custom_origin_config"]; ok { + if s := v.(*schema.Set).List(); len(s) > 0 { + buf.WriteString(fmt.Sprintf("%d-", customOriginConfigHash((s[0].(map[string]interface{}))))) + } + } + if v, ok := m["origin_path"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["s3_origin_config"]; ok { + if s := v.(*schema.Set).List(); len(s) > 0 { + buf.WriteString(fmt.Sprintf("%d-", s3OriginConfigHash((s[0].(map[string]interface{}))))) + } + } + return hashcode.String(buf.String()) +} + +func expandCustomHeaders(s *schema.Set) *cloudfront.CustomHeaders { + qty := 0 + items := []*cloudfront.OriginCustomHeader{} + for _, v := range s.List() { + items = append(items, expandOriginCustomHeader(v.(map[string]interface{}))) + qty++ + } + return &cloudfront.CustomHeaders{ + Quantity: aws.Int64(int64(qty)), + Items: items, + } +} + +func flattenCustomHeaders(chs *cloudfront.CustomHeaders) *schema.Set { + s := []interface{}{} + for _, v := range chs.Items { + s = append(s, flattenOriginCustomHeader(v)) + } + return schema.NewSet(originCustomHeaderHash, s) +} + +func expandOriginCustomHeader(m map[string]interface{}) *cloudfront.OriginCustomHeader { + return &cloudfront.OriginCustomHeader{ + HeaderName: aws.String(m["name"].(string)), + HeaderValue: aws.String(m["value"].(string)), + } +} + +func flattenOriginCustomHeader(och *cloudfront.OriginCustomHeader) map[string]interface{} { + return map[string]interface{}{ + "name": *och.HeaderName, + "value": *och.HeaderValue, + } +} + +// Helper function used by originHash to get a composite hash for all +// aws_cloudfront_distribution custom_header attributes. +func customHeadersHash(s *schema.Set) int { + var buf bytes.Buffer + for _, v := range s.List() { + buf.WriteString(fmt.Sprintf("%d-", originCustomHeaderHash(v))) + } + return hashcode.String(buf.String()) +} + +// Assemble the hash for the aws_cloudfront_distribution custom_header +// TypeSet attribute. +func originCustomHeaderHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["value"].(string))) + return hashcode.String(buf.String()) +} + +func expandCustomOriginConfig(m map[string]interface{}) *cloudfront.CustomOriginConfig { + return &cloudfront.CustomOriginConfig{ + OriginProtocolPolicy: aws.String(m["origin_protocol_policy"].(string)), + HTTPPort: aws.Int64(int64(m["http_port"].(int))), + HTTPSPort: aws.Int64(int64(m["https_port"].(int))), + OriginSslProtocols: expandCustomOriginConfigSSL(m["origin_ssl_protocols"].([]interface{})), + } +} + +func flattenCustomOriginConfig(cor *cloudfront.CustomOriginConfig) map[string]interface{} { + return map[string]interface{}{ + "origin_protocol_policy": *cor.OriginProtocolPolicy, + "http_port": int(*cor.HTTPPort), + "https_port": int(*cor.HTTPSPort), + "origin_ssl_protocols": flattenCustomOriginConfigSSL(cor.OriginSslProtocols), + } +} + +// Assemble the hash for the aws_cloudfront_distribution custom_origin_config +// TypeSet attribute. +func customOriginConfigHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["origin_protocol_policy"].(string))) + buf.WriteString(fmt.Sprintf("%d-", m["http_port"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["https_port"].(int))) + for _, v := range sortInterfaceSlice(m["origin_ssl_protocols"].([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + return hashcode.String(buf.String()) +} + +func expandCustomOriginConfigSSL(s []interface{}) *cloudfront.OriginSslProtocols { + items := expandStringList(s) + return &cloudfront.OriginSslProtocols{ + Quantity: aws.Int64(int64(len(items))), + Items: items, + } +} + +func flattenCustomOriginConfigSSL(osp *cloudfront.OriginSslProtocols) []interface{} { + return flattenStringList(osp.Items) +} + +func expandS3OriginConfig(m map[string]interface{}) *cloudfront.S3OriginConfig { + return &cloudfront.S3OriginConfig{ + OriginAccessIdentity: aws.String(m["origin_access_identity"].(string)), + } +} + +func flattenS3OriginConfig(s3o *cloudfront.S3OriginConfig) map[string]interface{} { + return map[string]interface{}{ + "origin_access_identity": *s3o.OriginAccessIdentity, + } +} + +// Assemble the hash for the aws_cloudfront_distribution s3_origin_config +// TypeSet attribute. +func s3OriginConfigHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["origin_access_identity"].(string))) + return hashcode.String(buf.String()) +} + +func expandCustomErrorResponses(s *schema.Set) *cloudfront.CustomErrorResponses { + qty := 0 + items := []*cloudfront.CustomErrorResponse{} + for _, v := range s.List() { + items = append(items, expandCustomErrorResponse(v.(map[string]interface{}))) + qty++ + } + return &cloudfront.CustomErrorResponses{ + Quantity: aws.Int64(int64(qty)), + Items: items, + } +} + +func flattenCustomErrorResponses(ers *cloudfront.CustomErrorResponses) *schema.Set { + s := []interface{}{} + for _, v := range ers.Items { + s = append(s, flattenCustomErrorResponse(v)) + } + return schema.NewSet(customErrorResponseHash, s) +} + +func expandCustomErrorResponse(m map[string]interface{}) *cloudfront.CustomErrorResponse { + er := cloudfront.CustomErrorResponse{ + ErrorCode: aws.Int64(int64(m["error_code"].(int))), + } + if v, ok := m["error_caching_min_ttl"]; ok { + er.ErrorCachingMinTTL = aws.Int64(int64(v.(int))) + } + if v, ok := m["response_code"]; ok { + er.ResponseCode = aws.String(strconv.Itoa(v.(int))) + } + if v, ok := m["response_page_path"]; ok { + er.ResponsePagePath = aws.String(v.(string)) + } + return &er +} + +func flattenCustomErrorResponse(er *cloudfront.CustomErrorResponse) map[string]interface{} { + m := make(map[string]interface{}) + m["error_code"] = int(*er.ErrorCode) + if er.ErrorCachingMinTTL != nil { + m["error_caching_min_ttl"] = int(*er.ErrorCachingMinTTL) + } + if er.ResponseCode != nil { + m["response_code"], _ = strconv.Atoi(*er.ResponseCode) + } + if er.ResponsePagePath != nil { + m["response_page_path"] = *er.ResponsePagePath + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution custom_error_response +// TypeSet attribute. +func customErrorResponseHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%d-", m["error_code"].(int))) + if v, ok := m["error_caching_min_ttl"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["response_code"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["response_page_path"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + return hashcode.String(buf.String()) +} + +func expandLoggingConfig(m map[string]interface{}) *cloudfront.LoggingConfig { + var lc cloudfront.LoggingConfig + if m != nil { + lc.Prefix = aws.String(m["prefix"].(string)) + lc.Bucket = aws.String(m["bucket"].(string)) + lc.IncludeCookies = aws.Bool(m["include_cookies"].(bool)) + lc.Enabled = aws.Bool(true) + } else { + lc.Prefix = aws.String("") + lc.Bucket = aws.String("") + lc.IncludeCookies = aws.Bool(false) + lc.Enabled = aws.Bool(false) + } + return &lc +} + +func flattenLoggingConfig(lc *cloudfront.LoggingConfig) *schema.Set { + m := make(map[string]interface{}) + m["prefix"] = *lc.Prefix + m["bucket"] = *lc.Bucket + m["include_cookies"] = *lc.IncludeCookies + return schema.NewSet(loggingConfigHash, []interface{}{m}) +} + +// Assemble the hash for the aws_cloudfront_distribution logging_config +// TypeSet attribute. +func loggingConfigHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["prefix"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["bucket"].(string))) + buf.WriteString(fmt.Sprintf("%t-", m["include_cookies"].(bool))) + return hashcode.String(buf.String()) +} + +func expandAliases(as *schema.Set) *cloudfront.Aliases { + s := as.List() + var aliases cloudfront.Aliases + if len(s) > 0 { + aliases.Quantity = aws.Int64(int64(len(s))) + aliases.Items = expandStringList(s) + } else { + aliases.Quantity = aws.Int64(0) + } + return &aliases +} + +func flattenAliases(aliases *cloudfront.Aliases) *schema.Set { + if aliases.Items != nil { + return schema.NewSet(aliasesHash, flattenStringList(aliases.Items)) + } + return schema.NewSet(aliasesHash, []interface{}{}) +} + +// Assemble the hash for the aws_cloudfront_distribution aliases +// TypeSet attribute. +func aliasesHash(v interface{}) int { + return hashcode.String(v.(string)) +} + +func expandRestrictions(m map[string]interface{}) *cloudfront.Restrictions { + return &cloudfront.Restrictions{ + GeoRestriction: expandGeoRestriction(m["geo_restriction"].(*schema.Set).List()[0].(map[string]interface{})), + } +} + +func flattenRestrictions(r *cloudfront.Restrictions) *schema.Set { + m := make(map[string]interface{}) + s := schema.NewSet(geoRestrictionHash, []interface{}{flattenGeoRestriction(r.GeoRestriction)}) + m["geo_restriction"] = s + return schema.NewSet(restrictionsHash, []interface{}{m}) +} + +// Assemble the hash for the aws_cloudfront_distribution restrictions +// TypeSet attribute. +func restrictionsHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%d-", geoRestrictionHash(m["geo_restriction"].(*schema.Set).List()[0].(map[string]interface{})))) + return hashcode.String(buf.String()) +} + +func expandGeoRestriction(m map[string]interface{}) *cloudfront.GeoRestriction { + gr := cloudfront.GeoRestriction{ + RestrictionType: aws.String(m["restriction_type"].(string)), + } + if v, ok := m["locations"]; ok { + gr.Quantity = aws.Int64(int64(len(v.([]interface{})))) + gr.Items = expandStringList(v.([]interface{})) + } else { + gr.Quantity = aws.Int64(0) + } + return &gr +} + +func flattenGeoRestriction(gr *cloudfront.GeoRestriction) map[string]interface{} { + m := make(map[string]interface{}) + + m["restriction_type"] = *gr.RestrictionType + if gr.Items != nil { + m["locations"] = flattenStringList(gr.Items) + } + return m +} + +// Assemble the hash for the aws_cloudfront_distribution geo_restriction +// TypeSet attribute. +func geoRestrictionHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + // All keys added in alphabetical order. + buf.WriteString(fmt.Sprintf("%s-", m["restriction_type"].(string))) + if v, ok := m["locations"]; ok { + for _, w := range sortInterfaceSlice(v.([]interface{})) { + buf.WriteString(fmt.Sprintf("%s-", w.(string))) + } + } + return hashcode.String(buf.String()) +} + +func expandViewerCertificate(m map[string]interface{}) *cloudfront.ViewerCertificate { + var vc cloudfront.ViewerCertificate + if v, ok := m["iam_certificate_id"]; ok && v != "" { + vc.IAMCertificateId = aws.String(v.(string)) + vc.SSLSupportMethod = aws.String(m["ssl_support_method"].(string)) + } else { + vc.CloudFrontDefaultCertificate = aws.Bool(m["cloudfront_default_certificate"].(bool)) + } + if v, ok := m["minimum_protocol_version"]; ok && v != "" { + vc.MinimumProtocolVersion = aws.String(v.(string)) + } + return &vc +} + +func flattenViewerCertificate(vc *cloudfront.ViewerCertificate) *schema.Set { + m := make(map[string]interface{}) + + if vc.IAMCertificateId != nil { + m["iam_certificate_id"] = *vc.IAMCertificateId + m["ssl_support_method"] = *vc.SSLSupportMethod + } else { + m["cloudfront_default_certificate"] = *vc.CloudFrontDefaultCertificate + } + if vc.MinimumProtocolVersion != nil { + m["minimum_protocol_version"] = *vc.MinimumProtocolVersion + } + return schema.NewSet(viewerCertificateHash, []interface{}{m}) +} + +// Assemble the hash for the aws_cloudfront_distribution viewer_certificate +// TypeSet attribute. +func viewerCertificateHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + if v, ok := m["iam_certificate_id"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + buf.WriteString(fmt.Sprintf("%s-", m["ssl_support_method"].(string))) + } else { + buf.WriteString(fmt.Sprintf("%t-", m["cloudfront_default_certificate"].(bool))) + } + if v, ok := m["minimum_protocol_version"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + return hashcode.String(buf.String()) +} + +// Do a top-level copy of struct fields from one struct to another. Used to +// copy fields between CacheBehavior and DefaultCacheBehavior structs. +func simpleCopyStruct(src, dst interface{}) { + s := reflect.ValueOf(src).Elem() + d := reflect.ValueOf(dst).Elem() + + for i := 0; i < s.NumField(); i++ { + if s.Field(i).CanSet() == true { + if s.Field(i).Interface() != nil { + for j := 0; j < d.NumField(); j++ { + if d.Type().Field(j).Name == s.Type().Field(i).Name { + d.Field(j).Set(s.Field(i)) + } + } + } + } + } +} + +// Convert *cloudfront.ActiveTrustedSigners to a flatmap.Map type, which ensures +// it can probably be inserted into the schema.TypeMap type used by the +// active_trusted_signers attribute. +func flattenActiveTrustedSigners(ats *cloudfront.ActiveTrustedSigners) flatmap.Map { + m := make(map[string]interface{}) + s := []interface{}{} + m["enabled"] = *ats.Enabled + + for _, v := range ats.Items { + signer := make(map[string]interface{}) + signer["aws_account_number"] = *v.AwsAccountNumber + signer["key_pair_ids"] = aws.StringValueSlice(v.KeyPairIds.Items) + s = append(s, signer) + } + m["items"] = s + return flatmap.Flatten(m) +} diff --git a/builtin/providers/aws/cloudfront_distribution_configuration_structure_test.go b/builtin/providers/aws/cloudfront_distribution_configuration_structure_test.go new file mode 100644 index 000000000000..630fcbec03c4 --- /dev/null +++ b/builtin/providers/aws/cloudfront_distribution_configuration_structure_test.go @@ -0,0 +1,944 @@ +package aws + +import ( + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/hashicorp/terraform/helper/schema" +) + +func defaultCacheBehaviorConf() map[string]interface{} { + return map[string]interface{}{ + "viewer_protocol_policy": "allow-all", + "target_origin_id": "myS3Origin", + "forwarded_values": schema.NewSet(forwardedValuesHash, []interface{}{forwardedValuesConf()}), + "min_ttl": 86400, + "trusted_signers": trustedSignersConf(), + "max_ttl": 365000000, + "smooth_streaming": false, + "default_ttl": 86400, + "allowed_methods": allowedMethodsConf(), + "cached_methods": cachedMethodsConf(), + "compress": true, + } +} + +func cacheBehaviorConf1() map[string]interface{} { + cb := defaultCacheBehaviorConf() + cb["path_pattern"] = "/path1" + return cb +} + +func cacheBehaviorConf2() map[string]interface{} { + cb := defaultCacheBehaviorConf() + cb["path_pattern"] = "/path2" + return cb +} + +func cacheBehaviorsConf() *schema.Set { + return schema.NewSet(cacheBehaviorHash, []interface{}{cacheBehaviorConf1(), cacheBehaviorConf2()}) +} + +func trustedSignersConf() []interface{} { + return []interface{}{"1234567890EX", "1234567891EX"} +} + +func forwardedValuesConf() map[string]interface{} { + return map[string]interface{}{ + "query_string": true, + "cookies": schema.NewSet(cookiePreferenceHash, []interface{}{cookiePreferenceConf()}), + "headers": headersConf(), + } +} + +func headersConf() []interface{} { + return []interface{}{"X-Example1", "X-Example2"} +} + +func cookiePreferenceConf() map[string]interface{} { + return map[string]interface{}{ + "forward": "whitelist", + "whitelisted_names": cookieNamesConf(), + } +} + +func cookieNamesConf() []interface{} { + return []interface{}{"Example1", "Example2"} +} + +func allowedMethodsConf() []interface{} { + return []interface{}{"DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"} +} + +func cachedMethodsConf() []interface{} { + return []interface{}{"GET", "HEAD", "OPTIONS"} +} + +func originCustomHeadersConf() *schema.Set { + return schema.NewSet(originCustomHeaderHash, []interface{}{originCustomHeaderConf1(), originCustomHeaderConf2()}) +} + +func originCustomHeaderConf1() map[string]interface{} { + return map[string]interface{}{ + "name": "X-Custom-Header1", + "value": "samplevalue", + } +} + +func originCustomHeaderConf2() map[string]interface{} { + return map[string]interface{}{ + "name": "X-Custom-Header2", + "value": "samplevalue", + } +} + +func customOriginConf() map[string]interface{} { + return map[string]interface{}{ + "origin_protocol_policy": "http-only", + "http_port": 80, + "https_port": 443, + "origin_ssl_protocols": customOriginSslProtocolsConf(), + } +} + +func customOriginSslProtocolsConf() []interface{} { + return []interface{}{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"} +} + +func s3OriginConf() map[string]interface{} { + return map[string]interface{}{ + "origin_access_identity": "origin-access-identity/cloudfront/E127EXAMPLE51Z", + } +} + +func originWithCustomConf() map[string]interface{} { + return map[string]interface{}{ + "origin_id": "CustomOrigin", + "domain_name": "www.example.com", + "origin_path": "/", + "custom_origin_config": schema.NewSet(customOriginConfigHash, []interface{}{customOriginConf()}), + "custom_header": originCustomHeadersConf(), + } +} +func originWithS3Conf() map[string]interface{} { + return map[string]interface{}{ + "origin_id": "S3Origin", + "domain_name": "s3.example.com", + "origin_path": "/", + "s3_origin_config": schema.NewSet(s3OriginConfigHash, []interface{}{s3OriginConf()}), + "custom_header": originCustomHeadersConf(), + } +} + +func multiOriginConf() *schema.Set { + return schema.NewSet(originHash, []interface{}{originWithCustomConf(), originWithS3Conf()}) +} + +func geoRestrictionWhitelistConf() map[string]interface{} { + return map[string]interface{}{ + "restriction_type": "whitelist", + "locations": []interface{}{"CA", "GB", "US"}, + } +} + +func geoRestrictionsConf() map[string]interface{} { + return map[string]interface{}{ + "geo_restriction": schema.NewSet(geoRestrictionHash, []interface{}{geoRestrictionWhitelistConf()}), + } +} + +func geoRestrictionConfNoItems() map[string]interface{} { + return map[string]interface{}{ + "restriction_type": "none", + } +} + +func customErrorResponsesConf() []interface{} { + return []interface{}{ + map[string]interface{}{ + "error_code": 404, + "error_caching_min_ttl": 30, + "response_code": 200, + "response_page_path": "/error-pages/404.html", + }, + map[string]interface{}{ + "error_code": 403, + "error_caching_min_ttl": 15, + "response_code": 404, + "response_page_path": "/error-pages/404.html", + }, + } +} + +func aliasesConf() *schema.Set { + return schema.NewSet(aliasesHash, []interface{}{"example.com", "www.example.com"}) +} + +func loggingConfigConf() map[string]interface{} { + return map[string]interface{}{ + "include_cookies": false, + "bucket": "mylogs.s3.amazonaws.com", + "prefix": "myprefix", + } +} + +func customErrorResponsesConfSet() *schema.Set { + return schema.NewSet(customErrorResponseHash, customErrorResponsesConf()) +} + +func customErrorResponsesConfFirst() map[string]interface{} { + return customErrorResponsesConf()[0].(map[string]interface{}) +} + +func viewerCertificateConfSetCloudFrontDefault() map[string]interface{} { + return map[string]interface{}{ + "cloudfront_default_certificate": true, + } +} + +func viewerCertificateConfSetIAM() map[string]interface{} { + return map[string]interface{}{ + "iam_certificate_id": "iamcert-01234567", + "ssl_support_method": "vip", + "minimum_protocol_version": "TLSv1", + } +} + +func TestCloudFrontStructure_expandDefaultCacheBehavior(t *testing.T) { + data := defaultCacheBehaviorConf() + dcb := expandDefaultCacheBehavior(data) + if *dcb.Compress != true { + t.Fatalf("Expected Compress to be true, got %v", *dcb.Compress) + } + if *dcb.ViewerProtocolPolicy != "allow-all" { + t.Fatalf("Expected ViewerProtocolPolicy to be allow-all, got %v", *dcb.ViewerProtocolPolicy) + } + if *dcb.TargetOriginId != "myS3Origin" { + t.Fatalf("Expected TargetOriginId to be allow-all, got %v", *dcb.TargetOriginId) + } + if reflect.DeepEqual(dcb.ForwardedValues.Headers.Items, expandStringList(headersConf())) != true { + t.Fatalf("Expected Items to be %v, got %v", headersConf(), dcb.ForwardedValues.Headers.Items) + } + if *dcb.MinTTL != 86400 { + t.Fatalf("Expected MinTTL to be 86400, got %v", *dcb.MinTTL) + } + if reflect.DeepEqual(dcb.TrustedSigners.Items, expandStringList(trustedSignersConf())) != true { + t.Fatalf("Expected TrustedSigners.Items to be %v, got %v", trustedSignersConf(), dcb.TrustedSigners.Items) + } + if *dcb.MaxTTL != 365000000 { + t.Fatalf("Expected MaxTTL to be 86400, got %v", *dcb.MaxTTL) + } + if *dcb.SmoothStreaming != false { + t.Fatalf("Expected SmoothStreaming to be false, got %v", *dcb.SmoothStreaming) + } + if *dcb.DefaultTTL != 86400 { + t.Fatalf("Expected DefaultTTL to be 86400, got %v", *dcb.DefaultTTL) + } + if reflect.DeepEqual(dcb.AllowedMethods.Items, expandStringList(allowedMethodsConf())) != true { + t.Fatalf("Expected TrustedSigners.Items to be %v, got %v", allowedMethodsConf(), dcb.AllowedMethods.Items) + } + if reflect.DeepEqual(dcb.AllowedMethods.CachedMethods.Items, expandStringList(cachedMethodsConf())) != true { + t.Fatalf("Expected TrustedSigners.Items to be %v, got %v", cachedMethodsConf(), dcb.AllowedMethods.CachedMethods.Items) + } +} + +func TestCloudFrontStructure_flattenDefaultCacheBehavior(t *testing.T) { + in := defaultCacheBehaviorConf() + dcb := expandDefaultCacheBehavior(in) + out := flattenDefaultCacheBehavior(dcb) + diff := schema.NewSet(defaultCacheBehaviorHash, []interface{}{in}).Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandCacheBehavior(t *testing.T) { + data := cacheBehaviorConf1() + cb := expandCacheBehavior(data) + if *cb.Compress != true { + t.Fatalf("Expected Compress to be true, got %v", *cb.Compress) + } + if *cb.ViewerProtocolPolicy != "allow-all" { + t.Fatalf("Expected ViewerProtocolPolicy to be allow-all, got %v", *cb.ViewerProtocolPolicy) + } + if *cb.TargetOriginId != "myS3Origin" { + t.Fatalf("Expected TargetOriginId to be myS3Origin, got %v", *cb.TargetOriginId) + } + if reflect.DeepEqual(cb.ForwardedValues.Headers.Items, expandStringList(headersConf())) != true { + t.Fatalf("Expected Items to be %v, got %v", headersConf(), cb.ForwardedValues.Headers.Items) + } + if *cb.MinTTL != 86400 { + t.Fatalf("Expected MinTTL to be 86400, got %v", *cb.MinTTL) + } + if reflect.DeepEqual(cb.TrustedSigners.Items, expandStringList(trustedSignersConf())) != true { + t.Fatalf("Expected TrustedSigners.Items to be %v, got %v", trustedSignersConf(), cb.TrustedSigners.Items) + } + if *cb.MaxTTL != 365000000 { + t.Fatalf("Expected MaxTTL to be 365000000, got %v", *cb.MaxTTL) + } + if *cb.SmoothStreaming != false { + t.Fatalf("Expected SmoothStreaming to be false, got %v", *cb.SmoothStreaming) + } + if *cb.DefaultTTL != 86400 { + t.Fatalf("Expected DefaultTTL to be 86400, got %v", *cb.DefaultTTL) + } + if reflect.DeepEqual(cb.AllowedMethods.Items, expandStringList(allowedMethodsConf())) != true { + t.Fatalf("Expected AllowedMethods.Items to be %v, got %v", allowedMethodsConf(), cb.AllowedMethods.Items) + } + if reflect.DeepEqual(cb.AllowedMethods.CachedMethods.Items, expandStringList(cachedMethodsConf())) != true { + t.Fatalf("Expected AllowedMethods.CachedMethods.Items to be %v, got %v", cachedMethodsConf(), cb.AllowedMethods.CachedMethods.Items) + } + if *cb.PathPattern != "/path1" { + t.Fatalf("Expected PathPattern to be /path1, got %v", *cb.PathPattern) + } +} + +func TestCloudFrontStructure_flattenCacheBehavior(t *testing.T) { + in := cacheBehaviorConf1() + cb := expandCacheBehavior(in) + out := flattenCacheBehavior(cb) + var diff *schema.Set + if out["compress"] != true { + t.Fatalf("Expected out[compress] to be true, got %v", out["compress"]) + } + if out["viewer_protocol_policy"] != "allow-all" { + t.Fatalf("Expected out[viewer_protocol_policy] to be allow-all, got %v", out["viewer_protocol_policy"]) + } + if out["target_origin_id"] != "myS3Origin" { + t.Fatalf("Expected out[target_origin_id] to be myS3Origin, got %v", out["target_origin_id"]) + } + diff = out["forwarded_values"].(*schema.Set).Difference(in["forwarded_values"].(*schema.Set)) + if len(diff.List()) > 0 { + t.Fatalf("Expected out[forwarded_values] to be %v, got %v, diff: %v", out["forwarded_values"], in["forwarded_values"], diff) + } + if out["min_ttl"] != int(86400) { + t.Fatalf("Expected out[min_ttl] to be 86400 (int), got %v", out["forwarded_values"]) + } + if reflect.DeepEqual(out["trusted_signers"], in["trusted_signers"]) != true { + t.Fatalf("Expected out[trusted_signers] to be %v, got %v", in["trusted_signers"], out["trusted_signers"]) + } + if out["max_ttl"] != int(365000000) { + t.Fatalf("Expected out[max_ttl] to be 365000000 (int), got %v", out["max_ttl"]) + } + if out["smooth_streaming"] != false { + t.Fatalf("Expected out[smooth_streaming] to be false, got %v", out["smooth_streaming"]) + } + if out["default_ttl"] != int(86400) { + t.Fatalf("Expected out[default_ttl] to be 86400 (int), got %v", out["default_ttl"]) + } + if reflect.DeepEqual(out["allowed_methods"], in["allowed_methods"]) != true { + t.Fatalf("Expected out[allowed_methods] to be %v, got %v", in["allowed_methods"], out["allowed_methods"]) + } + if reflect.DeepEqual(out["cached_methods"], in["cached_methods"]) != true { + t.Fatalf("Expected out[cached_methods] to be %v, got %v", in["cached_methods"], out["cached_methods"]) + } + if out["path_pattern"] != "/path1" { + t.Fatalf("Expected out[path_pattern] to be /path1, got %v", out["path_pattern"]) + } +} + +func TestCloudFrontStructure_expandCacheBehaviors(t *testing.T) { + data := cacheBehaviorsConf() + cbs := expandCacheBehaviors(data) + if *cbs.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *cbs.Quantity) + } + if *cbs.Items[0].TargetOriginId != "myS3Origin" { + t.Fatalf("Expected first Item's TargetOriginId to be myS3Origin, got %v", *cbs.Items[0].TargetOriginId) + } +} + +func TestCloudFrontStructure_flattenCacheBehaviors(t *testing.T) { + in := cacheBehaviorsConf() + cbs := expandCacheBehaviors(in) + out := flattenCacheBehaviors(cbs) + diff := in.Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandTrustedSigners(t *testing.T) { + data := trustedSignersConf() + ts := expandTrustedSigners(data) + if *ts.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *ts.Quantity) + } + if *ts.Enabled != true { + t.Fatalf("Expected Enabled to be true, got %v", *ts.Enabled) + } + if reflect.DeepEqual(ts.Items, expandStringList(data)) != true { + t.Fatalf("Expected Items to be %v, got %v", data, ts.Items) + } +} + +func TestCloudFrontStructure_flattenTrustedSigners(t *testing.T) { + in := trustedSignersConf() + ts := expandTrustedSigners(in) + out := flattenTrustedSigners(ts) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandTrustedSigners_empty(t *testing.T) { + data := []interface{}{} + ts := expandTrustedSigners(data) + if *ts.Quantity != 0 { + t.Fatalf("Expected Quantity to be 2, got %v", *ts.Quantity) + } + if *ts.Enabled != false { + t.Fatalf("Expected Enabled to be true, got %v", *ts.Enabled) + } + if ts.Items != nil { + t.Fatalf("Expected Items to be nil, got %v", ts.Items) + } +} + +func TestCloudFrontStructure_expandForwardedValues(t *testing.T) { + data := forwardedValuesConf() + fv := expandForwardedValues(data) + if *fv.QueryString != true { + t.Fatalf("Expected QueryString to be true, got %v", *fv.QueryString) + } + if reflect.DeepEqual(fv.Cookies.WhitelistedNames.Items, expandStringList(cookieNamesConf())) != true { + t.Fatalf("Expected Cookies.WhitelistedNames.Items to be %v, got %v", cookieNamesConf(), fv.Cookies.WhitelistedNames.Items) + } + if reflect.DeepEqual(fv.Headers.Items, expandStringList(headersConf())) != true { + t.Fatalf("Expected Headers.Items to be %v, got %v", headersConf(), fv.Headers.Items) + } +} + +func TestCloudFrontStructure_flattenForwardedValues(t *testing.T) { + in := forwardedValuesConf() + fv := expandForwardedValues(in) + out := flattenForwardedValues(fv) + + if out["query_string"] != true { + t.Fatalf("Expected out[query_string] to be true, got %v", out["query_string"]) + } + if out["cookies"].(*schema.Set).Equal(in["cookies"].(*schema.Set)) != true { + t.Fatalf("Expected out[cookies] to be %v, got %v", in["cookies"], out["cookies"]) + } + if reflect.DeepEqual(out["headers"], in["headers"]) != true { + t.Fatalf("Expected out[headers] to be %v, got %v", in["headers"], out["headers"]) + } +} + +func TestCloudFrontStructure_expandHeaders(t *testing.T) { + data := headersConf() + h := expandHeaders(data) + if *h.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *h.Quantity) + } + if reflect.DeepEqual(h.Items, expandStringList(data)) != true { + t.Fatalf("Expected Items to be %v, got %v", data, h.Items) + } +} + +func TestCloudFrontStructure_flattenHeaders(t *testing.T) { + in := headersConf() + h := expandHeaders(in) + out := flattenHeaders(h) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCookiePreference(t *testing.T) { + data := cookiePreferenceConf() + cp := expandCookiePreference(data) + if *cp.Forward != "whitelist" { + t.Fatalf("Expected Forward to be whitelist, got %v", *cp.Forward) + } + if reflect.DeepEqual(cp.WhitelistedNames.Items, expandStringList(cookieNamesConf())) != true { + t.Fatalf("Expected WhitelistedNames.Items to be %v, got %v", cookieNamesConf(), cp.WhitelistedNames.Items) + } +} + +func TestCloudFrontStructure_flattenCookiePreference(t *testing.T) { + in := cookiePreferenceConf() + cp := expandCookiePreference(in) + out := flattenCookiePreference(cp) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCookieNames(t *testing.T) { + data := cookieNamesConf() + cn := expandCookieNames(data) + if *cn.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *cn.Quantity) + } + if reflect.DeepEqual(cn.Items, expandStringList(data)) != true { + t.Fatalf("Expected Items to be %v, got %v", data, cn.Items) + } +} + +func TestCloudFrontStructure_flattenCookieNames(t *testing.T) { + in := cookieNamesConf() + cn := expandCookieNames(in) + out := flattenCookieNames(cn) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandAllowedMethods(t *testing.T) { + data := allowedMethodsConf() + am := expandAllowedMethods(data) + if *am.Quantity != 7 { + t.Fatalf("Expected Quantity to be 3, got %v", *am.Quantity) + } + if reflect.DeepEqual(am.Items, expandStringList(data)) != true { + t.Fatalf("Expected Items to be %v, got %v", data, am.Items) + } +} + +func TestCloudFrontStructure_flattenAllowedMethods(t *testing.T) { + in := allowedMethodsConf() + am := expandAllowedMethods(in) + out := flattenAllowedMethods(am) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCachedMethods(t *testing.T) { + data := cachedMethodsConf() + cm := expandCachedMethods(data) + if *cm.Quantity != 3 { + t.Fatalf("Expected Quantity to be 3, got %v", *cm.Quantity) + } + if reflect.DeepEqual(cm.Items, expandStringList(data)) != true { + t.Fatalf("Expected Items to be %v, got %v", data, cm.Items) + } +} + +func TestCloudFrontStructure_flattenCachedMethods(t *testing.T) { + in := cachedMethodsConf() + cm := expandCachedMethods(in) + out := flattenCachedMethods(cm) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandOrigins(t *testing.T) { + data := multiOriginConf() + origins := expandOrigins(data) + if *origins.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *origins.Quantity) + } + if *origins.Items[0].OriginPath != "/" { + t.Fatalf("Expected first Item's OriginPath to be /, got %v", *origins.Items[0].OriginPath) + } +} + +func TestCloudFrontStructure_flattenOrigins(t *testing.T) { + in := multiOriginConf() + origins := expandOrigins(in) + out := flattenOrigins(origins) + diff := in.Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandOrigin(t *testing.T) { + data := originWithCustomConf() + or := expandOrigin(data) + if *or.Id != "CustomOrigin" { + t.Fatalf("Expected Id to be CustomOrigin, got %v", *or.Id) + } + if *or.DomainName != "www.example.com" { + t.Fatalf("Expected DomainName to be www.example.com, got %v", *or.DomainName) + } + if *or.OriginPath != "/" { + t.Fatalf("Expected OriginPath to be /, got %v", *or.OriginPath) + } + if *or.CustomOriginConfig.OriginProtocolPolicy != "http-only" { + t.Fatalf("Expected CustomOriginConfig.OriginProtocolPolicy to be http-only, got %v", *or.CustomOriginConfig.OriginProtocolPolicy) + } + if *or.CustomHeaders.Items[0].HeaderValue != "samplevalue" { + t.Fatalf("Expected CustomHeaders.Items[0].HeaderValue to be samplevalue, got %v", *or.CustomHeaders.Items[0].HeaderValue) + } +} + +func TestCloudFrontStructure_flattenOrigin(t *testing.T) { + in := originWithCustomConf() + or := expandOrigin(in) + out := flattenOrigin(or) + + if out["origin_id"] != "CustomOrigin" { + t.Fatalf("Expected out[origin_id] to be CustomOrigin, got %v", out["origin_id"]) + } + if out["domain_name"] != "www.example.com" { + t.Fatalf("Expected out[domain_name] to be www.example.com, got %v", out["domain_name"]) + } + if out["origin_path"] != "/" { + t.Fatalf("Expected out[origin_path] to be /, got %v", out["origin_path"]) + } + if out["custom_origin_config"].(*schema.Set).Equal(in["custom_origin_config"].(*schema.Set)) != true { + t.Fatalf("Expected out[custom_origin_config] to be %v, got %v", in["custom_origin_config"], out["custom_origin_config"]) + } +} + +func TestCloudFrontStructure_expandCustomHeaders(t *testing.T) { + in := originCustomHeadersConf() + chs := expandCustomHeaders(in) + if *chs.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *chs.Quantity) + } + if *chs.Items[0].HeaderValue != "samplevalue" { + t.Fatalf("Expected first Item's HeaderValue to be samplevalue, got %v", *chs.Items[0].HeaderValue) + } +} + +func TestCloudFrontStructure_flattenCustomHeaders(t *testing.T) { + in := originCustomHeadersConf() + chs := expandCustomHeaders(in) + out := flattenCustomHeaders(chs) + diff := in.Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_flattenOriginCustomHeader(t *testing.T) { + in := originCustomHeaderConf1() + och := expandOriginCustomHeader(in) + out := flattenOriginCustomHeader(och) + + if out["name"] != "X-Custom-Header1" { + t.Fatalf("Expected out[name] to be X-Custom-Header1, got %v", out["name"]) + } + if out["value"] != "samplevalue" { + t.Fatalf("Expected out[value] to be samplevalue, got %v", out["value"]) + } +} + +func TestCloudFrontStructure_expandOriginCustomHeader(t *testing.T) { + in := originCustomHeaderConf1() + och := expandOriginCustomHeader(in) + + if *och.HeaderName != "X-Custom-Header1" { + t.Fatalf("Expected HeaderName to be X-Custom-Header1, got %v", *och.HeaderName) + } + if *och.HeaderValue != "samplevalue" { + t.Fatalf("Expected HeaderValue to be samplevalue, got %v", *och.HeaderValue) + } +} + +func TestCloudFrontStructure_expandCustomOriginConfig(t *testing.T) { + data := customOriginConf() + co := expandCustomOriginConfig(data) + if *co.OriginProtocolPolicy != "http-only" { + t.Fatalf("Expected OriginProtocolPolicy to be http-only, got %v", *co.OriginProtocolPolicy) + } + if *co.HTTPPort != 80 { + t.Fatalf("Expected HTTPPort to be 80, got %v", *co.HTTPPort) + } + if *co.HTTPSPort != 443 { + t.Fatalf("Expected HTTPSPort to be 443, got %v", *co.HTTPSPort) + } +} + +func TestCloudFrontStructure_flattenCustomOriginConfig(t *testing.T) { + in := customOriginConf() + co := expandCustomOriginConfig(in) + out := flattenCustomOriginConfig(co) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCustomOriginConfigSSL(t *testing.T) { + in := customOriginSslProtocolsConf() + ocs := expandCustomOriginConfigSSL(in) + if *ocs.Quantity != 4 { + t.Fatalf("Expected Quantity to be 4, got %v", *ocs.Quantity) + } + if *ocs.Items[0] != "SSLv3" { + t.Fatalf("Expected first Item to be SSLv3, got %v", *ocs.Items[0]) + } +} + +func TestCloudFrontStructure_flattenCustomOriginConfigSSL(t *testing.T) { + in := customOriginSslProtocolsConf() + ocs := expandCustomOriginConfigSSL(in) + out := flattenCustomOriginConfigSSL(ocs) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandS3OriginConfig(t *testing.T) { + data := s3OriginConf() + s3o := expandS3OriginConfig(data) + if *s3o.OriginAccessIdentity != "origin-access-identity/cloudfront/E127EXAMPLE51Z" { + t.Fatalf("Expected OriginAccessIdentity to be origin-access-identity/cloudfront/E127EXAMPLE51Z, got %v", *s3o.OriginAccessIdentity) + } +} + +func TestCloudFrontStructure_flattenS3OriginConfig(t *testing.T) { + in := s3OriginConf() + s3o := expandS3OriginConfig(in) + out := flattenS3OriginConfig(s3o) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCustomErrorResponses(t *testing.T) { + data := customErrorResponsesConfSet() + ers := expandCustomErrorResponses(data) + if *ers.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *ers.Quantity) + } + if *ers.Items[0].ResponsePagePath != "/error-pages/404.html" { + t.Fatalf("Expected ResponsePagePath in first Item to be /error-pages/404.html, got %v", *ers.Items[0].ResponsePagePath) + } +} + +func TestCloudFrontStructure_flattenCustomErrorResponses(t *testing.T) { + in := customErrorResponsesConfSet() + ers := expandCustomErrorResponses(in) + out := flattenCustomErrorResponses(ers) + + if in.Equal(out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandCustomErrorResponse(t *testing.T) { + data := customErrorResponsesConfFirst() + er := expandCustomErrorResponse(data) + if *er.ErrorCode != 404 { + t.Fatalf("Expected ErrorCode to be 404, got %v", *er.ErrorCode) + } + if *er.ErrorCachingMinTTL != 30 { + t.Fatalf("Expected ErrorCachingMinTTL to be 30, got %v", *er.ErrorCachingMinTTL) + } + if *er.ResponseCode != "200" { + t.Fatalf("Expected ResponseCode to be 200 (as string), got %v", *er.ResponseCode) + } + if *er.ResponsePagePath != "/error-pages/404.html" { + t.Fatalf("Expected ResponsePagePath to be /error-pages/404.html, got %v", *er.ResponsePagePath) + } +} + +func TestCloudFrontStructure_flattenCustomErrorResponse(t *testing.T) { + in := customErrorResponsesConfFirst() + er := expandCustomErrorResponse(in) + out := flattenCustomErrorResponse(er) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandLoggingConfig(t *testing.T) { + data := loggingConfigConf() + + lc := expandLoggingConfig(data) + if *lc.Enabled != true { + t.Fatalf("Expected Enabled to be true, got %v", *lc.Enabled) + } + if *lc.Prefix != "myprefix" { + t.Fatalf("Expected Prefix to be myprefix, got %v", *lc.Prefix) + } + if *lc.Bucket != "mylogs.s3.amazonaws.com" { + t.Fatalf("Expected Bucket to be mylogs.s3.amazonaws.com, got %v", *lc.Bucket) + } + if *lc.IncludeCookies != false { + t.Fatalf("Expected IncludeCookies to be false, got %v", *lc.IncludeCookies) + } +} + +func TestCloudFrontStructure_expandLoggingConfig_nilValue(t *testing.T) { + lc := expandLoggingConfig(nil) + if *lc.Enabled != false { + t.Fatalf("Expected Enabled to be false, got %v", *lc.Enabled) + } + if *lc.Prefix != "" { + t.Fatalf("Expected Prefix to be blank, got %v", *lc.Prefix) + } + if *lc.Bucket != "" { + t.Fatalf("Expected Bucket to be blank, got %v", *lc.Bucket) + } + if *lc.IncludeCookies != false { + t.Fatalf("Expected IncludeCookies to be false, got %v", *lc.IncludeCookies) + } +} + +func TestCloudFrontStructure_flattenLoggingConfig(t *testing.T) { + in := loggingConfigConf() + lc := expandLoggingConfig(in) + out := flattenLoggingConfig(lc) + diff := schema.NewSet(loggingConfigHash, []interface{}{in}).Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandAliases(t *testing.T) { + data := aliasesConf() + a := expandAliases(data) + if *a.Quantity != 2 { + t.Fatalf("Expected Quantity to be 2, got %v", *a.Quantity) + } + if reflect.DeepEqual(a.Items, expandStringList(data.List())) != true { + t.Fatalf("Expected Items to be [example.com www.example.com], got %v", a.Items) + } +} + +func TestCloudFrontStructure_flattenAliases(t *testing.T) { + in := aliasesConf() + a := expandAliases(in) + out := flattenAliases(a) + diff := in.Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandRestrictions(t *testing.T) { + data := geoRestrictionsConf() + r := expandRestrictions(data) + if *r.GeoRestriction.RestrictionType != "whitelist" { + t.Fatalf("Expected GeoRestriction.RestrictionType to be whitelist, got %v", *r.GeoRestriction.RestrictionType) + } +} + +func TestCloudFrontStructure_flattenRestrictions(t *testing.T) { + in := geoRestrictionsConf() + r := expandRestrictions(in) + out := flattenRestrictions(r) + diff := schema.NewSet(restrictionsHash, []interface{}{in}).Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandGeoRestriction_whitelist(t *testing.T) { + data := geoRestrictionWhitelistConf() + gr := expandGeoRestriction(data) + if *gr.RestrictionType != "whitelist" { + t.Fatalf("Expected RestrictionType to be whitelist, got %v", *gr.RestrictionType) + } + if *gr.Quantity != 3 { + t.Fatalf("Expected Quantity to be 3, got %v", *gr.Quantity) + } + if reflect.DeepEqual(gr.Items, aws.StringSlice([]string{"CA", "GB", "US"})) != true { + t.Fatalf("Expected Items be [CA, GB, US], got %v", gr.Items) + } +} + +func TestCloudFrontStructure_flattenGeoRestriction_whitelist(t *testing.T) { + in := geoRestrictionWhitelistConf() + gr := expandGeoRestriction(in) + out := flattenGeoRestriction(gr) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandGeoRestriction_no_items(t *testing.T) { + data := geoRestrictionConfNoItems() + gr := expandGeoRestriction(data) + if *gr.RestrictionType != "none" { + t.Fatalf("Expected RestrictionType to be none, got %v", *gr.RestrictionType) + } + if *gr.Quantity != 0 { + t.Fatalf("Expected Quantity to be 0, got %v", *gr.Quantity) + } + if gr.Items != nil { + t.Fatalf("Expected Items to not be set, got %v", gr.Items) + } +} + +func TestCloudFrontStructure_flattenGeoRestriction_no_items(t *testing.T) { + in := geoRestrictionConfNoItems() + gr := expandGeoRestriction(in) + out := flattenGeoRestriction(gr) + + if reflect.DeepEqual(in, out) != true { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + +func TestCloudFrontStructure_expandViewerCertificate_cloudfront_default_certificate(t *testing.T) { + data := viewerCertificateConfSetCloudFrontDefault() + vc := expandViewerCertificate(data) + if *vc.CloudFrontDefaultCertificate != true { + t.Fatalf("Expected CloudFrontDefaultCertificate to be true, got %v", *vc.CloudFrontDefaultCertificate) + } + if vc.IAMCertificateId != nil { + t.Fatalf("Expected IAMCertificateId to not be set, got %v", *vc.IAMCertificateId) + } + if vc.SSLSupportMethod != nil { + t.Fatalf("Expected IAMCertificateId to not be set, got %v", *vc.SSLSupportMethod) + } + if vc.MinimumProtocolVersion != nil { + t.Fatalf("Expected IAMCertificateId to not be set, got %v", *vc.MinimumProtocolVersion) + } +} + +func TestCloudFrontStructure_flattenViewerCertificate_cloudfront_default_certificate(t *testing.T) { + in := viewerCertificateConfSetCloudFrontDefault() + vc := expandViewerCertificate(in) + out := flattenViewerCertificate(vc) + diff := schema.NewSet(viewerCertificateHash, []interface{}{in}).Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} + +func TestCloudFrontStructure_expandViewerCertificate_iam_certificate_id(t *testing.T) { + data := viewerCertificateConfSetIAM() + vc := expandViewerCertificate(data) + if vc.CloudFrontDefaultCertificate != nil { + t.Fatalf("Expected CloudFrontDefaultCertificate to be unset, got %v", *vc.CloudFrontDefaultCertificate) + } + if *vc.IAMCertificateId != "iamcert-01234567" { + t.Fatalf("Expected IAMCertificateId to be iamcert-01234567, got %v", *vc.IAMCertificateId) + } + if *vc.SSLSupportMethod != "vip" { + t.Fatalf("Expected IAMCertificateId to be vip, got %v", *vc.SSLSupportMethod) + } + if *vc.MinimumProtocolVersion != "TLSv1" { + t.Fatalf("Expected IAMCertificateId to be TLSv1, got %v", *vc.MinimumProtocolVersion) + } +} + +func TestCloudFrontStructure_falttenViewerCertificate_iam_certificate_id(t *testing.T) { + in := viewerCertificateConfSetIAM() + vc := expandViewerCertificate(in) + out := flattenViewerCertificate(vc) + diff := schema.NewSet(viewerCertificateHash, []interface{}{in}).Difference(out) + + if len(diff.List()) > 0 { + t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff) + } +} diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index ba4aaf44be13..72bed10b2e6d 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -111,123 +111,124 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "aws_ami": resourceAwsAmi(), - "aws_ami_copy": resourceAwsAmiCopy(), - "aws_ami_from_instance": resourceAwsAmiFromInstance(), - "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), - "aws_autoscaling_group": resourceAwsAutoscalingGroup(), - "aws_autoscaling_notification": resourceAwsAutoscalingNotification(), - "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), - "aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(), - "aws_cloudformation_stack": resourceAwsCloudFormationStack(), - "aws_cloudfront_web_distribution": resourceAwsCloudFrontWebDistribution(), - "aws_cloudtrail": resourceAwsCloudTrail(), - "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), - "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), - "aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(), - "aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(), - "aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(), - "aws_codedeploy_app": resourceAwsCodeDeployApp(), - "aws_codedeploy_deployment_group": resourceAwsCodeDeployDeploymentGroup(), - "aws_codecommit_repository": resourceAwsCodeCommitRepository(), - "aws_customer_gateway": resourceAwsCustomerGateway(), - "aws_db_instance": resourceAwsDbInstance(), - "aws_db_parameter_group": resourceAwsDbParameterGroup(), - "aws_db_security_group": resourceAwsDbSecurityGroup(), - "aws_db_subnet_group": resourceAwsDbSubnetGroup(), - "aws_directory_service_directory": resourceAwsDirectoryServiceDirectory(), - "aws_dynamodb_table": resourceAwsDynamoDbTable(), - "aws_ebs_volume": resourceAwsEbsVolume(), - "aws_ecr_repository": resourceAwsEcrRepository(), - "aws_ecr_repository_policy": resourceAwsEcrRepositoryPolicy(), - "aws_ecs_cluster": resourceAwsEcsCluster(), - "aws_ecs_service": resourceAwsEcsService(), - "aws_ecs_task_definition": resourceAwsEcsTaskDefinition(), - "aws_efs_file_system": resourceAwsEfsFileSystem(), - "aws_efs_mount_target": resourceAwsEfsMountTarget(), - "aws_eip": resourceAwsEip(), - "aws_elasticache_cluster": resourceAwsElasticacheCluster(), - "aws_elasticache_parameter_group": resourceAwsElasticacheParameterGroup(), - "aws_elasticache_security_group": resourceAwsElasticacheSecurityGroup(), - "aws_elasticache_subnet_group": resourceAwsElasticacheSubnetGroup(), - "aws_elasticsearch_domain": resourceAwsElasticSearchDomain(), - "aws_elb": resourceAwsElb(), - "aws_flow_log": resourceAwsFlowLog(), - "aws_glacier_vault": resourceAwsGlacierVault(), - "aws_iam_access_key": resourceAwsIamAccessKey(), - "aws_iam_group_policy": resourceAwsIamGroupPolicy(), - "aws_iam_group": resourceAwsIamGroup(), - "aws_iam_group_membership": resourceAwsIamGroupMembership(), - "aws_iam_instance_profile": resourceAwsIamInstanceProfile(), - "aws_iam_policy": resourceAwsIamPolicy(), - "aws_iam_policy_attachment": resourceAwsIamPolicyAttachment(), - "aws_iam_role_policy": resourceAwsIamRolePolicy(), - "aws_iam_role": resourceAwsIamRole(), - "aws_iam_saml_provider": resourceAwsIamSamlProvider(), - "aws_iam_server_certificate": resourceAwsIAMServerCertificate(), - "aws_iam_user_policy": resourceAwsIamUserPolicy(), - "aws_iam_user": resourceAwsIamUser(), - "aws_instance": resourceAwsInstance(), - "aws_internet_gateway": resourceAwsInternetGateway(), - "aws_key_pair": resourceAwsKeyPair(), - "aws_kinesis_firehose_delivery_stream": resourceAwsKinesisFirehoseDeliveryStream(), - "aws_kinesis_stream": resourceAwsKinesisStream(), - "aws_lambda_function": resourceAwsLambdaFunction(), - "aws_lambda_event_source_mapping": resourceAwsLambdaEventSourceMapping(), - "aws_lambda_alias": resourceAwsLambdaAlias(), - "aws_lambda_permission": resourceAwsLambdaPermission(), - "aws_launch_configuration": resourceAwsLaunchConfiguration(), - "aws_lb_cookie_stickiness_policy": resourceAwsLBCookieStickinessPolicy(), - "aws_main_route_table_association": resourceAwsMainRouteTableAssociation(), - "aws_nat_gateway": resourceAwsNatGateway(), - "aws_network_acl": resourceAwsNetworkAcl(), - "aws_network_acl_rule": resourceAwsNetworkAclRule(), - "aws_network_interface": resourceAwsNetworkInterface(), - "aws_opsworks_stack": resourceAwsOpsworksStack(), - "aws_opsworks_java_app_layer": resourceAwsOpsworksJavaAppLayer(), - "aws_opsworks_haproxy_layer": resourceAwsOpsworksHaproxyLayer(), - "aws_opsworks_static_web_layer": resourceAwsOpsworksStaticWebLayer(), - "aws_opsworks_php_app_layer": resourceAwsOpsworksPhpAppLayer(), - "aws_opsworks_rails_app_layer": resourceAwsOpsworksRailsAppLayer(), - "aws_opsworks_nodejs_app_layer": resourceAwsOpsworksNodejsAppLayer(), - "aws_opsworks_memcached_layer": resourceAwsOpsworksMemcachedLayer(), - "aws_opsworks_mysql_layer": resourceAwsOpsworksMysqlLayer(), - "aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(), - "aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(), - "aws_placement_group": resourceAwsPlacementGroup(), - "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), - "aws_rds_cluster": resourceAwsRDSCluster(), - "aws_rds_cluster_instance": resourceAwsRDSClusterInstance(), - "aws_redshift_cluster": resourceAwsRedshiftCluster(), - "aws_redshift_security_group": resourceAwsRedshiftSecurityGroup(), - "aws_redshift_parameter_group": resourceAwsRedshiftParameterGroup(), - "aws_redshift_subnet_group": resourceAwsRedshiftSubnetGroup(), - "aws_route53_delegation_set": resourceAwsRoute53DelegationSet(), - "aws_route53_record": resourceAwsRoute53Record(), - "aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(), - "aws_route53_zone": resourceAwsRoute53Zone(), - "aws_route53_health_check": resourceAwsRoute53HealthCheck(), - "aws_route": resourceAwsRoute(), - "aws_route_table": resourceAwsRouteTable(), - "aws_route_table_association": resourceAwsRouteTableAssociation(), - "aws_s3_bucket": resourceAwsS3Bucket(), - "aws_s3_bucket_object": resourceAwsS3BucketObject(), - "aws_security_group": resourceAwsSecurityGroup(), - "aws_security_group_rule": resourceAwsSecurityGroupRule(), - "aws_spot_instance_request": resourceAwsSpotInstanceRequest(), - "aws_sqs_queue": resourceAwsSqsQueue(), - "aws_sns_topic": resourceAwsSnsTopic(), - "aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(), - "aws_subnet": resourceAwsSubnet(), - "aws_volume_attachment": resourceAwsVolumeAttachment(), - "aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(), - "aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(), - "aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(), - "aws_vpc": resourceAwsVpc(), - "aws_vpc_endpoint": resourceAwsVpcEndpoint(), - "aws_vpn_connection": resourceAwsVpnConnection(), - "aws_vpn_connection_route": resourceAwsVpnConnectionRoute(), - "aws_vpn_gateway": resourceAwsVpnGateway(), + "aws_ami": resourceAwsAmi(), + "aws_ami_copy": resourceAwsAmiCopy(), + "aws_ami_from_instance": resourceAwsAmiFromInstance(), + "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), + "aws_autoscaling_group": resourceAwsAutoscalingGroup(), + "aws_autoscaling_notification": resourceAwsAutoscalingNotification(), + "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), + "aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(), + "aws_cloudformation_stack": resourceAwsCloudFormationStack(), + "aws_cloudfront_distribution": resourceAwsCloudFrontDistribution(), + "aws_cloudfront_origin_access_identity": resourceAwsCloudFrontOriginAccessIdentity(), + "aws_cloudtrail": resourceAwsCloudTrail(), + "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), + "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), + "aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(), + "aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(), + "aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(), + "aws_codedeploy_app": resourceAwsCodeDeployApp(), + "aws_codedeploy_deployment_group": resourceAwsCodeDeployDeploymentGroup(), + "aws_codecommit_repository": resourceAwsCodeCommitRepository(), + "aws_customer_gateway": resourceAwsCustomerGateway(), + "aws_db_instance": resourceAwsDbInstance(), + "aws_db_parameter_group": resourceAwsDbParameterGroup(), + "aws_db_security_group": resourceAwsDbSecurityGroup(), + "aws_db_subnet_group": resourceAwsDbSubnetGroup(), + "aws_directory_service_directory": resourceAwsDirectoryServiceDirectory(), + "aws_dynamodb_table": resourceAwsDynamoDbTable(), + "aws_ebs_volume": resourceAwsEbsVolume(), + "aws_ecr_repository": resourceAwsEcrRepository(), + "aws_ecr_repository_policy": resourceAwsEcrRepositoryPolicy(), + "aws_ecs_cluster": resourceAwsEcsCluster(), + "aws_ecs_service": resourceAwsEcsService(), + "aws_ecs_task_definition": resourceAwsEcsTaskDefinition(), + "aws_efs_file_system": resourceAwsEfsFileSystem(), + "aws_efs_mount_target": resourceAwsEfsMountTarget(), + "aws_eip": resourceAwsEip(), + "aws_elasticache_cluster": resourceAwsElasticacheCluster(), + "aws_elasticache_parameter_group": resourceAwsElasticacheParameterGroup(), + "aws_elasticache_security_group": resourceAwsElasticacheSecurityGroup(), + "aws_elasticache_subnet_group": resourceAwsElasticacheSubnetGroup(), + "aws_elasticsearch_domain": resourceAwsElasticSearchDomain(), + "aws_elb": resourceAwsElb(), + "aws_flow_log": resourceAwsFlowLog(), + "aws_glacier_vault": resourceAwsGlacierVault(), + "aws_iam_access_key": resourceAwsIamAccessKey(), + "aws_iam_group_policy": resourceAwsIamGroupPolicy(), + "aws_iam_group": resourceAwsIamGroup(), + "aws_iam_group_membership": resourceAwsIamGroupMembership(), + "aws_iam_instance_profile": resourceAwsIamInstanceProfile(), + "aws_iam_policy": resourceAwsIamPolicy(), + "aws_iam_policy_attachment": resourceAwsIamPolicyAttachment(), + "aws_iam_role_policy": resourceAwsIamRolePolicy(), + "aws_iam_role": resourceAwsIamRole(), + "aws_iam_saml_provider": resourceAwsIamSamlProvider(), + "aws_iam_server_certificate": resourceAwsIAMServerCertificate(), + "aws_iam_user_policy": resourceAwsIamUserPolicy(), + "aws_iam_user": resourceAwsIamUser(), + "aws_instance": resourceAwsInstance(), + "aws_internet_gateway": resourceAwsInternetGateway(), + "aws_key_pair": resourceAwsKeyPair(), + "aws_kinesis_firehose_delivery_stream": resourceAwsKinesisFirehoseDeliveryStream(), + "aws_kinesis_stream": resourceAwsKinesisStream(), + "aws_lambda_function": resourceAwsLambdaFunction(), + "aws_lambda_event_source_mapping": resourceAwsLambdaEventSourceMapping(), + "aws_lambda_alias": resourceAwsLambdaAlias(), + "aws_lambda_permission": resourceAwsLambdaPermission(), + "aws_launch_configuration": resourceAwsLaunchConfiguration(), + "aws_lb_cookie_stickiness_policy": resourceAwsLBCookieStickinessPolicy(), + "aws_main_route_table_association": resourceAwsMainRouteTableAssociation(), + "aws_nat_gateway": resourceAwsNatGateway(), + "aws_network_acl": resourceAwsNetworkAcl(), + "aws_network_acl_rule": resourceAwsNetworkAclRule(), + "aws_network_interface": resourceAwsNetworkInterface(), + "aws_opsworks_stack": resourceAwsOpsworksStack(), + "aws_opsworks_java_app_layer": resourceAwsOpsworksJavaAppLayer(), + "aws_opsworks_haproxy_layer": resourceAwsOpsworksHaproxyLayer(), + "aws_opsworks_static_web_layer": resourceAwsOpsworksStaticWebLayer(), + "aws_opsworks_php_app_layer": resourceAwsOpsworksPhpAppLayer(), + "aws_opsworks_rails_app_layer": resourceAwsOpsworksRailsAppLayer(), + "aws_opsworks_nodejs_app_layer": resourceAwsOpsworksNodejsAppLayer(), + "aws_opsworks_memcached_layer": resourceAwsOpsworksMemcachedLayer(), + "aws_opsworks_mysql_layer": resourceAwsOpsworksMysqlLayer(), + "aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(), + "aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(), + "aws_placement_group": resourceAwsPlacementGroup(), + "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), + "aws_rds_cluster": resourceAwsRDSCluster(), + "aws_rds_cluster_instance": resourceAwsRDSClusterInstance(), + "aws_redshift_cluster": resourceAwsRedshiftCluster(), + "aws_redshift_security_group": resourceAwsRedshiftSecurityGroup(), + "aws_redshift_parameter_group": resourceAwsRedshiftParameterGroup(), + "aws_redshift_subnet_group": resourceAwsRedshiftSubnetGroup(), + "aws_route53_delegation_set": resourceAwsRoute53DelegationSet(), + "aws_route53_record": resourceAwsRoute53Record(), + "aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(), + "aws_route53_zone": resourceAwsRoute53Zone(), + "aws_route53_health_check": resourceAwsRoute53HealthCheck(), + "aws_route": resourceAwsRoute(), + "aws_route_table": resourceAwsRouteTable(), + "aws_route_table_association": resourceAwsRouteTableAssociation(), + "aws_s3_bucket": resourceAwsS3Bucket(), + "aws_s3_bucket_object": resourceAwsS3BucketObject(), + "aws_security_group": resourceAwsSecurityGroup(), + "aws_security_group_rule": resourceAwsSecurityGroupRule(), + "aws_spot_instance_request": resourceAwsSpotInstanceRequest(), + "aws_sqs_queue": resourceAwsSqsQueue(), + "aws_sns_topic": resourceAwsSnsTopic(), + "aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(), + "aws_subnet": resourceAwsSubnet(), + "aws_volume_attachment": resourceAwsVolumeAttachment(), + "aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(), + "aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(), + "aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(), + "aws_vpc": resourceAwsVpc(), + "aws_vpc_endpoint": resourceAwsVpcEndpoint(), + "aws_vpn_connection": resourceAwsVpnConnection(), + "aws_vpn_connection_route": resourceAwsVpnConnectionRoute(), + "aws_vpn_gateway": resourceAwsVpnGateway(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/aws/resource_aws_cloudfront_distribution.go b/builtin/providers/aws/resource_aws_cloudfront_distribution.go new file mode 100644 index 000000000000..6edb7046605e --- /dev/null +++ b/builtin/providers/aws/resource_aws_cloudfront_distribution.go @@ -0,0 +1,578 @@ +package aws + +import ( + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsCloudFrontDistribution() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudFrontDistributionCreate, + Read: resourceAwsCloudFrontDistributionRead, + Update: resourceAwsCloudFrontDistributionUpdate, + Delete: resourceAwsCloudFrontDistributionDelete, + + Schema: map[string]*schema.Schema{ + "aliases": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: aliasesHash, + }, + "cache_behavior": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: cacheBehaviorHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_methods": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "cached_methods": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "compress": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "default_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "forwarded_values": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: forwardedValuesHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookies": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: cookiePreferenceHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "forward": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "whitelisted_names": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "headers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "query_string": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + "max_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "min_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "path_pattern": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "smooth_streaming": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + }, + "target_origin_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "trusted_signers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "viewer_protocol_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "comment": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "custom_error_response": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: customErrorResponseHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "error_caching_min_ttl": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "error_code": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "response_code": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "response_page_path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "default_cache_behavior": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: defaultCacheBehaviorHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_methods": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "cached_methods": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "compress": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "default_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "forwarded_values": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: forwardedValuesHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookies": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: cookiePreferenceHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "forward": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "whitelisted_names": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "headers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "query_string": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + "max_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "min_ttl": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "smooth_streaming": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + }, + "target_origin_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "trusted_signers": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "viewer_protocol_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "default_root_object": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + }, + "logging_config": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: loggingConfigHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "include_cookies": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "prefix": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + }, + }, + }, + }, + "origin": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: originHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_origin_config": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"origin.s3_origin_config"}, + Set: customOriginConfigHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "https_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "origin_protocol_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "origin_ssl_protocols": &schema.Schema{ + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "domain_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "custom_header": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: originCustomHeaderHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "origin_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "origin_path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "s3_origin_config": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"origin.custom_origin_config"}, + Set: s3OriginConfigHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "origin_access_identity": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + }, + }, + }, + }, + }, + }, + }, + "price_class": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "restrictions": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: restrictionsHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "geo_restriction": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Set: geoRestrictionHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "locations": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "restriction_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "viewer_certificate": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Set: viewerCertificateHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloudfront_default_certificate": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"viewer_certificate.iam_certificate_id"}, + }, + "iam_certificate_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"viewer_certificate.cloudfront_default_certificate"}, + }, + "minimum_protocol_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "SSLv3", + }, + "ssl_support_method": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "web_acl_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "caller_reference": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "active_trusted_signers": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + "domain_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "last_modified_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "in_progress_validation_batches": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + // retain_on_delete is a non-API attribute that may help facilitate speedy + // deletion of a resoruce. It's mainly here for testing purposes, so + // enable at your own risk. + "retain_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + } +} + +func resourceAwsCloudFrontDistributionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.CreateDistributionInput{ + DistributionConfig: expandDistributionConfig(d), + } + + resp, err := conn.CreateDistribution(params) + if err != nil { + return err + } + d.SetId(*resp.Distribution.Id) + return resourceAwsCloudFrontDistributionRead(d, meta) +} + +func resourceAwsCloudFrontDistributionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.GetDistributionInput{ + Id: aws.String(d.Id()), + } + + resp, err := conn.GetDistribution(params) + if err != nil { + return err + } + + // Update attributes from DistributionConfig + flattenDistributionConfig(d, resp.Distribution.DistributionConfig) + // Update other attributes outside of DistributionConfig + d.SetId(*resp.Distribution.Id) + d.Set("active_trusted_signers", flattenActiveTrustedSigners(resp.Distribution.ActiveTrustedSigners)) + d.Set("status", *resp.Distribution.Status) + d.Set("domain_name", *resp.Distribution.DomainName) + d.Set("last_modified_time", aws.String(resp.Distribution.LastModifiedTime.String())) + d.Set("in_progress_validation_batches", *resp.Distribution.InProgressInvalidationBatches) + d.Set("etag", *resp.ETag) + return nil +} + +func resourceAwsCloudFrontDistributionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.UpdateDistributionInput{ + Id: aws.String(d.Id()), + DistributionConfig: expandDistributionConfig(d), + IfMatch: aws.String(d.Get("etag").(string)), + } + _, err := conn.UpdateDistribution(params) + if err != nil { + return err + } + + return resourceAwsCloudFrontDistributionRead(d, meta) +} + +func resourceAwsCloudFrontDistributionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + + // manually disable the distribution first + d.Set("enabled", false) + err := resourceAwsCloudFrontDistributionUpdate(d, meta) + if err != nil { + return err + } + + // skip delete if retain_on_delete is enabled + if d.Get("retain_on_delete").(bool) { + log.Printf("[WARN] Removing Distribtuion ID %s with retain_on_delete set. Please delete this distribution manually.", d.Id()) + d.SetId("") + return nil + } + + // Distribution needs to be in deployed state again before it can be deleted. + resourceAwsCloudFrontDistributionWaitUntilDeployed(d.Id(), meta) + + // now delete + params := &cloudfront.DeleteDistributionInput{ + Id: aws.String(d.Id()), + IfMatch: aws.String(d.Get("etag").(string)), + } + + _, err = conn.DeleteDistribution(params) + if err != nil { + return err + } + + // Done + d.SetId("") + return nil +} + +// resourceAwsCloudFrontWebDistributionWaitUntilDeployed blocks until the +// distribution is deployed. It currently takes exactly 15 minutes to deploy +// but that might change in the future. +func resourceAwsCloudFrontDistributionWaitUntilDeployed(id string, meta interface{}) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{"InProgress", "Deployed"}, + Target: []string{"Deployed"}, + Refresh: resourceAwsCloudFrontWebDistributionStateRefreshFunc(id, meta), + Timeout: 40 * time.Minute, + MinTimeout: 15 * time.Second, + Delay: 10 * time.Minute, + } + + _, err := stateConf.WaitForState() + return err +} + +// The refresh function for resourceAwsCloudFrontWebDistributionWaitUntilDeployed. +func resourceAwsCloudFrontWebDistributionStateRefreshFunc(id string, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.GetDistributionInput{ + Id: aws.String(id), + } + + resp, err := conn.GetDistribution(params) + if err != nil { + log.Printf("Error on retrieving CloudFront distribution when waiting: %s", err) + return nil, "", err + } + + if resp == nil { + return nil, "", nil + } + + return resp.Distribution, *resp.Distribution.Status, nil + } +} diff --git a/builtin/providers/aws/resource_aws_cloudfront_distribution_test.go b/builtin/providers/aws/resource_aws_cloudfront_distribution_test.go new file mode 100644 index 000000000000..a19f342ab492 --- /dev/null +++ b/builtin/providers/aws/resource_aws_cloudfront_distribution_test.go @@ -0,0 +1,392 @@ +package aws + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSCloudFrontDistribution_S3Origin(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSCloudFrontDistributionS3Config, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExistence( + "aws_cloudfront_distribution.s3_distribution", + ), + ), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_customOrigin(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSCloudFrontDistributionCustomConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExistence( + "aws_cloudfront_distribution.custom_distribution", + ), + ), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_multiOrigin(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSCloudFrontDistributionMultiOriginConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExistence( + "aws_cloudfront_distribution.multi_origin_distribution", + ), + ), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_noLoggingConfig(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSCloudFrontDistributionNoLoggingConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExistence( + "aws_cloudfront_distribution.no_logging_config", + ), + ), + }, + }, + }) +} + +func testAccCheckCloudFrontDistributionDestroy(s *terraform.State) error { + for k, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudfront_distribution" { + continue + } + dist, _ := testAccAuxCloudFrontGetDistributionConfig(s, k) + + if *dist.DistributionConfig.Enabled != false { + return fmt.Errorf("CloudFront distribution should be disabled") + } + } + return nil +} + +func testAccCheckCloudFrontDistributionExistence(cloudFrontResource string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, err := testAccAuxCloudFrontGetDistributionConfig(s, cloudFrontResource) + + return err + } +} + +func testAccAuxCloudFrontGetDistributionConfig(s *terraform.State, cloudFrontResource string) (*cloudfront.Distribution, error) { + cf, ok := s.RootModule().Resources[cloudFrontResource] + if !ok { + return nil, fmt.Errorf("Not found: %s", cloudFrontResource) + } + + if cf.Primary.ID == "" { + return nil, fmt.Errorf("No Id is set") + } + + cloudfrontconn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + + req := &cloudfront.GetDistributionInput{ + Id: aws.String(cf.Primary.ID), + } + + res, err := cloudfrontconn.GetDistribution(req) + if err != nil { + return nil, fmt.Errorf("Error retrieving CloudFront distribution: %s", err) + } + + return res.Distribution, nil +} + +var testAccAWSCloudFrontDistributionS3Config = fmt.Sprintf(` +variable rand_id { + default = %d +} + +resource "aws_s3_bucket" "s3_bucket" { + bucket = "mybucket.${var.rand_id}.s3.amazonaws.com" + acl = "public-read" +} + +resource "aws_cloudfront_distribution" "s3_distribution" { + origin { + domain_name = "${aws_s3_bucket.s3_bucket.id}" + origin_id = "myS3Origin" + s3_origin_config {} + } + enabled = true + comment = "Some comment" + default_root_object = "index.html" + logging_config { + include_cookies = false + bucket = "mylogs.${var.rand_id}.s3.amazonaws.com" + prefix = "myprefix" + } + aliases = [ "mysite.${var.rand_id}.example.com", "yoursite.${var.rand_id}.example.com" ] + default_cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myS3Origin" + forwarded_values { + query_string = false + cookies { + forward = "none" + } + } + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + price_class = "PriceClass_200" + restrictions { + geo_restriction { + restriction_type = "whitelist" + locations = [ "US", "CA", "GB", "DE" ] + } + } + viewer_certificate { + cloudfront_default_certificate = true + } + retain_on_delete = true +} +`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) + +var testAccAWSCloudFrontDistributionCustomConfig = fmt.Sprintf(` +variable rand_id { + default = %d +} + +resource "aws_cloudfront_distribution" "custom_distribution" { + origin { + domain_name = "www.example.com" + origin_id = "myCustomOrigin" + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "http-only" + origin_ssl_protocols = [ "SSLv3", "TLSv1" ] + } + } + enabled = true + comment = "Some comment" + default_root_object = "index.html" + logging_config { + include_cookies = false + bucket = "mylogs.${var.rand_id}.s3.amazonaws.com" + prefix = "myprefix" + } + aliases = [ "mysite.${var.rand_id}.example.com", "*.yoursite.${var.rand_id}.example.com" ] + default_cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myCustomOrigin" + smooth_streaming = false + forwarded_values { + query_string = false + cookies { + forward = "all" + } + } + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + price_class = "PriceClass_200" + restrictions { + geo_restriction { + restriction_type = "whitelist" + locations = [ "US", "CA", "GB", "DE" ] + } + } + viewer_certificate { + cloudfront_default_certificate = true + } + retain_on_delete = true +} +`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) + +var testAccAWSCloudFrontDistributionMultiOriginConfig = fmt.Sprintf(` +variable rand_id { + default = %d +} + +resource "aws_s3_bucket" "s3_bucket" { + bucket = "mybucket.${var.rand_id}.s3.amazonaws.com" + acl = "public-read" +} + +resource "aws_cloudfront_distribution" "multi_origin_distribution" { + origin { + domain_name = "${aws_s3_bucket.s3_bucket.id}" + origin_id = "myS3Origin" + s3_origin_config {} + } + origin { + domain_name = "www.example.com" + origin_id = "myCustomOrigin" + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "http-only" + origin_ssl_protocols = [ "SSLv3", "TLSv1" ] + } + } + enabled = true + comment = "Some comment" + default_root_object = "index.html" + logging_config { + include_cookies = false + bucket = "mylogs.${var.rand_id}.s3.amazonaws.com" + prefix = "myprefix" + } + aliases = [ "mysite.${var.rand_id}.example.com", "*.yoursite.${var.rand_id}.example.com" ] + default_cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myS3Origin" + smooth_streaming = true + forwarded_values { + query_string = false + cookies { + forward = "all" + } + } + min_ttl = 100 + default_ttl = 100 + max_ttl = 100 + viewer_protocol_policy = "allow-all" + } + cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myS3Origin" + forwarded_values { + query_string = true + cookies { + forward = "none" + } + } + min_ttl = 50 + default_ttl = 50 + max_ttl = 50 + viewer_protocol_policy = "allow-all" + path_pattern = "images1/*.jpg" + } + cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myCustomOrigin" + forwarded_values { + query_string = true + cookies { + forward = "none" + } + } + min_ttl = 50 + default_ttl = 50 + max_ttl = 50 + viewer_protocol_policy = "allow-all" + path_pattern = "images2/*.jpg" + } + price_class = "PriceClass_All" + custom_error_response { + error_code = 404 + response_page_path = "/error-pages/404.html" + response_code = 200 + error_caching_min_ttl = 30 + } + restrictions { + geo_restriction { + restriction_type = "none" + } + } + viewer_certificate { + cloudfront_default_certificate = true + } + retain_on_delete = true +} +`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) + +var testAccAWSCloudFrontDistributionNoLoggingConfig = fmt.Sprintf(` +variable rand_id { + default = %d +} + +resource "aws_cloudfront_distribution" "no_logging_config" { + origin { + domain_name = "www.example.com" + origin_id = "myCustomOrigin" + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "http-only" + origin_ssl_protocols = [ "SSLv3", "TLSv1" ] + } + } + enabled = true + comment = "Some comment" + default_root_object = "index.html" + aliases = [ "mysite.${var.rand_id}.example.com", "*.yoursite.${var.rand_id}.example.com" ] + default_cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myCustomOrigin" + smooth_streaming = false + forwarded_values { + query_string = false + cookies { + forward = "all" + } + } + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + price_class = "PriceClass_200" + restrictions { + geo_restriction { + restriction_type = "whitelist" + locations = [ "US", "CA", "GB", "DE" ] + } + } + viewer_certificate { + cloudfront_default_certificate = true + } + retain_on_delete = true +} +`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) diff --git a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go new file mode 100644 index 000000000000..47bb9b15e38b --- /dev/null +++ b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go @@ -0,0 +1,128 @@ +package aws + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsCloudFrontOriginAccessIdentity() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudFrontOriginAccessIdentityCreate, + Read: resourceAwsCloudFrontOriginAccessIdentityRead, + Update: resourceAwsCloudFrontOriginAccessIdentityUpdate, + Delete: resourceAwsCloudFrontOriginAccessIdentityDelete, + + Schema: map[string]*schema.Schema{ + "comment": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + }, + "caller_reference": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "cloudfront_access_identity_path": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "s3_canonical_user_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsCloudFrontOriginAccessIdentityCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.CreateCloudFrontOriginAccessIdentityInput{ + CloudFrontOriginAccessIdentityConfig: expandOriginAccessIdentityConfig(d), + } + + resp, err := conn.CreateCloudFrontOriginAccessIdentity(params) + if err != nil { + return err + } + d.SetId(*resp.CloudFrontOriginAccessIdentity.Id) + return resourceAwsCloudFrontOriginAccessIdentityRead(d, meta) +} + +func resourceAwsCloudFrontOriginAccessIdentityRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.GetCloudFrontOriginAccessIdentityInput{ + Id: aws.String(d.Id()), + } + + resp, err := conn.GetCloudFrontOriginAccessIdentity(params) + if err != nil { + return err + } + + // Update attributes from DistributionConfig + flattenOriginAccessIdentityConfig(d, resp.CloudFrontOriginAccessIdentity.CloudFrontOriginAccessIdentityConfig) + // Update other attributes outside of DistributionConfig + d.SetId(*resp.CloudFrontOriginAccessIdentity.Id) + d.Set("etag", *resp.ETag) + d.Set("s3_canonical_user_id", *resp.CloudFrontOriginAccessIdentity.S3CanonicalUserId) + d.Set("cloudfront_access_identity_path", fmt.Sprintf("origin-access-identity/cloudfront/%s", *resp.CloudFrontOriginAccessIdentity.Id)) + return nil +} + +func resourceAwsCloudFrontOriginAccessIdentityUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.UpdateCloudFrontOriginAccessIdentityInput{ + Id: aws.String(d.Id()), + CloudFrontOriginAccessIdentityConfig: expandOriginAccessIdentityConfig(d), + IfMatch: aws.String(d.Get("etag").(string)), + } + _, err := conn.UpdateCloudFrontOriginAccessIdentity(params) + if err != nil { + return err + } + + return resourceAwsCloudFrontOriginAccessIdentityRead(d, meta) +} + +func resourceAwsCloudFrontOriginAccessIdentityDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + params := &cloudfront.DeleteCloudFrontOriginAccessIdentityInput{ + Id: aws.String(d.Id()), + IfMatch: aws.String(d.Get("etag").(string)), + } + + _, err := conn.DeleteCloudFrontOriginAccessIdentity(params) + if err != nil { + return err + } + + // Done + d.SetId("") + return nil +} + +func expandOriginAccessIdentityConfig(d *schema.ResourceData) *cloudfront.OriginAccessIdentityConfig { + originAccessIdentityConfig := &cloudfront.OriginAccessIdentityConfig{ + Comment: aws.String(d.Get("comment").(string)), + } + // This sets CallerReference if it's still pending computation (ie: new resource) + if v, ok := d.GetOk("caller_reference"); ok == false { + originAccessIdentityConfig.CallerReference = aws.String(time.Now().Format(time.RFC3339Nano)) + } else { + originAccessIdentityConfig.CallerReference = aws.String(v.(string)) + } + return originAccessIdentityConfig +} + +func flattenOriginAccessIdentityConfig(d *schema.ResourceData, originAccessIdentityConfig *cloudfront.OriginAccessIdentityConfig) { + d.Set("comment", *originAccessIdentityConfig.Comment) + d.Set("caller_reference", *originAccessIdentityConfig.CallerReference) +} diff --git a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go new file mode 100644 index 000000000000..e6c525e4e3ce --- /dev/null +++ b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go @@ -0,0 +1,89 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSCloudFrontOriginAccessIdentity_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontOriginAccessIdentityDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSCloudFrontOriginAccessIdentityConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontOriginAccessIdentityExistence("aws_cloudfront_origin_access_identity.origin_access_identity"), + resource.TestCheckResourceAttr("aws_cloudfront_origin_access_identity.origin_access_identity", "comment", "some comment"), + resource.TestMatchResourceAttr("aws_cloudfront_origin_access_identity.origin_access_identity", + "caller_reference", + regexp.MustCompile("^20[0-9]{2}.*")), + resource.TestMatchResourceAttr("aws_cloudfront_origin_access_identity.origin_access_identity", + "s3_canonical_user_id", + regexp.MustCompile("^[a-z0-9]+")), + resource.TestMatchResourceAttr("aws_cloudfront_origin_access_identity.origin_access_identity", + "cloudfront_access_identity_path", + regexp.MustCompile("^origin-access-identity/cloudfront/[A-Z0-9]+")), + ), + }, + }, + }) +} + +func testAccCheckCloudFrontOriginAccessIdentityDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudfront_origin_access_identity" { + continue + } + + params := &cloudfront.GetCloudFrontOriginAccessIdentityInput{ + Id: aws.String(rs.Primary.ID), + } + + _, err := conn.GetCloudFrontOriginAccessIdentity(params) + if err == nil { + return fmt.Errorf("CloudFront origin access identity was not deleted") + } + } + + return nil +} + +func testAccCheckCloudFrontOriginAccessIdentityExistence(r string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[r] + if !ok { + return fmt.Errorf("Not found: %s", r) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Id is set") + } + + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + + params := &cloudfront.GetCloudFrontOriginAccessIdentityInput{ + Id: aws.String(rs.Primary.ID), + } + + _, err := conn.GetCloudFrontOriginAccessIdentity(params) + if err != nil { + return fmt.Errorf("Error retrieving CloudFront distribution: %s", err) + } + return nil + } +} + +const testAccAWSCloudFrontOriginAccessIdentityConfig = ` +resource "aws_cloudfront_origin_access_identity" "origin_access_identity" { + comment = "some comment" +} +` diff --git a/builtin/providers/aws/resource_aws_cloudfront_web_distribution.go b/builtin/providers/aws/resource_aws_cloudfront_web_distribution.go deleted file mode 100644 index 0b0fb9b567f2..000000000000 --- a/builtin/providers/aws/resource_aws_cloudfront_web_distribution.go +++ /dev/null @@ -1,587 +0,0 @@ -package aws - -import ( - "fmt" - "log" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/cloudfront" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/helper/schema" -) - -func resourceAwsCloudFrontWebDistribution() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsCloudFrontWebDistributionCreate, - Read: resourceAwsCloudFrontWebDistributionRead, - Update: resourceAwsCloudFrontWebDistributionUpdate, - Delete: resourceAwsCloudFrontWebDistributionDelete, - - Schema: map[string]*schema.Schema{ - "origin_domain_name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - - "origin_http_port": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Default: 80, - }, - - "origin_https_port": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Default: 443, - }, - - "origin_protocol_policy": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "http-only", - }, - - "origin_path": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", - }, - - "enabled": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - - "comment": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - - "price_class": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "PriceClass_All", - }, - - "default_root_object": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - - "domain_name": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "status": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "viewer_protocol_policy": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "allow-all", - }, - - "forward_cookie": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "none", - }, - - "whitelisted_cookies": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - }, - - "forward_query_string": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "minimum_ttl": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Default: 0, - }, - - "maximum_ttl": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Default: 31536000, - }, - - "default_ttl": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - Default: 86400, - }, - - "smooth_streaming": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - }, - - "allowed_methods": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Computed: true, - }, - - "cached_methods": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Computed: true, - }, - - "forwarded_headers": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - }, - - "logging_enabled": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "logging_include_cookies": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "logging_prefix": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - - "logging_bucket": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - - "minimum_ssl": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "SSLv3", - }, - - "certificate_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - }, - - "ssl_support_method": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "vip", - }, - - "aliases": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - }, - - "geo_restriction_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "none", - }, - - "geo_restrictions": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - }, - - "zone_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceAwsCloudFrontWebDistributionCreate(d *schema.ResourceData, meta interface{}) error { - cloudfrontconn := meta.(*AWSClient).cloudfrontconn - - // CloudFront distribution configurations require a unique Caller Reference - callerReference := time.Now().Format(time.RFC3339Nano) - c, err := resourceAwsCloudFrontWebDistributionDistributionConfig(d, meta, &callerReference) - if err != nil { - return err - } - - res, err := cloudfrontconn.CreateDistribution(&cloudfront.CreateDistributionInput{ - DistributionConfig: c, - }) - - if err != nil { - return fmt.Errorf("Error creating CloudFront distribution: %s", err) - } - - d.SetId(*res.Distribution.Id) - - err = resourceAwsCloudFrontWebDistributionWaitUntilDeployed(d, meta) - if err != nil { - return err - } - - return resourceAwsCloudFrontWebDistributionRead(d, meta) -} - -func resourceAwsCloudFrontWebDistributionRead(d *schema.ResourceData, meta interface{}) error { - v, err := resourceAwsCloudFrontWebDistributionDistributionRetrieve(d, meta) - if err != nil { - if cferr, ok := err.(awserr.Error); ok && cferr.Code() == "NoSuchDistribution" { - // Fail quietly if resource no longer exists - d.SetId("") - return nil - } - return err - } - - c := v.Distribution.DistributionConfig - d.Set("enabled", c.Enabled) - d.Set("comment", c.Comment) - d.Set("price_class", c.PriceClass) - d.Set("default_root_object", c.DefaultRootObject) - d.Set("domain_name", v.Distribution.DomainName) - d.Set("status", v.Distribution.Status) - d.Set("viewer_protocol_policy", c.DefaultCacheBehavior.ViewerProtocolPolicy) - d.Set("forward_cookie", c.DefaultCacheBehavior.ForwardedValues.Cookies) - if c.DefaultCacheBehavior.ForwardedValues.Cookies.WhitelistedNames != nil { - d.Set("whitelisted_cookies", resourceAwsCloudFrontCopyItems(c.DefaultCacheBehavior.ForwardedValues.Cookies.WhitelistedNames.Items)) - } - d.Set("forward_query_string", c.DefaultCacheBehavior.ForwardedValues.QueryString) - d.Set("minimum_ttl", c.DefaultCacheBehavior.MinTTL) - d.Set("maximum_ttl", c.DefaultCacheBehavior.MaxTTL) - d.Set("default_ttl", c.DefaultCacheBehavior.DefaultTTL) - d.Set("smooth_streaming", c.DefaultCacheBehavior.SmoothStreaming) - d.Set("allowed_methods", resourceAwsCloudFrontCopyItems(c.DefaultCacheBehavior.AllowedMethods.Items)) - d.Set("cached_methods", resourceAwsCloudFrontCopyItems(c.DefaultCacheBehavior.AllowedMethods.CachedMethods.Items)) - d.Set("forwarded_headers", resourceAwsCloudFrontCopyItems(c.DefaultCacheBehavior.ForwardedValues.Headers.Items)) - d.Set("logging_enabled", c.Logging.Enabled) - d.Set("logging_include_cookies", c.Logging.IncludeCookies) - d.Set("logging_prefix", c.Logging.Prefix) - d.Set("logging_bucket", c.Logging.Bucket) - d.Set("aliases", c.Aliases.Items) - d.Set("geo_restriction_type", c.Restrictions.GeoRestriction.RestrictionType) - d.Set("geo_restrictions", resourceAwsCloudFrontCopyItems(c.Restrictions.GeoRestriction.Items)) - d.Set("zone_id", "Z2FDTNDATAQYW2") - - d.Set("minimum_ssl", c.ViewerCertificate.MinimumProtocolVersion) - d.Set("ssl_support_method", c.ViewerCertificate.SSLSupportMethod) - if *c.ViewerCertificate.CloudFrontDefaultCertificate == true { - d.Set("certificate_id", "") - } else { - d.Set("certificate_id", c.ViewerCertificate.IAMCertificateId) - } - - // CloudFront distributions supports multiple origins. However most of the above - // configuration options also apply to a single origin which would result in - // an overwhelming API - o := c.Origins.Items[0] - d.Set("origin_domain_name", o.DomainName) - d.Set("origin_path", o.OriginPath) - d.Set("origin_http_port", o.CustomOriginConfig.HTTPPort) - d.Set("origin_https_port", o.CustomOriginConfig.HTTPSPort) - d.Set("origin_protocol_policy", o.CustomOriginConfig.OriginProtocolPolicy) - - return nil -} - -func resourceAwsCloudFrontWebDistributionUpdate(d *schema.ResourceData, meta interface{}) error { - cloudfrontconn := meta.(*AWSClient).cloudfrontconn - - // CloudFront configuration changes requires the ETag of the latest changeset - v, err := resourceAwsCloudFrontWebDistributionDistributionRetrieve(d, meta) - if err != nil { - return err - } - - c, err := resourceAwsCloudFrontWebDistributionDistributionConfig(d, meta, v.Distribution.DistributionConfig.CallerReference) - if err != nil { - return err - } - - params := &cloudfront.UpdateDistributionInput{ - DistributionConfig: c, - Id: aws.String(string(d.Id())), - IfMatch: v.ETag, - } - - _, err = cloudfrontconn.UpdateDistribution(params) - - if err != nil { - return fmt.Errorf("Error updating CloudFront distribution: %s", err) - } - - err = resourceAwsCloudFrontWebDistributionWaitUntilDeployed(d, meta) - if err != nil { - return err - } - - return resourceAwsCloudFrontWebDistributionRead(d, meta) -} - -func resourceAwsCloudFrontWebDistributionDelete(d *schema.ResourceData, meta interface{}) error { - cloudfrontconn := meta.(*AWSClient).cloudfrontconn - - v, err := resourceAwsCloudFrontWebDistributionDistributionRetrieve(d, meta) - if err != nil { - return err - } - - // Do nothing if resource no longer exists - if v == nil { - return nil - } - - // CloudFront distributions must be disabled in order to be deleted - if d.Get("enabled") == true { - d.Set("enabled", false) - - err := resourceAwsCloudFrontWebDistributionUpdate(d, meta) - if err != nil { - return err - } - - // Retrieve the latest ETag again - v, err = resourceAwsCloudFrontWebDistributionDistributionRetrieve(d, meta) - if err != nil { - return err - } - } - - params := &cloudfront.DeleteDistributionInput{ - Id: aws.String(string(d.Id())), - IfMatch: v.ETag, - } - - _, err = cloudfrontconn.DeleteDistribution(params) - - if err != nil { - return fmt.Errorf("Error deleting CloudFront distribution: %s", err) - } - - return nil -} - -func resourceAwsCloudFrontWebDistributionDistributionConfig( - d *schema.ResourceData, meta interface{}, - callerReference *string) (*cloudfront.DistributionConfig, error) { - - originId := fmt.Sprintf("%s-origin", d.Get("origin_domain_name")) - aliases := resourceAwsCloudFrontWebDistributionAwsStringLists( - d.Get("aliases")) - geoRestrictions := resourceAwsCloudFrontWebDistributionAwsStringLists( - d.Get("geo_restrictions")) - allowedMethods := resourceAwsCloudFrontWebDistributionHandleMethods( - d.Get("allowed_methods")) - cachedMethods := resourceAwsCloudFrontWebDistributionHandleMethods( - d.Get("cached_methods")) - forwardedHeaders := resourceAwsCloudFrontWebDistributionAwsStringLists( - d.Get("forwarded_headers")) - cookies := resourceAwsCloudFrontWebDistributionCookies( - d.Get("forward_cookie"), d.Get("whitelisted_cookies")) - viewerCertificate := &cloudfront.ViewerCertificate{ - MinimumProtocolVersion: aws.String(d.Get("minimum_ssl").(string)), - SSLSupportMethod: aws.String(d.Get("ssl_support_method").(string)), - } - if d.Get("certificate_id") == "" { - viewerCertificate.CloudFrontDefaultCertificate = aws.Bool(true) - } else { - viewerCertificate.IAMCertificateId = aws.String(d.Get("certificate_id").(string)) - } - - // PUT DistributionConfig requires, unlike POST, EVERY possible option to be set. - // Except for the configurable options, these are the defaults options. - return &cloudfront.DistributionConfig{ - CallerReference: callerReference, - Enabled: aws.Bool(d.Get("enabled").(bool)), - Comment: aws.String(d.Get("comment").(string)), - PriceClass: aws.String(d.Get("price_class").(string)), - DefaultRootObject: aws.String(d.Get("default_root_object").(string)), - Aliases: &cloudfront.Aliases{ - Quantity: aws.Int64(int64(len(aliases))), - Items: aliases, - }, - Origins: &cloudfront.Origins{ - Quantity: aws.Int64(1), - Items: []*cloudfront.Origin{ - &cloudfront.Origin{ - DomainName: aws.String(d.Get("origin_domain_name").(string)), - Id: aws.String(originId), - OriginPath: aws.String(d.Get("origin_path").(string)), - CustomOriginConfig: &cloudfront.CustomOriginConfig{ - HTTPPort: aws.Int64(int64(d.Get("origin_http_port").(int))), - HTTPSPort: aws.Int64(int64(d.Get("origin_https_port").(int))), - OriginProtocolPolicy: aws.String(d.Get("origin_protocol_policy").(string)), - }, - }, - }, - }, - ViewerCertificate: viewerCertificate, - Logging: &cloudfront.LoggingConfig{ - Enabled: aws.Bool(d.Get("logging_enabled").(bool)), - IncludeCookies: aws.Bool(d.Get("logging_include_cookies").(bool)), - Prefix: aws.String(d.Get("logging_prefix").(string)), - Bucket: aws.String(d.Get("logging_bucket").(string)), - }, - Restrictions: &cloudfront.Restrictions{ - GeoRestriction: &cloudfront.GeoRestriction{ - Quantity: aws.Int64(int64(len(geoRestrictions))), - RestrictionType: aws.String(d.Get("geo_restriction_type").(string)), - Items: geoRestrictions, - }, - }, - DefaultCacheBehavior: &cloudfront.DefaultCacheBehavior{ - ForwardedValues: &cloudfront.ForwardedValues{ - Cookies: cookies, - QueryString: aws.Bool(d.Get("forward_query_string").(bool)), - Headers: &cloudfront.Headers{ - Quantity: aws.Int64(int64(len(forwardedHeaders))), - Items: forwardedHeaders, - }, - }, - TargetOriginId: aws.String(originId), - ViewerProtocolPolicy: aws.String(d.Get("viewer_protocol_policy").(string)), - MinTTL: aws.Int64(int64(d.Get("minimum_ttl").(int))), - MaxTTL: aws.Int64(int64(d.Get("maximum_ttl").(int))), - DefaultTTL: aws.Int64(int64(d.Get("default_ttl").(int))), - TrustedSigners: &cloudfront.TrustedSigners{ - Enabled: aws.Bool(false), - Quantity: aws.Int64(0), - }, - SmoothStreaming: aws.Bool(d.Get("smooth_streaming").(bool)), - AllowedMethods: &cloudfront.AllowedMethods{ - Quantity: aws.Int64(int64(len(allowedMethods))), - Items: allowedMethods, - CachedMethods: &cloudfront.CachedMethods{ - Quantity: aws.Int64(int64(len(cachedMethods))), - Items: cachedMethods, - }, - }, - }, - CacheBehaviors: &cloudfront.CacheBehaviors{ - Quantity: aws.Int64(0), - }, - CustomErrorResponses: &cloudfront.CustomErrorResponses{ - Quantity: aws.Int64(0), - }, - }, nil -} - -// resourceAwsCloudFrontWebDistributionWaitUntilDeployed blocks until the -// distribution is deployed. It currently takes exactly 15 minutes to deploy -// but that might change in the future. -func resourceAwsCloudFrontWebDistributionWaitUntilDeployed( - d *schema.ResourceData, meta interface{}) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{"InProgress", "Deployed"}, - Target: "Deployed", - Refresh: resourceAwsCloudFrontWebDistributionStateRefreshFunc(d, meta), - Timeout: 40 * time.Minute, - MinTimeout: 15 * time.Second, - Delay: 10 * time.Minute, - } - - _, err := stateConf.WaitForState() - return err -} - -func resourceAwsCloudFrontWebDistributionStateRefreshFunc( - d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - v, err := resourceAwsCloudFrontWebDistributionDistributionRetrieve(d, meta) - - if err != nil { - log.Printf("Error on retrieving CloudFront distribution when waiting: %s", err) - return nil, "", err - } - - if v == nil { - return nil, "", nil - } - - return v.Distribution, *v.Distribution.Status, nil - } -} - -func resourceAwsCloudFrontWebDistributionDistributionRetrieve( - d *schema.ResourceData, meta interface{}) (*cloudfront.GetDistributionOutput, error) { - cloudfrontconn := meta.(*AWSClient).cloudfrontconn - - req := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } - - res, err := cloudfrontconn.GetDistribution(req) - if err != nil { - return nil, fmt.Errorf("Error retrieving CloudFront distribution: %s", err) - } - - return res, nil -} - -func resourceAwsCloudFrontWebDistributionAwsStringLists(in interface{}) []*string { - list := in.([]interface{}) - out := make([]*string, 0, len(list)) - for _, r := range list { - s := r.(string) - out = append(out, aws.String(s)) - } - return out -} - -func resourceAwsCloudFrontWebDistributionHandleMethods(in interface{}) []*string { - // Terraform schemas does not currently support arrays as default values - if len(in.([]interface{})) == 0 { - return []*string{ - aws.String("GET"), - aws.String("HEAD"), - } - } - - return resourceAwsCloudFrontWebDistributionAwsStringLists(in) -} - -func resourceAwsCloudFrontWebDistributionCookies(a, b interface{}) *cloudfront.CookiePreference { - forwardCookie := a.(string) - - if forwardCookie != "whitelist" { - return &cloudfront.CookiePreference{ - Forward: aws.String(forwardCookie), - } - } - - whitelist := resourceAwsCloudFrontWebDistributionAwsStringLists(b) - - return &cloudfront.CookiePreference{ - Forward: aws.String(forwardCookie), - WhitelistedNames: &cloudfront.CookieNames{ - Quantity: aws.Int64(int64(len(whitelist))), - Items: whitelist, - }, - } -} - -func resourceAwsCloudFrontCopyItems(d []*string) []string { - list := make([]string, 0, len(d)) - for _, item := range d { - list = append(list, *item) - } - return list -} diff --git a/builtin/providers/aws/resource_aws_cloudfront_web_distribution_test.go b/builtin/providers/aws/resource_aws_cloudfront_web_distribution_test.go deleted file mode 100644 index d4810d449ca7..000000000000 --- a/builtin/providers/aws/resource_aws_cloudfront_web_distribution_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package aws - -import ( - "fmt" - "math/rand" - "testing" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudfront" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" -) - -func TestAccAWSCloudFront_basic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCloudFrontDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccAWSCloudFrontConfig, - Check: resource.ComposeTestCheckFunc( - testAccCheckCloudfrontExistance( - "aws_cloudfront_web_distribution.main", - ), - ), - }, - resource.TestStep{ - Config: testAccAWSCloudFrontUpdate, - Check: resource.ComposeTestCheckFunc( - testAccCheckCloudfrontExistance( - "aws_cloudfront_web_distribution.main", - ), - testAccCheckCloudfrontCheckDistributionDisabled( - "aws_cloudfront_web_distribution.main", - ), - testAccCheckCloudfrontCheckDistributionAlias( - "aws_cloudfront_web_distribution.main", - ), - ), - }, - }, - }) -} - -func testAccCheckCloudFrontDestroy(s *terraform.State) error { - if len(s.RootModule().Resources) > 0 { - return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources) - } - - return nil -} - -func testAccCheckCloudfrontExistance(cloudFrontResource string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _, err := testAccAuxCloudfrontGetDistributionConfig(s, cloudFrontResource) - - return err - } -} - -func testAccCheckCloudfrontCheckDistributionDisabled(cloudFrontResource string) resource.TestCheckFunc { - return func(s *terraform.State) error { - dist, _ := testAccAuxCloudfrontGetDistributionConfig(s, cloudFrontResource) - - if *dist.DistributionConfig.Enabled != false { - return fmt.Errorf("CloudFront distribution should be disabled") - } - - return nil - } -} - -func testAccCheckCloudfrontCheckDistributionAlias(cloudFrontResource string) resource.TestCheckFunc { - return func(s *terraform.State) error { - dist, _ := testAccAuxCloudfrontGetDistributionConfig(s, cloudFrontResource) - - if len(dist.DistributionConfig.Aliases.Items) != 1 { - return fmt.Errorf("CloudFront failed updating aliases") - } - - return nil - } -} - -func testAccAuxCloudfrontGetDistributionConfig(s *terraform.State, cloudFrontResource string) (*cloudfront.Distribution, error) { - cf, ok := s.RootModule().Resources[cloudFrontResource] - if !ok { - return nil, fmt.Errorf("Not found: %s", cloudFrontResource) - } - - if cf.Primary.ID == "" { - return nil, fmt.Errorf("No Id is set") - } - - cloudfrontconn := testAccProvider.Meta().(*AWSClient).cloudfrontconn - - req := &cloudfront.GetDistributionInput{ - Id: aws.String(cf.Primary.ID), - } - - res, err := cloudfrontconn.GetDistribution(req) - if err != nil { - return nil, fmt.Errorf("Error retrieving CloudFront distribution: %s", err) - } - - return res.Distribution, nil -} - -const testAccAWSCloudFrontConfig = ` -resource "aws_cloudfront_web_distribution" "main" { - origin_domain_name = "fileserver.example.com" -} -` - -// CloudFront does not allow CNAME conflicts on the same account -var testAccAWSCloudFrontUpdate = fmt.Sprintf(` -resource "aws_cloudfront_web_distribution" "main" { - enabled = false - origin_domain_name = "fileserver.example.com" - aliases = ["static-%d.example.com"] -} -`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index dd22d83c90d0..b4faaa381b67 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -766,3 +766,23 @@ func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string } return outputs } + +// There are several parts of the AWS API that will sort lists of strings, +// causing diffs inbetweeen resources that use lists. This avoids a bit of +// code duplication for pre-sorts that can be used for things like hash +// functions, etc. +func sortInterfaceSlice(in []interface{}) []interface{} { + a := []string{} + b := []interface{}{} + for _, v := range in { + a = append(a, v.(string)) + } + + sort.Strings(a) + + for _, v := range a { + b = append(b, v) + } + + return b +} diff --git a/website/source/docs/providers/aws/r/cloudfront_distribution.html.markdown b/website/source/docs/providers/aws/r/cloudfront_distribution.html.markdown new file mode 100644 index 000000000000..ffc64afac1b1 --- /dev/null +++ b/website/source/docs/providers/aws/r/cloudfront_distribution.html.markdown @@ -0,0 +1,195 @@ +--- +layout: "aws" +page_title: "AWS: cloudfront_distribution" +sidebar_current: "docs-aws-resource-cloudfront-distribution" +description: |- + Provides a CloudFront web distribution resource. +--- + +# aws\_cloudfront\_distribution + +Creates an Amazon CloudFront web distribution. + +For information about CloudFront distributions, see the +[Amazon CloudFront Developer Guide][1]. For specific information about creating +CloudFront web distributions, see the [POST Distribution][2] page in the Amazon +CloudFront API Reference. + +~> **NOTE:** CloudFront distributions take about 15 minutes to a deployed state +after creation or modification. During this time, deletes to resources will be +blocked. If you need to delete a distribution that is enabled and you do not +want to wait, you need to use the `retain_on_delete` flag. + +## Example Usage + +The following example below creates a CloudFront distribution with an S3 origin. + +``` +resource "aws_cloudfront_distribution" "s3_distribution" { + origin { + domain_name = "mybucket.s3.amazonaws.com" + origin_id = "myS3Origin" + s3_origin_config { + origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567" + } + } + enabled = true + comment = "Some comment" + default_root_object = "index.html" + logging_config { + include_cookies = false + bucket = "mylogs.s3.amazonaws.com" + prefix = "myprefix" + } + aliases = [ "mysite.example.com", "yoursite.example.com" ] + default_cache_behavior { + allowed_methods = [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ] + cached_methods = [ "GET", "HEAD" ] + target_origin_id = "myS3Origin" + forwarded_values { + query_string = false + cookies { + forward = "none" + } + } + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + price_class = "PriceClass_200" + restrictions { + geo_restriction { + restriction_type = "whitelist" + locations = [ "US", "CA", "GB", "DE" ] + } + } + viewer_certificate { + cloudfront_default_certificate = true + } +} +``` + +## Argument Reference + +The CloudFront distribution argument layout is a complex structure composed +of several sub-resources - these resources are laid out below. + +### Top-Level Arguments + +* `aliases` (Optional) - Extra CNAMEs (alternate domain names), if any, for this distribution. +* `cache_behavior` (Optional) - A [cache behavior](#cache_behavior) resource for this distribution (multiples allowed). +* `comment` (Optional) - Any comments you want to include about the distribution. +* `custom_error_response` (Optional) - One or more [custom error response](#custom_error_response) elements (multiples allowed). +* `default_cache_behavior` (Required) - The [default cache behavior](#default_cache_behavior) for this distribution (maximum one). +* `default_root_object` (Optional) - The object that you want CloudFront to return (for example, index.html) when an end user requests the root URL. +* `enabled` (Required) - Whether the distribution is enabled to accept end user requests for content. +* `logging_config` (Optional) - The [logging configuration](#logging_config) that controls how logs are written to your distribution (maximum one). +* `origin` (Required) - One or more [origins](#origin) for this distribution (multiples allowed). +* `price_class` (Optional) - The price class for this distribution. +* `restrictions` (Required) - The [restriction configuration](#restrictions) for this distribution (maximum one). +* `viewer_certificate` (Optional) - The [SSL configuration](#viewer_certificate) for this distribution (maximum one). +* `web_acl_id` (Optional) - If you're using AWS WAF to filter CloudFront requests, the Id of the AWS WAF web ACL that is associated with the distribution. +* `retain_on_delete` (Optional) - Disables the distribution instead of deleting it when destroying the resource through Terraform. If this is set, the distribution needs to be deleted manually afterwards. Default: `false`. + +#### `cache_behavior` Arguments + +* `allowed_methods` (Required) - Controls which HTTP methods CloudFront processes and forwards to your Amazon S3 bucket or your custom origin. +* `cached_methods` (Required) - Controls whether CloudFront caches the response to requests using the specified HTTP methods. +* `compress` (Optional) - Whether you want CloudFront to automatically compress content for web requests that include `Accept-Encoding: gzip` in the request header (default: `false`). +* `default_ttl` (Required) - The default amount of time (in seconds) that an object is in a CloudFront cache before CloudFront forwards another request in the absence of an `Cache-Control max-age` or `Expires` header. +* `forwarded_values` (Required) - The [forwarded values configuration](#forwarded_values) that specifies how CloudFront handles query strings, cookies and headers (maximum one). +* `max_ttl` (Required) - The maximum amount of time (in seconds) that an object is in a CloudFront cache before CloudFront forwards another request to your origin to determine whether the object has been updated. Only effective in the presence of `Cache-Control max-age`, `Cache-Control s-maxage`, and `Expires` headers. +* `min_ttl` (Required) - The minimum amount of time that you want objects to stay in CloudFront caches before CloudFront queries your origin to see whether the object has been updated. +* `path_pattern` (Required) - The pattern (for example, `images/*.jpg)` that specifies which requests you want this cache behavior to apply to. +* `smooth_streaming` (Optional) - Indicates whether you want to distribute media files in Microsoft Smooth Streaming format using the origin that is associated with this cache behavior. +* `target_origin_id` (Required) - The value of ID for the origin that you want CloudFront to route requests to when a request matches the path pattern either for a cache behavior or for the default cache behavior. +* `trusted_signers` (Optional) - The AWS accounts, if any, that you want to allow to create signed URLs for private content. +* `viewer_protocol_policy` (Required) - Use this element to specify the protocol that users can use to access the files in the origin specified by TargetOriginId when a request matches the path pattern in PathPattern. One of `allow-all`, `https-only`, or `redirect-to-https`. + +##### `forwarded_values` Arguments + +* `cookies` (Optional) - The [forwarded values cookies](#cookies) that specifies how CloudFront handles cookies (maximum one). +* `headers` (Optional) - Specifies the Headers, if any, that you want CloudFront to vary upon for this cache behavior. +* `query_string` (Required) - Indicates whether you want CloudFront to forward query strings to the origin that is associated with this cache behavior. + +##### `cookies` Arguments + +* `forward` (Required) - Specifies whether you want CloudFront to forward cookies to the origin that is associated with this cache behavior. You can specify `all`, `none` or `whitelist`. +* `whitelisted_names` (Optional) - If you have specified `whitelist` to `forward`, the whitelisted cookies that you want CloudFront to forward to your origin. + +#### `custom_error_response` Arguments + +* `error_caching_min_ttl` (Optional) - The minimum amount of time you want HTTP error codes to stay in CloudFront caches before CloudFront queries your origin to see whether the object has been updated. +* `error_code` (Required) - The 4xx or 5xx HTTP status code that you want to customize. +* `response_code` (Optional) - The HTTP status code that you want CloudFront to return with the custom error page to the viewer. +* `response_page_path` (Optional) - The path of the custom error page (for example, `/custom_404.html`). + +#### `default_cache_behavior` Arguments + +The arguments for `default_cache_behavior` are the same as for +[`cache_behavior`](#cache_behavior), except for the `path_pattern` argument is +not required. + +#### `logging_config` Arguments + +* `bucket` (Required) - The Amazon S3 bucket to store the access logs in, for example, `myawslogbucket.s3.amazonaws.com`. +* `include_cookies` (Optional) - Specifies whether you want CloudFront to include cookies in access logs (default: `false`). +* `prefix` (Optional) - An optional string that you want CloudFront to prefix to the access log filenames for this distribution, for example, `myprefix/`. + +#### `origin` Arguments + +* `custom_origin_config` - The [CloudFront custom origin](#custom_origin_config) configuration information. If an S3 origin is required, use `s3_origin_config` instead. +* `domain_name` (Required) - The DNS domain name of either the S3 bucket, or web site of your custom origin. +* `custom_header` (Optional) - One or more sub-resources with `name` and `value` parameters that specify header data that will be sent to the origin (multiples allowed). +* `origin_id` (Required) - A unique identifier for the origin. +* `origin_path` (Optional) - An optional element that causes CloudFront to request your content from a directory in your Amazon S3 bucket or your custom origin. +* `s3_origin_config` - The [CloudFront S3 origin](#s3_origin_config) configuration information. If a custom origin is required, use `s3_origin_config` instead. + +##### `custom_origin_config` Arguments + +* `http_port` (Required) - The HTTP port the custom origin listens on. +* `https_port` (Required) - The HTTPS port the custom origin listens on. +* `origin_protocol_policy` (Required) - The origin protocol policy to apply to your origin. One of `http-only`, `https-only`, or `match-viewer`. +* `origin_ssl_protocols` (Required) - The SSL/TLS protocols that you want CloudFront to use when communicating with your origin over HTTPS. A list of one or more of `SSLv3`, `TLSv1`, `TLSv1.1`, and `TLSv1.2`. + +##### `s3_origin_config` Arguments + +* `origin_access_identity` (Optional) - The [CloudFront origin access identity][5] to associate with the origin. + +#### `restrictions` Arguments + +The `restrictions` sub-resource takes another single sub-resource named +`geo_restriction` (see the example for usage). + +The arguments of `geo_restriction` are: + +* `locations` (Optional) - The [ISO 3166-1-alpha-2 codes][4] for which you want CloudFront either to distribute your content (`whitelist`) or not distribute your content (`blacklist`). +* `restriction_type` (Required) - The method that you want to use to restrict distribution of your content by country: `none`, `whitelist`, or `blacklist`. + +#### `viewer_certificate` Arguments + +* `cloudfront_default_certificate` - `true` if you want viewers to use HTTPS to request your objects and you're using the CloudFront domain name for your distribution. Specify this, or `iam_certificate_id`. +* `iam_certificate_id` - The IAM certificate identifier of the custom viewer certificate for this distribution if you are using a custom domain. Specify this, or `cloudfront_default_certificate`. +* `minimum_protocol_version` - The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections. One of `SSLv3` or `TLSv1`. Default: `SSLv3`. +* `ssl_support_method`: Specifies how you want CloudFront to serve HTTPS requests. One of `vip` or `sni-only`. Required if you specify `iam_certificate_id`. **NOTE:** `vip` causes CloudFront to use a dedicated IP address and may incur extra charges. + +## Attribute Reference + +The following attributes are exported: + +* `id` - The identifier for the distribution. For example: `EDFDVBD632BHDS5`. +* `caller_reference` - Internal value used by CloudFront to allow future updates to the distribution configuration. +* `status` - The current status of the distribution. `Deployed` if the distribution's information is fully propagated throughout the Amazon CloudFront system. +* `active_trusted_signers` - The key pair IDs that CloudFront is aware of for each trusted signer, if the distribution is set up to serve private content with signed URLs. +* `domain_name` - The domain name corresponding to the distribution. For example: `d604721fxaaqy9.cloudfront.net`. +* `last_modified_time` - The date and time the distribution was last modified. +* `in_progress_validation_batches` - The number of invalidation batches currently in progress. +* `etag` - The current version of the distribution's information. For example: `E2QWRUHAPOMQZL`. + + +[1]: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html +[2]: http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/CreateDistribution.html +[3]: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html +[4]: http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.htm +[5]: /docs/providers/aws/r/cloudfront_origin_access_identity.html diff --git a/website/source/docs/providers/aws/r/cloudfront_origin_access_identity.html.markdown b/website/source/docs/providers/aws/r/cloudfront_origin_access_identity.html.markdown new file mode 100644 index 000000000000..c3565180c555 --- /dev/null +++ b/website/source/docs/providers/aws/r/cloudfront_origin_access_identity.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "aws" +page_title: "AWS: cloudfront_origin_access_identity" +sidebar_current: "docs-aws-resource-cloudfront-origin-access-identity" +description: |- + Provides a CloudFront origin access identity. +--- + +# aws\_cloudfront\_origin\_access\_identity + +Creates an Amazon CloudFront origin access identity. + +For information about CloudFront distributions, see the +[Amazon CloudFront Developer Guide][1]. For more information on generating +origin access identities, see +[Using an Origin Access Identity to Restrict Access to Your Amazon S3 Content][2]. + +## Example Usage + +The following example below creates a CloudFront origin access identity. + +``` +resource "aws_origin_access_identity" "origin_access_identity" { + comment = "Some comment" +} +``` + +## Argument Reference + +* `comment` (Optional) - An optional comment for the origin access identity. + +## Attribute Reference + +The following attributes are exported: + +* `id` - The identifier for the distribution. For example: `EDFDVBD632BHDS5`. +* `caller_reference` - Internal value used by CloudFront to allow future updates to the origin access identity. +* `cloudfront_access_identity_path` - A shortcut to the full path for the origin access identity to use in CloudFront, see below. +* `etag` - The current version of the origin access identity's information. For example: E2QWRUHAPOMQZL. +* `s3_canonical_user_id` - The Amazon S3 canonical user ID for the origin access identity, which you use when giving the origin access identity read permission to an object in Amazon S3. + +## Using With CloudFront + +Normally, when referencing an origin access identity in CloudFront, you need to +prefix the ID with the `origin-access-identity/cloudfront/` special path. +The `cloudfront_access_identity_path` allows this to be circumvented. +The below snippet demonstrates use with the `s3_origin_config` structure for the +[`aws_cloudfront_web_distribution`][3] resource: + +``` +s3_origin_config { + origin_access_identity = "${aws_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}" +} +``` + +[1]: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html +[2]: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html +[3]: /docs/providers/aws/r/cloudfront_distribution.html diff --git a/website/source/docs/providers/aws/r/cloudfront_web_distribution.html.markdown b/website/source/docs/providers/aws/r/cloudfront_web_distribution.html.markdown deleted file mode 100644 index 84a0c1b48ece..000000000000 --- a/website/source/docs/providers/aws/r/cloudfront_web_distribution.html.markdown +++ /dev/null @@ -1,64 +0,0 @@ ---- -layout: "aws" -page_title: "AWS: cloudfront_web_distribution" -sidebar_current: "docs-aws-resource-cloudfront-web-distribution" -description: |- - Provides a CloudFront web distribution resource. ---- - -# cloudfront\_web\_distribution - -Provides a CloudFront distribution resource. Distributions takes approximately -15 minutes to deploy. - -## Example Usage - -``` -resource "aws_cloudfront_web_distribution" "static" { - origin_domain_name = "bucket.s3.amazonaws.com" -} -``` - -## Argument Reference - -The following arguments are supported: - -* `origin_domain_name` - (Required) The Amazon S3 bucket or web server from which you want CloudFront to fetch your web content. -* `origin_http_port` - (Optional) Default: `80`. -* `origin_https_port` - (Optional) Default: `443`. -* `origin_protocol_policy` - (Optional) Default: `"http-only"`. -* `origin_path` - (Optional) Request the content from a directory in your Amazon S3 bucket or your custom origin. -* `enabled` - (Optional) Default: `true`. -* `comment` - (Optional) -* `price_class` - (Optional) Default: `"PriceClass_All"`. -* `default_root_object` - (Optional) -* `status` - (Optional) -* `viewer_protocol_policy` - (Optional) Default: `"allow-all"`. -* `forward_cookie` - (Optional) Include all user cookies in the request URLs that it forwards to your origin. Default: `"none"`. -* `whitelisted_cookies` - (Optional) -* `forward_query_string` - (Optional) Include query strings in the request URLs that it forwards to your origin. Default: `false`. -* `minimum_ttl` - (Optional) The minimum amount of time (in seconds) that an object is in a CloudFront cache before CloudFront forwards another request to your origin to determine whether an updated version is available. Default: `0`. -* `maximum_ttl` - (Optional) Default: `31536000`. -* `default_ttl` - (Optional) Default: `86400`. -* `smooth_streaming` - (Optional) -* `allowed_methods` - (Optional) -* `cached_methods` - (Optional) -* `forwarded_headers` - (Optional) -* `logging_enabled` - (Optional) Log all viewer requests for files in your distribution. Default: `false`. -* `logging_include_cookies` - (Optional) Include cookies in access logs. Default: `false`. -* `logging_prefix` - (Optional) Prefix for the names of log files. -* `logging_bucket` - (Optional) Destination bucket in the format of `bucketname.s3.amazonaws.com`. -* `minimum_ssl` - (Optional) -* `certificate_id` - (Optional) -* `ssl_support_method` - (Optional) -* `aliases` - (Optional) A list alternate domain names(CNAMES). -* `geo_restriction_type` - (Optional) Type of restriction. Default `"none"`. -* `geo_restrictions` - (Optional) A list of two-letter country codes. - -## Attributes Reference - -The following attributes are exported: - -* `id` - The unique identifier of the distribution. -* `domain_name` - Unique domain of the resource. -* `zone_id` - The canonical hosted zone ID of CloudFront(to be used in a Route 53 Alias record) diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index e0aa7f023f8a..78954ce43fa9 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -22,8 +22,11 @@ > CloudFront Resources