CloudFront distribution and origin access identity support (#5221)

* CloudFront implementation v3

* Update tests

* Refactor - new resource: aws_cloudfront_distribution

 * Includes a complete re-write of the old aws_cloudfront_web_distribution
   resource to bring it to feature parity with API and CloudFormation.
 * Also includes the aws_cloudfront_origin_access_identity resource to generate
   origin access identities for use with S3.
This commit is contained in:
Chris Marchesi 2016-04-14 12:55:11 -07:00 committed by Clint
parent eed8733ee3
commit a38ccbe074
16 changed files with 7076 additions and 2 deletions

5
Godeps/Godeps.json generated
View File

@ -365,6 +365,11 @@
"Comment": "v1.1.14", "Comment": "v1.1.14",
"Rev": "6876e9922ff299adf36e43e04c94820077968b3b" "Rev": "6876e9922ff299adf36e43e04c94820077968b3b"
}, },
{
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudfront",
"Comment": "v1.1.14",
"Rev": "6876e9922ff299adf36e43e04c94820077968b3b"
},
{ {
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudtrail", "ImportPath": "github.com/aws/aws-sdk-go/service/cloudtrail",
"Comment": "v1.1.14", "Comment": "v1.1.14",

View File

@ -0,0 +1,942 @@
// 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)),
PriceClass: aws.String(d.Get("price_class").(string)),
}
// 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))
} else {
distributionConfig.DefaultRootObject = aws.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))
} else {
distributionConfig.Aliases = expandAliases(schema.NewSet(aliasesHash, []interface{}{}))
}
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))
d.Set("viewer_certificate", flattenViewerCertificate(distributionConfig.ViewerCertificate))
d.Set("price_class", *distributionConfig.PriceClass)
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.Restrictions != nil {
d.Set("restrictions", flattenRestrictions(distributionConfig.Restrictions))
}
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 if v, ok := m["acm_certificate_arn"]; ok && v != "" {
vc.ACMCertificateArn = 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 if vc.ACMCertificateArn != nil {
m["acm_certificate_arn"] = *vc.ACMCertificateArn
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 if v, ok := m["acm_certificate_arn"]; 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)
}

View File

@ -0,0 +1,989 @@
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 viewerCertificateConfSetACM() map[string]interface{} {
return map[string]interface{}{
"acm_certificate_arn": "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012",
"ssl_support_method": "sni-only",
"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.ACMCertificateArn != nil {
t.Fatalf("Expected ACMCertificateArn to be unset, got %v", *vc.ACMCertificateArn)
}
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.ACMCertificateArn != nil {
t.Fatalf("Expected ACMCertificateArn to be unset, got %v", *vc.ACMCertificateArn)
}
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_expandViewerCertificate_acm_certificate_arn(t *testing.T) {
data := viewerCertificateConfSetACM()
vc := expandViewerCertificate(data)
if *vc.ACMCertificateArn != "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012" {
t.Fatalf("Expected ACMCertificateArn to be arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012, got %v", *vc.ACMCertificateArn)
}
if vc.CloudFrontDefaultCertificate != nil {
t.Fatalf("Expected CloudFrontDefaultCertificate to be unset, got %v", *vc.CloudFrontDefaultCertificate)
}
if vc.IAMCertificateId != nil {
t.Fatalf("Expected IAMCertificateId to be unset, got %v", *vc.IAMCertificateId)
}
if *vc.SSLSupportMethod != "sni-only" {
t.Fatalf("Expected IAMCertificateId to be sni-only, 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)
}
}
func TestCloudFrontStructure_falttenViewerCertificate_acm_certificate_arn(t *testing.T) {
in := viewerCertificateConfSetACM()
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)
}
}

View File

@ -25,6 +25,7 @@ import (
"github.com/aws/aws-sdk-go/service/apigateway" "github.com/aws/aws-sdk-go/service/apigateway"
"github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/aws/aws-sdk-go/service/cloudtrail" "github.com/aws/aws-sdk-go/service/cloudtrail"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/cloudwatchevents" "github.com/aws/aws-sdk-go/service/cloudwatchevents"
@ -78,6 +79,7 @@ type Config struct {
type AWSClient struct { type AWSClient struct {
cfconn *cloudformation.CloudFormation cfconn *cloudformation.CloudFormation
cloudfrontconn *cloudfront.CloudFront
cloudtrailconn *cloudtrail.CloudTrail cloudtrailconn *cloudtrail.CloudTrail
cloudwatchconn *cloudwatch.CloudWatch cloudwatchconn *cloudwatch.CloudWatch
cloudwatchlogsconn *cloudwatchlogs.CloudWatchLogs cloudwatchlogsconn *cloudwatchlogs.CloudWatchLogs
@ -188,6 +190,9 @@ func (c *Config) Client() (interface{}, error) {
dynamoSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.DynamoDBEndpoint)}) dynamoSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.DynamoDBEndpoint)})
client.dynamodbconn = dynamodb.New(dynamoSess) client.dynamodbconn = dynamodb.New(dynamoSess)
log.Println("[INFO] Initializing Cloudfront connection")
client.cloudfrontconn = cloudfront.New(sess)
log.Println("[INFO] Initializing ELB connection") log.Println("[INFO] Initializing ELB connection")
awsElbSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.ElbEndpoint)}) awsElbSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.ElbEndpoint)})
client.elbconn = elb.New(awsElbSess) client.elbconn = elb.New(awsElbSess)

