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