CloudFront improvements (#5275)
This commit is contained in:
parent
4d84f84ffc
commit
6282e5124d
@ -536,7 +536,7 @@
|
||||
|
||||
## cloudfront
|
||||
<details>
|
||||
<summary>5% implemented</summary>
|
||||
<summary>7% implemented</summary>
|
||||
|
||||
- [ ] associate_alias
|
||||
- [ ] create_cache_policy
|
||||
@ -546,7 +546,7 @@
|
||||
- [ ] create_field_level_encryption_config
|
||||
- [ ] create_field_level_encryption_profile
|
||||
- [ ] create_function
|
||||
- [ ] create_invalidation
|
||||
- [X] create_invalidation
|
||||
- [ ] create_key_group
|
||||
- [ ] create_monitoring_subscription
|
||||
- [ ] create_origin_request_policy
|
||||
@ -613,7 +613,7 @@
|
||||
- [ ] list_realtime_log_configs
|
||||
- [ ] list_response_headers_policies
|
||||
- [ ] list_streaming_distributions
|
||||
- [ ] list_tags_for_resource
|
||||
- [X] list_tags_for_resource
|
||||
- [ ] publish_function
|
||||
- [ ] tag_resource
|
||||
- [ ] test_function
|
||||
|
@ -30,8 +30,7 @@ cloudfront
|
||||
- [ ] create_cloud_front_origin_access_identity
|
||||
- [X] create_distribution
|
||||
|
||||
This has been tested against an S3-distribution with the
|
||||
simplest possible configuration. Please raise an issue if
|
||||
Not all configuration options are supported yet. Please raise an issue if
|
||||
we're not persisting/returning the correct attributes for your
|
||||
use-case.
|
||||
|
||||
@ -40,7 +39,7 @@ cloudfront
|
||||
- [ ] create_field_level_encryption_config
|
||||
- [ ] create_field_level_encryption_profile
|
||||
- [ ] create_function
|
||||
- [ ] create_invalidation
|
||||
- [X] create_invalidation
|
||||
- [ ] create_key_group
|
||||
- [ ] create_monitoring_subscription
|
||||
- [ ] create_origin_request_policy
|
||||
@ -116,7 +115,7 @@ cloudfront
|
||||
- [ ] list_realtime_log_configs
|
||||
- [ ] list_response_headers_policies
|
||||
- [ ] list_streaming_distributions
|
||||
- [ ] list_tags_for_resource
|
||||
- [X] list_tags_for_resource
|
||||
- [ ] publish_function
|
||||
- [ ] tag_resource
|
||||
- [ ] test_function
|
||||
|
@ -1,10 +1,12 @@
|
||||
import random
|
||||
import string
|
||||
|
||||
from datetime import datetime
|
||||
from moto.core import get_account_id, BaseBackend, BaseModel
|
||||
from moto.core.utils import BackendDict
|
||||
from moto.core.utils import BackendDict, iso_8601_datetime_with_milliseconds
|
||||
from moto.moto_api import state_manager
|
||||
from moto.moto_api._internal.managed_state_model import ManagedState
|
||||
from moto.utilities.tagging_service import TaggingService
|
||||
from uuid import uuid4
|
||||
|
||||
from .exceptions import (
|
||||
@ -39,9 +41,15 @@ class LambdaFunctionAssociation:
|
||||
|
||||
|
||||
class ForwardedValues:
|
||||
def __init__(self):
|
||||
self.query_string = ""
|
||||
self.whitelisted_names = []
|
||||
def __init__(self, config):
|
||||
self.query_string = config.get("QueryString", "false")
|
||||
self.cookie_forward = config.get("Cookies", {}).get("Forward") or "none"
|
||||
self.whitelisted_names = (
|
||||
config.get("Cookies", {}).get("WhitelistedNames", {}).get("Items") or {}
|
||||
)
|
||||
self.whitelisted_names = self.whitelisted_names.get("Name") or []
|
||||
if isinstance(self.whitelisted_names, str):
|
||||
self.whitelisted_names = [self.whitelisted_names]
|
||||
self.headers = []
|
||||
self.query_string_cache_keys = []
|
||||
|
||||
@ -54,22 +62,28 @@ class DefaultCacheBehaviour:
|
||||
self.trusted_key_groups_enabled = False
|
||||
self.trusted_key_groups = []
|
||||
self.viewer_protocol_policy = config["ViewerProtocolPolicy"]
|
||||
self.allowed_methods = ["HEAD", "GET"]
|
||||
self.cached_methods = ["GET", "HEAD"]
|
||||
self.smooth_streaming = True
|
||||
self.compress = True
|
||||
methods = config.get("AllowedMethods", {})
|
||||
self.allowed_methods = methods.get("Items", {}).get("Method", ["HEAD", "GET"])
|
||||
self.cached_methods = (
|
||||
methods.get("CachedMethods", {})
|
||||
.get("Items", {})
|
||||
.get("Method", ["GET", "HEAD"])
|
||||
)
|
||||
self.smooth_streaming = config.get("SmoothStreaming") or True
|
||||
self.compress = config.get("Compress", "true").lower() == "true"
|
||||
self.lambda_function_associations = []
|
||||
self.function_associations = []
|
||||
self.field_level_encryption_id = ""
|
||||
self.forwarded_values = ForwardedValues()
|
||||
self.min_ttl = 0
|
||||
self.default_ttl = 0
|
||||
self.max_ttl = 0
|
||||
self.forwarded_values = ForwardedValues(config.get("ForwardedValues", {}))
|
||||
self.min_ttl = config.get("MinTTL") or 0
|
||||
self.default_ttl = config.get("DefaultTTL") or 0
|
||||
self.max_ttl = config.get("MaxTTL") or 0
|
||||
|
||||
|
||||
class Logging:
|
||||
def __init__(self):
|
||||
self.enabled = False
|
||||
self.include_cookies = False
|
||||
|
||||
|
||||
class ViewerCertificate:
|
||||
@ -79,6 +93,19 @@ class ViewerCertificate:
|
||||
self.certificate_source = "cloudfront"
|
||||
|
||||
|
||||
class CustomOriginConfig:
|
||||
def __init__(self, config):
|
||||
self.http_port = config.get("HTTPPort")
|
||||
self.https_port = config.get("HTTPSPort")
|
||||
self.keep_alive = config.get("OriginKeepaliveTimeout")
|
||||
self.protocol_policy = config.get("OriginProtocolPolicy")
|
||||
self.read_timeout = config.get("OriginReadTimeout")
|
||||
self.ssl_protocols = (
|
||||
config.get("OriginSslProtocols", {}).get("Items", {}).get("SslProtocol")
|
||||
or []
|
||||
)
|
||||
|
||||
|
||||
class Origin:
|
||||
def __init__(self, origin):
|
||||
self.id = origin["Id"]
|
||||
@ -86,9 +113,9 @@ class Origin:
|
||||
self.custom_headers = []
|
||||
self.s3_access_identity = ""
|
||||
self.custom_origin = None
|
||||
self.origin_shield = None
|
||||
self.connection_attempts = 3
|
||||
self.connection_timeout = 10
|
||||
self.origin_shield = origin.get("OriginShield")
|
||||
self.connection_attempts = origin.get("ConnectionAttempts") or 3
|
||||
self.connection_timeout = origin.get("ConnectionTimeout") or 10
|
||||
|
||||
if "S3OriginConfig" not in origin and "CustomOriginConfig" not in origin:
|
||||
raise InvalidOriginServer
|
||||
@ -99,22 +126,33 @@ class Origin:
|
||||
raise DomainNameNotAnS3Bucket
|
||||
self.s3_access_identity = origin["S3OriginConfig"]["OriginAccessIdentity"]
|
||||
|
||||
if "CustomOriginConfig" in origin:
|
||||
self.custom_origin = CustomOriginConfig(origin["CustomOriginConfig"])
|
||||
|
||||
|
||||
class GeoRestrictions:
|
||||
def __init__(self, config):
|
||||
config = config.get("GeoRestriction") or {}
|
||||
self._type = config.get("RestrictionType", "none")
|
||||
self.restrictions = (config.get("Items") or {}).get("Location") or []
|
||||
|
||||
|
||||
class DistributionConfig:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.aliases = config.get("Aliases", {}).get("Items", {}).get("CNAME", [])
|
||||
self.comment = config.get("Comment", "")
|
||||
self.aliases = ((config.get("Aliases") or {}).get("Items") or {}).get(
|
||||
"CNAME"
|
||||
) or []
|
||||
self.comment = config.get("Comment") or ""
|
||||
self.default_cache_behavior = DefaultCacheBehaviour(
|
||||
config["DefaultCacheBehavior"]
|
||||
)
|
||||
self.cache_behaviors = []
|
||||
self.custom_error_responses = []
|
||||
self.logging = Logging()
|
||||
self.enabled = False
|
||||
self.enabled = config.get("Enabled") or False
|
||||
self.viewer_certificate = ViewerCertificate()
|
||||
self.geo_restriction_type = "none"
|
||||
self.geo_restrictions = []
|
||||
self.geo_restriction = GeoRestrictions(config.get("Restrictions") or {})
|
||||
self.caller_reference = config.get("CallerReference", str(uuid4()))
|
||||
self.origins = config["Origins"]["Items"]["Origin"]
|
||||
if not isinstance(self.origins, list):
|
||||
@ -127,9 +165,10 @@ class DistributionConfig:
|
||||
raise OriginDoesNotExist
|
||||
|
||||
self.origins = [Origin(o) for o in self.origins]
|
||||
self.price_class = "PriceClass_All"
|
||||
self.http_version = "http2"
|
||||
self.is_ipv6_enabled = True
|
||||
self.price_class = config.get("PriceClass", "PriceClass_All")
|
||||
self.http_version = config.get("HttpVersion", "http2")
|
||||
self.is_ipv6_enabled = config.get("IsIPV6Enabled", "true").lower() == "true"
|
||||
self.default_root_object = config.get("DefaultRootObject") or ""
|
||||
|
||||
|
||||
class Distribution(BaseModel, ManagedState):
|
||||
@ -161,29 +200,50 @@ class Distribution(BaseModel, ManagedState):
|
||||
self.in_progress_invalidation_batches = 0
|
||||
self.has_active_trusted_key_groups = False
|
||||
self.domain_name = f"{Distribution.random_id(uppercase=False)}.cloudfront.net"
|
||||
self.etag = Distribution.random_id()
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return f"https://cloudfront.amazonaws.com/2020-05-31/distribution/{self.distribution_id}"
|
||||
|
||||
|
||||
class Invalidation(BaseModel):
|
||||
@staticmethod
|
||||
def random_id(uppercase=True):
|
||||
ascii_set = string.ascii_uppercase if uppercase else string.ascii_lowercase
|
||||
chars = list(range(10)) + list(ascii_set)
|
||||
resource_id = random.choice(ascii_set) + "".join(
|
||||
str(random.choice(chars)) for _ in range(12)
|
||||
)
|
||||
return resource_id
|
||||
|
||||
def __init__(self, distribution, paths, caller_ref):
|
||||
self.invalidation_id = Invalidation.random_id()
|
||||
self.create_time = iso_8601_datetime_with_milliseconds(datetime.now())
|
||||
self.distribution = distribution
|
||||
self.status = "COMPLETED"
|
||||
|
||||
self.paths = paths
|
||||
self.caller_ref = caller_ref
|
||||
|
||||
@property
|
||||
def etag(self):
|
||||
return Distribution.random_id()
|
||||
def location(self):
|
||||
return self.distribution.location + f"/invalidation/{self.invalidation_id}"
|
||||
|
||||
|
||||
class CloudFrontBackend(BaseBackend):
|
||||
def __init__(self, region_name, account_id):
|
||||
super().__init__(region_name, account_id)
|
||||
self.distributions = dict()
|
||||
self.tagger = TaggingService()
|
||||
|
||||
state_manager.register_default_transition(
|
||||
"cloudfront::distribution", transition={"progression": "manual", "times": 1}
|
||||
)
|
||||
|
||||
def create_distribution(self, distribution_config):
|
||||
def create_distribution(self, distribution_config, tags):
|
||||
"""
|
||||
This has been tested against an S3-distribution with the
|
||||
simplest possible configuration. Please raise an issue if
|
||||
Not all configuration options are supported yet. Please raise an issue if
|
||||
we're not persisting/returning the correct attributes for your
|
||||
use-case.
|
||||
"""
|
||||
@ -193,6 +253,7 @@ class CloudFrontBackend(BaseBackend):
|
||||
if existing_dist:
|
||||
raise DistributionAlreadyExists(existing_dist.distribution_id)
|
||||
self.distributions[dist.distribution_id] = dist
|
||||
self.tagger.tag_resource(dist.arn, tags)
|
||||
return dist, dist.location, dist.etag
|
||||
|
||||
def get_distribution(self, distribution_id):
|
||||
@ -248,6 +309,15 @@ class CloudFrontBackend(BaseBackend):
|
||||
dist.advance()
|
||||
return dist, dist.location, dist.etag
|
||||
|
||||
def create_invalidation(self, dist_id, paths, caller_ref):
|
||||
dist, _ = self.get_distribution(dist_id)
|
||||
invalidation = Invalidation(dist, paths, caller_ref)
|
||||
|
||||
return invalidation
|
||||
|
||||
def list_tags_for_resource(self, resource):
|
||||
return self.tagger.list_tags_for_resource(resource)
|
||||
|
||||
|
||||
cloudfront_backends = BackendDict(
|
||||
CloudFrontBackend,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import xmltodict
|
||||
from urllib.parse import unquote
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import cloudfront_backends
|
||||
@ -22,11 +23,28 @@ class CloudFrontResponse(BaseResponse):
|
||||
if request.method == "GET":
|
||||
return self.list_distributions()
|
||||
|
||||
def invalidation(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
if request.method == "POST":
|
||||
return self.create_invalidation()
|
||||
|
||||
def tags(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
if request.method == "GET":
|
||||
return self.list_tags_for_resource()
|
||||
|
||||
def create_distribution(self):
|
||||
params = self._get_xml_body()
|
||||
distribution_config = params.get("DistributionConfig")
|
||||
if "DistributionConfigWithTags" in params:
|
||||
config = params.get("DistributionConfigWithTags")
|
||||
tags = (config.get("Tags", {}).get("Items") or {}).get("Tag", [])
|
||||
else:
|
||||
config = params
|
||||
tags = []
|
||||
distribution_config = config.get("DistributionConfig")
|
||||
distribution, location, e_tag = self.backend.create_distribution(
|
||||
distribution_config=distribution_config
|
||||
distribution_config=distribution_config,
|
||||
tags=tags,
|
||||
)
|
||||
template = self.response_template(CREATE_DISTRIBUTION_TEMPLATE)
|
||||
response = template.render(distribution=distribution, xmlns=XMLNS)
|
||||
@ -69,6 +87,25 @@ class CloudFrontResponse(BaseResponse):
|
||||
headers = {"ETag": e_tag, "Location": location}
|
||||
return 200, headers, response
|
||||
|
||||
def create_invalidation(self):
|
||||
dist_id = self.path.split("/")[-2]
|
||||
params = self._get_xml_body()["InvalidationBatch"]
|
||||
paths = ((params.get("Paths") or {}).get("Items") or {}).get("Path") or []
|
||||
caller_ref = params.get("CallerReference")
|
||||
|
||||
invalidation = self.backend.create_invalidation(dist_id, paths, caller_ref)
|
||||
template = self.response_template(CREATE_INVALIDATION_TEMPLATE)
|
||||
response = template.render(invalidation=invalidation, xmlns=XMLNS)
|
||||
|
||||
return 200, {"Location": invalidation.location}, response
|
||||
|
||||
def list_tags_for_resource(self):
|
||||
resource = unquote(self._get_param("Resource"))
|
||||
tags = self.backend.list_tags_for_resource(resource=resource)["Tags"]
|
||||
template = self.response_template(TAGS_TEMPLATE)
|
||||
response = template.render(tags=tags, xmlns=XMLNS)
|
||||
return 200, {}, response
|
||||
|
||||
|
||||
DIST_META_TEMPLATE = """
|
||||
<Id>{{ distribution.distribution_id }}</Id>
|
||||
@ -90,7 +127,7 @@ DIST_CONFIG_TEMPLATE = """
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</Aliases>
|
||||
<DefaultRootObject>{{ distribution.distribution_config.default_distribution_object }}</DefaultRootObject>
|
||||
<DefaultRootObject>{{ distribution.distribution_config.default_root_object }}</DefaultRootObject>
|
||||
<Origins>
|
||||
<Quantity>{{ distribution.distribution_config.origins|length }}</Quantity>
|
||||
<Items>
|
||||
@ -108,32 +145,34 @@ DIST_CONFIG_TEMPLATE = """
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</CustomHeaders>
|
||||
{% if origin.s3_access_identity %}
|
||||
<S3OriginConfig>
|
||||
<OriginAccessIdentity>{{ origin.s3_access_identity }}</OriginAccessIdentity>
|
||||
</S3OriginConfig>
|
||||
{% endif %}
|
||||
{% if origin.custom_origin %}
|
||||
<CustomOriginConfig>
|
||||
<HTTPPort>{{ origin.custom_origin.http_port }}</HTTPPort>
|
||||
<HTTPSPort>{{ origin.custom_origin.https_port }}</HTTPSPort>
|
||||
<OriginProtocolPolicy>{{ OriginProtocolPolicy }}</OriginProtocolPolicy>
|
||||
<OriginProtocolPolicy>{{ origin.custom_origin.protocol_policy }}</OriginProtocolPolicy>
|
||||
<OriginSslProtocols>
|
||||
<Quantity>{{ origin.custom_origin.origin_ssl_protocols.quantity }}</Quantity>
|
||||
<Quantity>{{ origin.custom_origin.ssl_protocols|length }}</Quantity>
|
||||
<Items>
|
||||
{% for protocol in origin.custom_origin.origin_ssl_protocols %}
|
||||
{{ protocol }}
|
||||
{% for protocol in origin.custom_origin.ssl_protocols %}
|
||||
<SslProtocol>{{ protocol }}</SslProtocol>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</OriginSslProtocols>
|
||||
<OriginReadTimeout>{{ origin.custom_origin.origin_read_timeout }}</OriginReadTimeout>
|
||||
<OriginKeepaliveTimeout>{{ origin.custom_origin.origin_keepalive_timeout }}</OriginKeepaliveTimeout>
|
||||
<OriginReadTimeout>{{ origin.custom_origin.read_timeout }}</OriginReadTimeout>
|
||||
<OriginKeepaliveTimeout>{{ origin.custom_origin.keep_alive }}</OriginKeepaliveTimeout>
|
||||
</CustomOriginConfig>
|
||||
{% endif %}
|
||||
<ConnectionAttempts>{{ origin.connection_attempts }}</ConnectionAttempts>
|
||||
<ConnectionTimeout>{{ origin.connection_timeout }}</ConnectionTimeout>
|
||||
{% if origin.origin_shield %}
|
||||
<OriginShield>
|
||||
<Enabled>{{ origin.origin_shield.enabled }}</Enabled>
|
||||
<OriginShieldRegion>{{ OriginShieldRegion }}</OriginShieldRegion>
|
||||
<Enabled>{{ origin.origin_shield.get("Enabled") }}</Enabled>
|
||||
<OriginShieldRegion>{{ origin.origin_shield.get("OriginShieldRegion") }}</OriginShieldRegion>
|
||||
</OriginShield>
|
||||
{% else %}
|
||||
<OriginShield>
|
||||
@ -175,7 +214,7 @@ DIST_CONFIG_TEMPLATE = """
|
||||
<DefaultCacheBehavior>
|
||||
<TargetOriginId>{{ distribution.distribution_config.default_cache_behavior.target_origin_id }}</TargetOriginId>
|
||||
<TrustedSigners>
|
||||
<Enabled>{{ distribution.distribution_config.default_cache_behavior.trusted_signers.enabled }}</Enabled>
|
||||
<Enabled>{{ distribution.distribution_config.default_cache_behavior.trusted_signers_enabled }}</Enabled>
|
||||
<Quantity>{{ distribution.distribution_config.default_cache_behavior.trusted_signers|length }}</Quantity>
|
||||
<Items>
|
||||
{% for aws_account_number in distribution.distribution_config.default_cache_behavior.trusted_signers %}
|
||||
@ -197,14 +236,14 @@ DIST_CONFIG_TEMPLATE = """
|
||||
<Quantity>{{ distribution.distribution_config.default_cache_behavior.allowed_methods|length }}</Quantity>
|
||||
<Items>
|
||||
{% for method in distribution.distribution_config.default_cache_behavior.allowed_methods %}
|
||||
<member>{{ method }}</member>
|
||||
<Method>{{ method }}</Method>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
<CachedMethods>
|
||||
<Quantity>{{ distribution.distribution_config.default_cache_behavior.cached_methods|length }}</Quantity>
|
||||
<Items>
|
||||
{% for method in distribution.distribution_config.default_cache_behavior.cached_methods %}
|
||||
<member>{{ method }}</member>
|
||||
<Method>{{ method }}</Method>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</CachedMethods>
|
||||
@ -242,7 +281,7 @@ DIST_CONFIG_TEMPLATE = """
|
||||
<ForwardedValues>
|
||||
<QueryString>{{ distribution.distribution_config.default_cache_behavior.forwarded_values.query_string }}</QueryString>
|
||||
<Cookies>
|
||||
<Forward>{{ ItemSelection }}</Forward>
|
||||
<Forward>{{ distribution.distribution_config.default_cache_behavior.forwarded_values.cookie_forward }}</Forward>
|
||||
<WhitelistedNames>
|
||||
<Quantity>{{ distribution.distribution_config.default_cache_behavior.forwarded_values.whitelisted_names|length }}</Quantity>
|
||||
<Items>
|
||||
@ -277,7 +316,7 @@ DIST_CONFIG_TEMPLATE = """
|
||||
<Quantity>{{ distribution.distribution_config.cache_behaviors|length }}</Quantity>
|
||||
{% if distribution.distribution_config.cache_behaviors %}
|
||||
<Items>
|
||||
{% for behaviour in distribution.distribution_config.cache_behaviors %}
|
||||
{% for behaviour in distribution.distribution_config.cache_behaviors %}
|
||||
<PathPattern>{{ behaviour.path_pattern }}</PathPattern>
|
||||
<TargetOriginId>{{ behaviour.target_origin_id }}</TargetOriginId>
|
||||
<TrustedSigners>
|
||||
@ -290,33 +329,33 @@ DIST_CONFIG_TEMPLATE = """
|
||||
</Items>
|
||||
</TrustedSigners>
|
||||
<TrustedKeyGroups>
|
||||
<Enabled>{{ cache_behavior_list.trusted_key_groups.enabled }}</Enabled>
|
||||
<Quantity>{{ cache_behavior_list.trusted_key_groups.quantity }}</Quantity>
|
||||
<Enabled>{{ behaviour.trusted_key_groups.enabled }}</Enabled>
|
||||
<Quantity>{{ behaviour.trusted_key_groups.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for trusted_key_group_id_list in cache_behavior_list.trusted_key_groups.TrustedKeyGroupIdList %}
|
||||
{% for trusted_key_group_id_list in behaviour.trusted_key_groups.TrustedKeyGroupIdList %}
|
||||
<KeyGroup>{{ trusted_key_group_id_list.key_group }}</KeyGroup>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</TrustedKeyGroups>
|
||||
<ViewerProtocolPolicy>{{ ViewerProtocolPolicy }}</ViewerProtocolPolicy>
|
||||
<AllowedMethods>
|
||||
<Quantity>{{ cache_behavior_list.allowed_methods.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.allowed_methods.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for methods_list in cache_behavior_list.allowed_methods.MethodsList %}{{ Method }}{% endfor %}
|
||||
{% for methods_list in behaviour.allowed_methods.MethodsList %}{{ Method }}{% endfor %}
|
||||
</Items>
|
||||
<CachedMethods>
|
||||
<Quantity>{{ cache_behavior_list.allowed_methods.cached_methods.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.allowed_methods.cached_methods.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for methods_list in cache_behavior_list.allowed_methods.cached_methods.MethodsList %}{{ Method }}{% endfor %}
|
||||
{% for methods_list in behaviour.allowed_methods.cached_methods.MethodsList %}{{ Method }}{% endfor %}
|
||||
</Items>
|
||||
</CachedMethods>
|
||||
</AllowedMethods>
|
||||
<SmoothStreaming>{{ cache_behavior_list.smooth_streaming }}</SmoothStreaming>
|
||||
<Compress>{{ cache_behavior_list.compress }}</Compress>
|
||||
<SmoothStreaming>{{ behaviour.smooth_streaming }}</SmoothStreaming>
|
||||
<Compress>{{ behaviour.compress }}</Compress>
|
||||
<LambdaFunctionAssociations>
|
||||
<Quantity>{{ cache_behavior_list.lambda_function_associations.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.lambda_function_associations.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for lambda_function_association_list in cache_behavior_list.lambda_function_associations.LambdaFunctionAssociationList %}
|
||||
{% for lambda_function_association_list in behaviour.lambda_function_associations.LambdaFunctionAssociationList %}
|
||||
<LambdaFunctionARN>{{ LambdaFunctionARN }}</LambdaFunctionARN>
|
||||
<EventType>{{ EventType }}</EventType>
|
||||
<IncludeBody>{{ lambda_function_association_list.include_body }}</IncludeBody>
|
||||
@ -324,52 +363,52 @@ DIST_CONFIG_TEMPLATE = """
|
||||
</Items>
|
||||
</LambdaFunctionAssociations>
|
||||
<FunctionAssociations>
|
||||
<Quantity>{{ cache_behavior_list.function_associations.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.function_associations.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for function_association_list in cache_behavior_list.function_associations.FunctionAssociationList %}
|
||||
{% for function_association_list in behaviour.function_associations.FunctionAssociationList %}
|
||||
<FunctionARN>{{ FunctionARN }}</FunctionARN>
|
||||
<EventType>{{ EventType }}</EventType>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</FunctionAssociations>
|
||||
<FieldLevelEncryptionId>{{ cache_behavior_list.field_level_encryption_id }}</FieldLevelEncryptionId>
|
||||
<RealtimeLogConfigArn>{{ cache_behavior_list.realtime_log_config_arn }}</RealtimeLogConfigArn>
|
||||
<CachePolicyId>{{ cache_behavior_list.cache_policy_id }}</CachePolicyId>
|
||||
<OriginRequestPolicyId>{{ cache_behavior_list.origin_request_policy_id }}</OriginRequestPolicyId>
|
||||
<ResponseHeadersPolicyId>{{ cache_behavior_list.response_headers_policy_id }}</ResponseHeadersPolicyId>
|
||||
<FieldLevelEncryptionId>{{ behaviour.field_level_encryption_id }}</FieldLevelEncryptionId>
|
||||
<RealtimeLogConfigArn>{{ behaviour.realtime_log_config_arn }}</RealtimeLogConfigArn>
|
||||
<CachePolicyId>{{ behaviour.cache_policy_id }}</CachePolicyId>
|
||||
<OriginRequestPolicyId>{{ behaviour.origin_request_policy_id }}</OriginRequestPolicyId>
|
||||
<ResponseHeadersPolicyId>{{ behaviour.response_headers_policy_id }}</ResponseHeadersPolicyId>
|
||||
<ForwardedValues>
|
||||
<QueryString>{{ cache_behavior_list.forwarded_values.query_string }}</QueryString>
|
||||
<QueryString>{{ behaviour.forwarded_values.query_string }}</QueryString>
|
||||
<Cookies>
|
||||
<Forward>{{ ItemSelection }}</Forward>
|
||||
<WhitelistedNames>
|
||||
<Quantity>{{ cache_behavior_list.forwarded_values.cookies.whitelisted_names.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.forwarded_values.cookies.whitelisted_names.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for cookie_name_list in cache_behavior_list.forwarded_values.cookies.whitelisted_names.CookieNameList %}
|
||||
{% for cookie_name_list in behaviour.forwarded_values.cookies.whitelisted_names.CookieNameList %}
|
||||
<Name>{{ cookie_name_list.name }}</Name>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</WhitelistedNames>
|
||||
</Cookies>
|
||||
<Headers>
|
||||
<Quantity>{{ cache_behavior_list.forwarded_values.headers.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.forwarded_values.headers.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for header_list in cache_behavior_list.forwarded_values.headers.HeaderList %}
|
||||
{% for header_list in behaviour.forwarded_values.headers.HeaderList %}
|
||||
<Name>{{ header_list.name }}</Name>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</Headers>
|
||||
<QueryStringCacheKeys>
|
||||
<Quantity>{{ cache_behavior_list.forwarded_values.query_string_cache_keys.quantity }}</Quantity>
|
||||
<Quantity>{{ behaviour.forwarded_values.query_string_cache_keys.quantity }}</Quantity>
|
||||
<Items>
|
||||
{% for query_string_cache_keys_list in cache_behavior_list.forwarded_values.query_string_cache_keys.QueryStringCacheKeysList %}
|
||||
{% for query_string_cache_keys_list in behaviour.forwarded_values.query_string_cache_keys.QueryStringCacheKeysList %}
|
||||
<Name>{{ query_string_cache_keys_list.name }}</Name>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</QueryStringCacheKeys>
|
||||
</ForwardedValues>
|
||||
<MinTTL>{{ cache_behavior_list.min_ttl }}</MinTTL>
|
||||
<DefaultTTL>{{ cache_behavior_list.default_ttl }}</DefaultTTL>
|
||||
<MaxTTL>{{ cache_behavior_list.max_ttl }}</MaxTTL>
|
||||
<MinTTL>{{ behaviour.min_ttl }}</MinTTL>
|
||||
<DefaultTTL>{{ behaviour.default_ttl }}</DefaultTTL>
|
||||
<MaxTTL>{{ behaviour.max_ttl }}</MaxTTL>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
{% endif %}
|
||||
@ -407,11 +446,11 @@ DIST_CONFIG_TEMPLATE = """
|
||||
</ViewerCertificate>
|
||||
<Restrictions>
|
||||
<GeoRestriction>
|
||||
<RestrictionType>{{ distribution.distribution_config.geo_restriction_type }}</RestrictionType>
|
||||
<Quantity>{{ distribution.distribution_config.geo_restrictions|length }}</Quantity>
|
||||
{% if distribution.distribution_config.geo_restrictions %}
|
||||
<RestrictionType>{{ distribution.distribution_config.geo_restriction._type }}</RestrictionType>
|
||||
<Quantity>{{ distribution.distribution_config.geo_restriction.restrictions|length }}</Quantity>
|
||||
{% if distribution.distribution_config.geo_restriction.restrictions %}
|
||||
<Items>
|
||||
{% for location in distribution.distribution_config.geo_restrictions %}
|
||||
{% for location in distribution.distribution_config.geo_restriction.restrictions %}
|
||||
<Location>{{ location }}</Location>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
@ -528,3 +567,33 @@ UPDATE_DISTRIBUTION_TEMPLATE = (
|
||||
</Distribution>
|
||||
"""
|
||||
)
|
||||
|
||||
CREATE_INVALIDATION_TEMPLATE = """<?xml version="1.0"?>
|
||||
<Invalidation>
|
||||
<Id>{{ invalidation.invalidation_id }}</Id>
|
||||
<Status>{{ invalidation.status }}</Status>
|
||||
<CreateTime>{{ invalidation.create_time }}</CreateTime>
|
||||
<InvalidationBatch>
|
||||
<CallerReference>{{ invalidation.caller_ref }}</CallerReference>
|
||||
<Paths>
|
||||
<Quantity>{{ invalidation.paths|length }}</Quantity>
|
||||
<Items>
|
||||
{% for path in invalidation.paths %}<Path>{{ path }}</Path>{% endfor %}
|
||||
</Items>
|
||||
</Paths>
|
||||
</InvalidationBatch>
|
||||
</Invalidation>
|
||||
"""
|
||||
|
||||
TAGS_TEMPLATE = """<?xml version="1.0"?>
|
||||
<Tags>
|
||||
<Items>
|
||||
{% for tag in tags %}
|
||||
<Tag>
|
||||
<Key>{{ tag["Key"] }}</Key>
|
||||
<Value>{{ tag["Value"] }}</Value>
|
||||
</Tag>
|
||||
{% endfor %}
|
||||
</Items>
|
||||
</Tags>
|
||||
"""
|
||||
|
@ -11,4 +11,6 @@ url_paths = {
|
||||
"{0}/2020-05-31/distribution$": response.distributions,
|
||||
"{0}/2020-05-31/distribution/(?P<distribution_id>[^/]+)$": response.individual_distribution,
|
||||
"{0}/2020-05-31/distribution/(?P<distribution_id>[^/]+)/config$": response.update_distribution,
|
||||
"{0}/2020-05-31/distribution/(?P<distribution_id>[^/]+)/invalidation": response.invalidation,
|
||||
"{0}/2020-05-31/tagging$": response.tags,
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ PATCH="etc/0001-Patch-Hardcode-endpoints-to-local-server.patch"
|
||||
(git apply $pwd/etc/0003-Patch-IAM-wait-times.patch > /dev/null 2>&1 && echo "Patched IAM") || echo "Not patching IAM - Directory was probably already patched."
|
||||
(git apply $pwd/etc/0004-DAX-Reduce-wait-times.patch > /dev/null 2>&1 && echo "Patched DAX") || echo "Not patching DAX - Directory was probably already patched."
|
||||
(git apply $pwd/etc/0005-Route53-Reduce-wait-times.patch > /dev/null 2>&1 && echo "Patched Route53") || echo "Not patching Route53 - Directory was probably already patched."
|
||||
(git apply $pwd/etc/0006-CF-Reduce-wait-times.patch > /dev/null 2>&1 && echo "Patched CF") || echo "Not patching CF - Directory was probably already patched."
|
||||
)
|
||||
|
||||
(
|
||||
|
@ -1,12 +1,12 @@
|
||||
From 64093955e96cff42a797880b4a6921663af6040d Mon Sep 17 00:00:00 2001
|
||||
From 91f2d9c33f241cb9dfb3700eaa739a46a06a29bc Mon Sep 17 00:00:00 2001
|
||||
From: Bert Blommers <info@bertblommers.nl>
|
||||
Date: Sun, 19 Jun 2022 19:32:26 +0000
|
||||
Date: Wed, 29 Jun 2022 16:24:04 +0000
|
||||
Subject: [PATCH] Patch: Hardcode endpoints
|
||||
|
||||
---
|
||||
internal/conns/config.go | 15 +++++++++++++++
|
||||
internal/provider/provider.go | 2 +-
|
||||
2 files changed, 16 insertions(+), 1 deletion(-)
|
||||
internal/provider/provider.go | 4 ++--
|
||||
2 files changed, 17 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/internal/conns/config.go b/internal/conns/config.go
|
||||
index 7bfd3100fd..b59083068a 100644
|
||||
@ -37,10 +37,10 @@ index 7bfd3100fd..b59083068a 100644
|
||||
AccessKey: c.AccessKey,
|
||||
APNInfo: StdUserAgentProducts(c.TerraformVersion),
|
||||
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
|
||||
index 7e6200d9ac..7005caccd3 100644
|
||||
index 7e6200d9ac..98d8c4fccc 100644
|
||||
--- a/internal/provider/provider.go
|
||||
+++ b/internal/provider/provider.go
|
||||
@@ -2082,7 +2082,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, terraformVer
|
||||
@@ -2082,14 +2082,14 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, terraformVer
|
||||
CustomCABundle: d.Get("custom_ca_bundle").(string),
|
||||
EC2MetadataServiceEndpoint: d.Get("ec2_metadata_service_endpoint").(string),
|
||||
EC2MetadataServiceEndpointMode: d.Get("ec2_metadata_service_endpoint_mode").(string),
|
||||
@ -49,6 +49,14 @@ index 7e6200d9ac..7005caccd3 100644
|
||||
HTTPProxy: d.Get("http_proxy").(string),
|
||||
IgnoreTagsConfig: expandProviderIgnoreTags(d.Get("ignore_tags").([]interface{})),
|
||||
Insecure: d.Get("insecure").(bool),
|
||||
MaxRetries: d.Get("max_retries").(int),
|
||||
Profile: d.Get("profile").(string),
|
||||
Region: d.Get("region").(string),
|
||||
- S3UsePathStyle: d.Get("s3_use_path_style").(bool) || d.Get("s3_force_path_style").(bool),
|
||||
+ S3UsePathStyle: true,
|
||||
SecretKey: d.Get("secret_key").(string),
|
||||
SkipCredsValidation: d.Get("skip_credentials_validation").(bool),
|
||||
SkipGetEC2Platforms: d.Get("skip_get_ec2_platforms").(bool),
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
29
tests/terraformtests/etc/0006-CF-Reduce-wait-times.patch
Normal file
29
tests/terraformtests/etc/0006-CF-Reduce-wait-times.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From bc72f0c3ec4a4d099d6d9c9ab8bb5c839957378f Mon Sep 17 00:00:00 2001
|
||||
From: Bert Blommers <info@bertblommers.nl>
|
||||
Date: Wed, 29 Jun 2022 16:25:09 +0000
|
||||
Subject: [PATCH] Patch CF timings
|
||||
|
||||
---
|
||||
internal/service/cloudfront/distribution.go | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/internal/service/cloudfront/distribution.go b/internal/service/cloudfront/distribution.go
|
||||
index 3d34f2cf1c..17e7e17014 100644
|
||||
--- a/internal/service/cloudfront/distribution.go
|
||||
+++ b/internal/service/cloudfront/distribution.go
|
||||
@@ -1185,9 +1185,9 @@ func DistributionWaitUntilDeployed(id string, meta interface{}) error {
|
||||
Pending: []string{"InProgress"},
|
||||
Target: []string{"Deployed"},
|
||||
Refresh: resourceWebDistributionStateRefreshFunc(id, meta),
|
||||
- Timeout: 90 * time.Minute,
|
||||
- MinTimeout: 15 * time.Second,
|
||||
- Delay: 1 * time.Minute,
|
||||
+ Timeout: 1 * time.Minute,
|
||||
+ MinTimeout: 5 * time.Second,
|
||||
+ Delay: 10 * time.Second,
|
||||
}
|
||||
|
||||
_, err := stateConf.WaitForState()
|
||||
--
|
||||
2.25.1
|
||||
|
@ -17,6 +17,9 @@ batch:
|
||||
- TestAccBatchJobDefinition
|
||||
ce:
|
||||
- TestAccCECostCategory
|
||||
cloudfront:
|
||||
- TestAccCloudFrontDistributionDataSource_basic
|
||||
- TestAccCloudFrontDistribution_isIPV6Enabled
|
||||
cloudtrail:
|
||||
- TestAccCloudTrailServiceAccount
|
||||
cloudwatch:
|
||||
|
@ -25,3 +25,45 @@ def example_distribution_config(ref):
|
||||
"Comment": "an optional comment that's not actually optional",
|
||||
"Enabled": False,
|
||||
}
|
||||
|
||||
|
||||
def example_dist_config_with_tags(ref):
|
||||
config = example_distribution_config(ref)
|
||||
config["Tags"] = {
|
||||
"Items": [{"Key": "k1", "Value": "v1"}, {"Key": "k2", "Value": "v2"}]
|
||||
}
|
||||
return config
|
||||
|
||||
|
||||
def example_dist_custom_config(ref):
|
||||
return {
|
||||
"CallerReference": ref,
|
||||
"Origins": {
|
||||
"Quantity": 1,
|
||||
"Items": [
|
||||
{
|
||||
"Id": "origin1",
|
||||
"DomainName": "asdf.s3.us-east-1.amazonaws.com",
|
||||
"CustomOriginConfig": {
|
||||
"HTTPPort": 80,
|
||||
"HTTPSPort": 443,
|
||||
"OriginKeepaliveTimeout": 5,
|
||||
"OriginProtocolPolicy": "http-only",
|
||||
"OriginReadTimeout": 30,
|
||||
"OriginSslProtocols": {
|
||||
"Quantity": 2,
|
||||
"Items": ["TLSv1", "SSLv3"],
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
"DefaultCacheBehavior": {
|
||||
"TargetOriginId": "origin1",
|
||||
"ViewerProtocolPolicy": "allow-all",
|
||||
"MinTTL": 10,
|
||||
"ForwardedValues": {"QueryString": False, "Cookies": {"Forward": "none"}},
|
||||
},
|
||||
"Comment": "an optional comment that's not actually optional",
|
||||
"Enabled": False,
|
||||
}
|
||||
|
21
tests/test_cloudfront/test_cloudfront_dist_tags.py
Normal file
21
tests/test_cloudfront/test_cloudfront_dist_tags.py
Normal file
@ -0,0 +1,21 @@
|
||||
import boto3
|
||||
from moto import mock_cloudfront
|
||||
from . import cloudfront_test_scaffolding as scaffold
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_with_tags():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
tags = {"Items": [{"Key": "k1", "Value": "v1"}, {"Key": "k2", "Value": "v2"}]}
|
||||
config = {"DistributionConfig": config, "Tags": tags}
|
||||
|
||||
resp = client.create_distribution_with_tags(DistributionConfigWithTags=config)
|
||||
resp.should.have.key("Distribution")
|
||||
|
||||
resp = client.list_tags_for_resource(Resource=resp["Distribution"]["ARN"])
|
||||
resp.should.have.key("Tags")
|
||||
resp["Tags"].should.have.key("Items").length_of(2)
|
||||
resp["Tags"]["Items"].should.contain({"Key": "k1", "Value": "v1"})
|
||||
resp["Tags"]["Items"].should.contain({"Key": "k2", "Value": "v2"})
|
@ -127,11 +127,105 @@ def test_create_distribution_s3_minimum():
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_with_additional_fields():
|
||||
def test_create_distribution_with_georestriction():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
config["Restrictions"] = {
|
||||
"GeoRestriction": {
|
||||
"RestrictionType": "whitelist",
|
||||
"Quantity": 2,
|
||||
"Items": ["GB", "US"],
|
||||
}
|
||||
}
|
||||
|
||||
resp = client.create_distribution(DistributionConfig=config)
|
||||
resp.should.have.key("Distribution")
|
||||
|
||||
distribution = resp["Distribution"]
|
||||
|
||||
distribution.should.have.key("DistributionConfig")
|
||||
config = distribution["DistributionConfig"]
|
||||
|
||||
config.should.have.key("Restrictions")
|
||||
config["Restrictions"].should.have.key("GeoRestriction")
|
||||
restriction = config["Restrictions"]["GeoRestriction"]
|
||||
restriction.should.have.key("RestrictionType").equals("whitelist")
|
||||
restriction.should.have.key("Quantity").equals(2)
|
||||
restriction["Items"].should.contain("US")
|
||||
restriction["Items"].should.contain("GB")
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_with_allowed_methods():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
config["DefaultCacheBehavior"]["AllowedMethods"] = {
|
||||
"Quantity": 3,
|
||||
"Items": ["GET", "HEAD", "PUT"],
|
||||
"CachedMethods": {
|
||||
"Quantity": 7,
|
||||
"Items": ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
|
||||
},
|
||||
}
|
||||
|
||||
dist = client.create_distribution(DistributionConfig=config)["Distribution"]
|
||||
|
||||
dist.should.have.key("DistributionConfig")
|
||||
cache = dist["DistributionConfig"]["DefaultCacheBehavior"]
|
||||
|
||||
cache.should.have.key("AllowedMethods").equals(
|
||||
{
|
||||
"CachedMethods": {
|
||||
"Items": ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
|
||||
"Quantity": 7,
|
||||
},
|
||||
"Items": ["GET", "HEAD", "PUT"],
|
||||
"Quantity": 3,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_with_origins():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
config["Origins"]["Items"][0]["ConnectionAttempts"] = 1
|
||||
config["Origins"]["Items"][0]["ConnectionTimeout"] = 2
|
||||
config["Origins"]["Items"][0]["OriginShield"] = {
|
||||
"Enabled": True,
|
||||
"OriginShieldRegion": "east",
|
||||
}
|
||||
|
||||
dist = client.create_distribution(DistributionConfig=config)["Distribution"]
|
||||
|
||||
origin = dist["DistributionConfig"]["Origins"]["Items"][0]
|
||||
origin.should.have.key("ConnectionAttempts").equals(1)
|
||||
origin.should.have.key("ConnectionTimeout").equals(2)
|
||||
origin.should.have.key("OriginShield").equals(
|
||||
{"Enabled": True, "OriginShieldRegion": "east"}
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
@pytest.mark.parametrize("compress", [True, False])
|
||||
@pytest.mark.parametrize("qs", [True, False])
|
||||
@pytest.mark.parametrize("smooth", [True, False])
|
||||
@pytest.mark.parametrize("ipv6", [True, False])
|
||||
def test_create_distribution_with_additional_fields(compress, qs, smooth, ipv6):
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
config["IsIPV6Enabled"] = ipv6
|
||||
config["Aliases"] = {"Quantity": 2, "Items": ["alias1", "alias2"]}
|
||||
config["DefaultCacheBehavior"]["ForwardedValues"]["Cookies"] = {
|
||||
"Forward": "whitelist",
|
||||
"WhitelistedNames": {"Quantity": 1, "Items": ["x-amz-header"]},
|
||||
}
|
||||
config["DefaultCacheBehavior"]["ForwardedValues"]["QueryString"] = qs
|
||||
config["DefaultCacheBehavior"]["Compress"] = compress
|
||||
config["DefaultCacheBehavior"]["MinTTL"] = 10
|
||||
config["DefaultCacheBehavior"]["SmoothStreaming"] = smooth
|
||||
config["PriceClass"] = "PriceClass_100"
|
||||
resp = client.create_distribution(DistributionConfig=config)
|
||||
distribution = resp["Distribution"]
|
||||
distribution.should.have.key("DistributionConfig")
|
||||
@ -140,6 +234,21 @@ def test_create_distribution_with_additional_fields():
|
||||
{"Items": ["alias1", "alias2"], "Quantity": 2}
|
||||
)
|
||||
|
||||
config.should.have.key("PriceClass").equals("PriceClass_100")
|
||||
config.should.have.key("IsIPV6Enabled").equals(ipv6)
|
||||
|
||||
config["DefaultCacheBehavior"].should.have.key("Compress").equals(compress)
|
||||
config["DefaultCacheBehavior"].should.have.key("MinTTL").equals(10)
|
||||
config["DefaultCacheBehavior"].should.have.key("SmoothStreaming").equals(smooth)
|
||||
|
||||
forwarded = config["DefaultCacheBehavior"]["ForwardedValues"]
|
||||
forwarded.should.have.key("QueryString").equals(qs)
|
||||
forwarded["Cookies"].should.have.key("Forward").equals("whitelist")
|
||||
forwarded["Cookies"].should.have.key("WhitelistedNames")
|
||||
forwarded["Cookies"]["WhitelistedNames"].should.have.key("Items").equals(
|
||||
["x-amz-header"]
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_returns_etag():
|
||||
@ -179,7 +288,9 @@ def test_create_distribution_needs_unique_caller_reference():
|
||||
dist2 = client.create_distribution(DistributionConfig=config)
|
||||
dist1_id.shouldnt.equal(dist2["Distribution"]["Id"])
|
||||
|
||||
# TODO: Verify two exist, using the list_distributions method
|
||||
resp = client.list_distributions()["DistributionList"]
|
||||
resp.should.have.key("Quantity").equals(2)
|
||||
resp.should.have.key("Items").length_of(2)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
@ -277,6 +388,29 @@ def test_create_distribution_with_invalid_s3_bucket():
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_distribution_custom_config():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_dist_custom_config("ref")
|
||||
|
||||
dist = client.create_distribution(DistributionConfig=config)["Distribution"][
|
||||
"DistributionConfig"
|
||||
]
|
||||
dist.should.have.key("Origins")
|
||||
dist["Origins"].should.have.key("Items").length_of(1)
|
||||
origin = dist["Origins"]["Items"][0]
|
||||
|
||||
origin.should.have.key("CustomOriginConfig")
|
||||
custom_config = origin["CustomOriginConfig"]
|
||||
|
||||
custom_config.should.have.key("HTTPPort").equals(80)
|
||||
custom_config.should.have.key("HTTPSPort").equals(443)
|
||||
custom_config.should.have.key("OriginProtocolPolicy").equals("http-only")
|
||||
custom_config.should.have.key("OriginSslProtocols").equals(
|
||||
{"Items": ["TLSv1", "SSLv3"], "Quantity": 2}
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_list_distributions_without_any():
|
||||
client = boto3.client("cloudfront", region_name="us-east-1")
|
||||
|
33
tests/test_cloudfront/test_cloudfront_invalidation.py
Normal file
33
tests/test_cloudfront/test_cloudfront_invalidation.py
Normal file
@ -0,0 +1,33 @@
|
||||
import boto3
|
||||
from moto import mock_cloudfront
|
||||
from . import cloudfront_test_scaffolding as scaffold
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_create_invalidation():
|
||||
client = boto3.client("cloudfront", region_name="us-west-1")
|
||||
config = scaffold.example_distribution_config("ref")
|
||||
resp = client.create_distribution(DistributionConfig=config)
|
||||
dist_id = resp["Distribution"]["Id"]
|
||||
|
||||
resp = client.create_invalidation(
|
||||
DistributionId=dist_id,
|
||||
InvalidationBatch={
|
||||
"Paths": {"Quantity": 2, "Items": ["/path1", "/path2"]},
|
||||
"CallerReference": "ref2",
|
||||
},
|
||||
)
|
||||
|
||||
resp.should.have.key("Location")
|
||||
resp.should.have.key("Invalidation")
|
||||
|
||||
resp["Invalidation"].should.have.key("Id")
|
||||
resp["Invalidation"].should.have.key("Status").equals("COMPLETED")
|
||||
resp["Invalidation"].should.have.key("CreateTime")
|
||||
resp["Invalidation"].should.have.key("InvalidationBatch").equals(
|
||||
{
|
||||
"Paths": {"Quantity": 2, "Items": ["/path1", "/path2"]},
|
||||
"CallerReference": "ref2",
|
||||
}
|
||||
)
|
@ -1,9 +1,11 @@
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
import xmltodict
|
||||
|
||||
from moto import mock_cloudfront
|
||||
import moto.server as server
|
||||
|
||||
|
||||
@mock_cloudfront
|
||||
def test_cloudfront_list():
|
||||
backend = server.create_backend_app("cloudfront")
|
||||
test_client = backend.test_client()
|
||||
|
Loading…
Reference in New Issue
Block a user