View File

@ -129,6 +129,8 @@ func Provider() terraform.ResourceProvider {
"aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(),
"aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(), "aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(),
"aws_cloudformation_stack": resourceAwsCloudFormationStack(), "aws_cloudformation_stack": resourceAwsCloudFormationStack(),
"aws_cloudfront_distribution": resourceAwsCloudFrontDistribution(),
"aws_cloudfront_origin_access_identity": resourceAwsCloudFrontOriginAccessIdentity(),
"aws_cloudtrail": resourceAwsCloudTrail(), "aws_cloudtrail": resourceAwsCloudTrail(),
"aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(),
"aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(),

View File

@ -0,0 +1,595 @@
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,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cookies": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Set: cookiePreferenceHash,
MaxItems: 1,
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,
MaxItems: 1,
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,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cookies": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Set: cookiePreferenceHash,
MaxItems: 1,
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,
MaxItems: 1,
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,
MaxItems: 1,
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,
MaxItems: 1,
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,
Default: "PriceClass_All",
},
"restrictions": &schema.Schema{
Type: schema.TypeSet,
Required: true,
Set: restrictionsHash,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"geo_restriction": &schema.Schema{
Type: schema.TypeSet,
Required: true,
Set: geoRestrictionHash,
MaxItems: 1,
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,
Required: true,
Set: viewerCertificateHash,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"acm_certificate_arn": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"viewer_certificate.cloudfront_default_certificate", "viewer_certificate.iam_certificate_id"},
},
"cloudfront_default_certificate": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
ConflictsWith: []string{"viewer_certificate.acm_certificate_arn", "viewer_certificate.iam_certificate_id"},
},
"iam_certificate_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"viewer_certificate.acm_certificate_arn", "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
}
}

View File

@ -0,0 +1,388 @@
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_noOptionalItemsConfig(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudFrontDistributionDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSCloudFrontDistributionNoOptionalItemsConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudFrontDistributionExistence(
"aws_cloudfront_distribution.no_optional_items",
),
),
},
},
})
}
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
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 testAccAWSCloudFrontDistributionNoOptionalItemsConfig = fmt.Sprintf(`
variable rand_id {
default = %d
}
resource "aws_cloudfront_distribution" "no_optional_items" {
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_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
}
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())

View File

@ -0,0 +1,130 @@
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) {
if originAccessIdentityConfig.Comment != nil {
d.Set("comment", *originAccessIdentityConfig.Comment)
}
d.Set("caller_reference", *originAccessIdentityConfig.CallerReference)
}

View File

@ -0,0 +1,119 @@
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 TestAccAWSCloudFrontOriginAccessIdentity_noComment(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudFrontOriginAccessIdentityDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSCloudFrontOriginAccessIdentityNoCommentConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudFrontOriginAccessIdentityExistence("aws_cloudfront_origin_access_identity.origin_access_identity"),
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"
}
`
const testAccAWSCloudFrontOriginAccessIdentityNoCommentConfig = `
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
}
`

View File

@ -1077,3 +1077,23 @@ func flattenBeanstalkTrigger(list []*elasticbeanstalk.Trigger) []string {
} }
return strs return strs
} }
// 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
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package cloudfront
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/restxml"
"github.com/aws/aws-sdk-go/private/signer/v4"
)
// CloudFront is a client for CloudFront.
//The service client's operations are safe to be used concurrently.
// It is not safe to mutate any of the client's properties though.
type CloudFront struct {
*client.Client
}
// Used for custom client initialization logic
var initClient func(*client.Client)
// Used for custom request initialization logic
var initRequest func(*request.Request)
// A ServiceName is the name of the service the client will make API calls to.
const ServiceName = "cloudfront"
// New creates a new instance of the CloudFront client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a CloudFront client from just a session.
// svc := cloudfront.New(mySession)
//
// // Create a CloudFront client with additional configuration
// svc := cloudfront.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *CloudFront {
c := p.ClientConfig(ServiceName, cfgs...)
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
}
// newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *CloudFront {
svc := &CloudFront{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: ServiceName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "2016-01-28",
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBack(v4.Sign)
svc.Handlers.Build.PushBackNamed(restxml.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed(restxml.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler)
// Run custom client initialization if present
if initClient != nil {
initClient(svc.Client)
}
return svc
}
// newRequest creates a new request for a CloudFront operation and runs any
// custom request initialization.
func (c *CloudFront) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
// Run custom request initialization if present
if initRequest != nil {
initRequest(req)
}
return req
}

View File

@ -0,0 +1,76 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package cloudfront
import (
"github.com/aws/aws-sdk-go/private/waiter"
)
func (c *CloudFront) WaitUntilDistributionDeployed(input *GetDistributionInput) error {
waiterCfg := waiter.Config{
Operation: "GetDistribution",
Delay: 60,
MaxAttempts: 25,
Acceptors: []waiter.WaitAcceptor{
{
State: "success",
Matcher: "path",
Argument: "Distribution.Status",
Expected: "Deployed",
},
},
}
w := waiter.Waiter{
Client: c,
Input: input,
Config: waiterCfg,
}
return w.Wait()
}
func (c *CloudFront) WaitUntilInvalidationCompleted(input *GetInvalidationInput) error {
waiterCfg := waiter.Config{
Operation: "GetInvalidation",
Delay: 20,
MaxAttempts: 30,
Acceptors: []waiter.WaitAcceptor{
{
State: "success",
Matcher: "path",
Argument: "Invalidation.Status",
Expected: "Completed",
},
},
}
w := waiter.Waiter{
Client: c,
Input: input,
Config: waiterCfg,
}
return w.Wait()
}
func (c *CloudFront) WaitUntilStreamingDistributionDeployed(input *GetStreamingDistributionInput) error {
waiterCfg := waiter.Config{
Operation: "GetStreamingDistribution",
Delay: 60,
MaxAttempts: 25,
Acceptors: []waiter.WaitAcceptor{
{
State: "success",
Matcher: "path",
Argument: "StreamingDistribution.Status",
Expected: "Deployed",
},
},
}
w := waiter.Waiter{
Client: c,
Input: input,
Config: waiterCfg,
}
return w.Wait()
}

View File

@ -0,0 +1,197 @@
---
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` (Required) - 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`.
#### <a name="cache_behavior"> `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`.
##### <a name="forwarded_values"> `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. Specify `*` to include all headers.
* `query_string` (Required) - Indicates whether you want CloudFront to forward query strings to the origin that is associated with this cache behavior.
##### <a name="cookies"> `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.
#### <a name="custom_error_response"> `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`).
#### <a name="default_cache_behavior"> `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.
#### <a name="logging_config"> `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/`.
#### <a name="origin"> `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.
##### <a name="custom_origin_config"> `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`.
##### <a name="s3_origin_config"> `s3_origin_config` Arguments
* `origin_access_identity` (Optional) - The [CloudFront origin access identity][5] to associate with the origin.
#### <a name="restrictions"> `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`.
#### <a name="viewer_certificate"> `viewer_certificate` Arguments
* `acm_certificate_arn` - The ARN of the [AWS Certificate Manager][6] certificate that you wish to use with this distribution. Specify this, `cloudfront_default_certificate`, or `iam_certificate_id`.
* `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, `acm_certificate_arn`, 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, `acm_certificate_arn`, 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`. **NOTE**: If you are using a custom certificate (specified with `acm_certificate_arn` or `iam_certificate_id`), and have specified `sni-only` in `ssl_support_method`, `TLSv1` must be specified.
* `ssl_support_method`: Specifies how you want CloudFront to serve HTTPS requests. One of `vip` or `sni-only`. Required if you specify `acm_certificate_arn` or `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
[6]: https://aws.amazon.com/certificate-manager/

View File

@ -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_cloudfront_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_cloudfront_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

View File

@ -52,6 +52,18 @@
</ul> </ul>
</li> </li>
<li<%= sidebar_current(/^docs-aws-resource-cloudfront/) %>>
<a href="#">CloudFront Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-aws-resource-cloudfront-distribution") %>>
<a href="/docs/providers/aws/r/cloudfront_distribution.html">aws_cloudfront_distribution</a>
</li>
<li<%= sidebar_current("docs-aws-resource-cloudfront-origin-access-identity") %>>
<a href="/docs/providers/aws/r/cloudfront_origin_access_identity.html">aws_cloudfront_origin_access_identity</a>
</li>
</ul>
</li>
<li<%= sidebar_current(/^docs-aws-resource-cloudtrail/) %>> <li<%= sidebar_current(/^docs-aws-resource-cloudtrail/) %>>
<a href="#">CloudTrail Resources</a> <a href="#">CloudTrail Resources</a>
<ul class="nav nav-visible"> <ul class="nav nav-visible">