fixed tf suite: Route53HostedZone (#5223)
This commit is contained in:
parent
1698c52740
commit
631e887b5e
@ -89,6 +89,28 @@ class HostedZoneNotEmpty(Route53ClientError):
|
|||||||
self.content_type = "text/xml"
|
self.content_type = "text/xml"
|
||||||
|
|
||||||
|
|
||||||
|
class PublicZoneVPCAssociation(Route53ClientError):
|
||||||
|
"""Public hosted zone can't be associated."""
|
||||||
|
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
message = "You're trying to associate a VPC with a public hosted zone. Amazon Route 53 doesn't support associating a VPC with a public hosted zone."
|
||||||
|
super().__init__("PublicZoneVPCAssociation", message)
|
||||||
|
self.content_type = "text/xml"
|
||||||
|
|
||||||
|
|
||||||
|
class LastVPCAssociation(Route53ClientError):
|
||||||
|
"""Last VPC can't be disassociate."""
|
||||||
|
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
message = "The VPC that you're trying to disassociate from the private hosted zone is the last VPC that is associated with the hosted zone. Amazon Route 53 doesn't support disassociating the last VPC from a hosted zone."
|
||||||
|
super().__init__("LastVPCAssociation", message)
|
||||||
|
self.content_type = "text/xml"
|
||||||
|
|
||||||
|
|
||||||
class NoSuchQueryLoggingConfig(Route53ClientError):
|
class NoSuchQueryLoggingConfig(Route53ClientError):
|
||||||
"""Query log config does not exist."""
|
"""Query log config does not exist."""
|
||||||
|
|
||||||
|
@ -11,11 +11,13 @@ from jinja2 import Template
|
|||||||
from moto.route53.exceptions import (
|
from moto.route53.exceptions import (
|
||||||
HostedZoneNotEmpty,
|
HostedZoneNotEmpty,
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
|
LastVPCAssociation,
|
||||||
NoSuchCloudWatchLogsLogGroup,
|
NoSuchCloudWatchLogsLogGroup,
|
||||||
NoSuchDelegationSet,
|
NoSuchDelegationSet,
|
||||||
NoSuchHealthCheck,
|
NoSuchHealthCheck,
|
||||||
NoSuchHostedZone,
|
NoSuchHostedZone,
|
||||||
NoSuchQueryLoggingConfig,
|
NoSuchQueryLoggingConfig,
|
||||||
|
PublicZoneVPCAssociation,
|
||||||
QueryLoggingConfigAlreadyExists,
|
QueryLoggingConfigAlreadyExists,
|
||||||
)
|
)
|
||||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel, get_account_id
|
from moto.core import BaseBackend, BaseModel, CloudFormationModel, get_account_id
|
||||||
@ -236,19 +238,14 @@ class FakeZone(CloudFormationModel):
|
|||||||
name,
|
name,
|
||||||
id_,
|
id_,
|
||||||
private_zone,
|
private_zone,
|
||||||
vpcid=None,
|
|
||||||
vpcregion=None,
|
|
||||||
comment=None,
|
comment=None,
|
||||||
delegation_set=None,
|
delegation_set=None,
|
||||||
):
|
):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.id = id_
|
self.id = id_
|
||||||
|
self.vpcs = []
|
||||||
if comment is not None:
|
if comment is not None:
|
||||||
self.comment = comment
|
self.comment = comment
|
||||||
if vpcid is not None:
|
|
||||||
self.vpcid = vpcid
|
|
||||||
if vpcregion is not None:
|
|
||||||
self.vpcregion = vpcregion
|
|
||||||
self.private_zone = private_zone
|
self.private_zone = private_zone
|
||||||
self.rrsets = []
|
self.rrsets = []
|
||||||
self.delegation_set = delegation_set
|
self.delegation_set = delegation_set
|
||||||
@ -287,6 +284,19 @@ class FakeZone(CloudFormationModel):
|
|||||||
if record_set.set_identifier != set_identifier
|
if record_set.set_identifier != set_identifier
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def add_vpc(self, vpc_id, vpc_region):
|
||||||
|
vpc = {}
|
||||||
|
if vpc_id is not None:
|
||||||
|
vpc["vpc_id"] = vpc_id
|
||||||
|
if vpc_region is not None:
|
||||||
|
vpc["vpc_region"] = vpc_region
|
||||||
|
if vpc_id or vpc_region:
|
||||||
|
self.vpcs.append(vpc)
|
||||||
|
return vpc
|
||||||
|
|
||||||
|
def delete_vpc(self, vpc_id):
|
||||||
|
self.vpcs = [vpc for vpc in self.vpcs if vpc["vpc_id"] != vpc_id]
|
||||||
|
|
||||||
def get_record_sets(self, start_type, start_name):
|
def get_record_sets(self, start_type, start_name):
|
||||||
def predicate(rrset):
|
def predicate(rrset):
|
||||||
rrset_name_reversed = reverse_domain_name(rrset.name)
|
rrset_name_reversed = reverse_domain_name(rrset.name)
|
||||||
@ -420,8 +430,6 @@ class Route53Backend(BaseBackend):
|
|||||||
name,
|
name,
|
||||||
new_id,
|
new_id,
|
||||||
private_zone=private_zone,
|
private_zone=private_zone,
|
||||||
vpcid=vpcid,
|
|
||||||
vpcregion=vpcregion,
|
|
||||||
comment=comment,
|
comment=comment,
|
||||||
delegation_set=delegation_set,
|
delegation_set=delegation_set,
|
||||||
)
|
)
|
||||||
@ -433,6 +441,7 @@ class Route53Backend(BaseBackend):
|
|||||||
"Type": "NS",
|
"Type": "NS",
|
||||||
}
|
}
|
||||||
new_zone.add_rrset(record_set)
|
new_zone.add_rrset(record_set)
|
||||||
|
new_zone.add_vpc(vpcid, vpcregion)
|
||||||
self.zones[new_id] = new_zone
|
self.zones[new_id] = new_zone
|
||||||
return new_zone
|
return new_zone
|
||||||
|
|
||||||
@ -440,6 +449,20 @@ class Route53Backend(BaseBackend):
|
|||||||
# check if hosted zone exists
|
# check if hosted zone exists
|
||||||
self.get_hosted_zone(zone_id)
|
self.get_hosted_zone(zone_id)
|
||||||
|
|
||||||
|
def associate_vpc(self, zone_id, vpcid, vpcregion):
|
||||||
|
zone = self.get_hosted_zone(zone_id)
|
||||||
|
if not zone.private_zone:
|
||||||
|
raise PublicZoneVPCAssociation()
|
||||||
|
zone.add_vpc(vpcid, vpcregion)
|
||||||
|
return zone
|
||||||
|
|
||||||
|
def disassociate_vpc(self, zone_id, vpcid):
|
||||||
|
zone = self.get_hosted_zone(zone_id)
|
||||||
|
if len(zone.vpcs) <= 1:
|
||||||
|
raise LastVPCAssociation()
|
||||||
|
zone.delete_vpc(vpcid)
|
||||||
|
return zone
|
||||||
|
|
||||||
def change_tags_for_resource(self, resource_id, tags):
|
def change_tags_for_resource(self, resource_id, tags):
|
||||||
if "Tag" in tags:
|
if "Tag" in tags:
|
||||||
if isinstance(tags["Tag"], list):
|
if isinstance(tags["Tag"], list):
|
||||||
@ -545,15 +568,16 @@ class Route53Backend(BaseBackend):
|
|||||||
for zone in self.list_hosted_zones():
|
for zone in self.list_hosted_zones():
|
||||||
if zone.private_zone is True:
|
if zone.private_zone is True:
|
||||||
this_zone = self.get_hosted_zone(zone.id)
|
this_zone = self.get_hosted_zone(zone.id)
|
||||||
if this_zone.vpcid == vpc_id:
|
for vpc in this_zone.vpcs:
|
||||||
this_id = f"/hostedzone/{zone.id}"
|
if vpc["vpc_id"] == vpc_id:
|
||||||
zone_list.append(
|
this_id = f"/hostedzone/{zone.id}"
|
||||||
{
|
zone_list.append(
|
||||||
"HostedZoneId": this_id,
|
{
|
||||||
"Name": zone.name,
|
"HostedZoneId": this_id,
|
||||||
"Owner": {"OwningAccount": get_account_id()},
|
"Name": zone.name,
|
||||||
}
|
"Owner": {"OwningAccount": get_account_id()},
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return zone_list
|
return zone_list
|
||||||
|
|
||||||
@ -581,6 +605,11 @@ class Route53Backend(BaseBackend):
|
|||||||
raise HostedZoneNotEmpty()
|
raise HostedZoneNotEmpty()
|
||||||
return self.zones.pop(id_.replace("/hostedzone/", ""), None)
|
return self.zones.pop(id_.replace("/hostedzone/", ""), None)
|
||||||
|
|
||||||
|
def update_hosted_zone_comment(self, id_, comment):
|
||||||
|
zone = self.get_hosted_zone(id_)
|
||||||
|
zone.comment = comment
|
||||||
|
return zone
|
||||||
|
|
||||||
def create_health_check(self, caller_reference, health_check_args):
|
def create_health_check(self, caller_reference, health_check_args):
|
||||||
health_check_id = str(uuid.uuid4())
|
health_check_id = str(uuid.uuid4())
|
||||||
health_check = HealthCheck(health_check_id, caller_reference, health_check_args)
|
health_check = HealthCheck(health_check_id, caller_reference, health_check_args)
|
||||||
|
@ -114,6 +114,14 @@ class Route53(BaseResponse):
|
|||||||
elif request.method == "DELETE":
|
elif request.method == "DELETE":
|
||||||
route53_backend.delete_hosted_zone(zoneid)
|
route53_backend.delete_hosted_zone(zoneid)
|
||||||
return 200, headers, DELETE_HOSTED_ZONE_RESPONSE
|
return 200, headers, DELETE_HOSTED_ZONE_RESPONSE
|
||||||
|
elif request.method == "POST":
|
||||||
|
elements = xmltodict.parse(self.body)
|
||||||
|
comment = elements.get("UpdateHostedZoneCommentRequest", {}).get(
|
||||||
|
"Comment", None
|
||||||
|
)
|
||||||
|
zone = route53_backend.update_hosted_zone_comment(zoneid, comment)
|
||||||
|
template = Template(UPDATE_HOSTED_ZONE_COMMENT_RESPONSE)
|
||||||
|
return 200, headers, template.render(zone=zone)
|
||||||
|
|
||||||
def get_dnssec_response(self, request, full_url, headers):
|
def get_dnssec_response(self, request, full_url, headers):
|
||||||
# returns static response
|
# returns static response
|
||||||
@ -129,6 +137,43 @@ class Route53(BaseResponse):
|
|||||||
route53_backend.get_dnssec(zoneid)
|
route53_backend.get_dnssec(zoneid)
|
||||||
return 200, headers, GET_DNSSEC
|
return 200, headers, GET_DNSSEC
|
||||||
|
|
||||||
|
def associate_vpc_response(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
zoneid = parsed_url.path.rstrip("/").rsplit("/", 2)[1]
|
||||||
|
|
||||||
|
elements = xmltodict.parse(self.body)
|
||||||
|
comment = vpc = elements.get("AssociateVPCWithHostedZoneRequest", {}).get(
|
||||||
|
"Comment", {}
|
||||||
|
)
|
||||||
|
vpc = elements.get("AssociateVPCWithHostedZoneRequest", {}).get("VPC", {})
|
||||||
|
vpcid = vpc.get("VPCId", None)
|
||||||
|
vpcregion = vpc.get("VPCRegion", None)
|
||||||
|
|
||||||
|
route53_backend.associate_vpc(zoneid, vpcid, vpcregion)
|
||||||
|
|
||||||
|
template = Template(ASSOCIATE_VPC_RESPONSE)
|
||||||
|
return 200, headers, template.render(comment=comment)
|
||||||
|
|
||||||
|
def disassociate_vpc_response(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
zoneid = parsed_url.path.rstrip("/").rsplit("/", 2)[1]
|
||||||
|
|
||||||
|
elements = xmltodict.parse(self.body)
|
||||||
|
comment = vpc = elements.get("DisassociateVPCFromHostedZoneRequest", {}).get(
|
||||||
|
"Comment", {}
|
||||||
|
)
|
||||||
|
vpc = elements.get("DisassociateVPCFromHostedZoneRequest", {}).get("VPC", {})
|
||||||
|
vpcid = vpc.get("VPCId", None)
|
||||||
|
|
||||||
|
route53_backend.disassociate_vpc(zoneid, vpcid)
|
||||||
|
|
||||||
|
template = Template(DISASSOCIATE_VPC_RESPONSE)
|
||||||
|
return 200, headers, template.render(comment)
|
||||||
|
|
||||||
def rrset_response(self, request, full_url, headers):
|
def rrset_response(self, request, full_url, headers):
|
||||||
self.setup_class(request, full_url, headers)
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
@ -544,10 +589,12 @@ GET_HOSTED_ZONE_RESPONSE = """<GetHostedZoneResponse xmlns="https://route53.amaz
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if zone.private_zone %}
|
{% if zone.private_zone %}
|
||||||
<VPCs>
|
<VPCs>
|
||||||
|
{% for vpc in zone.vpcs %}
|
||||||
<VPC>
|
<VPC>
|
||||||
<VPCId>{{zone.vpcid}}</VPCId>
|
<VPCId>{{vpc.vpc_id}}</VPCId>
|
||||||
<VPCRegion>{{zone.vpcregion}}</VPCRegion>
|
<VPCRegion>{{vpc.vpc_region}}</VPCRegion>
|
||||||
</VPC>
|
</VPC>
|
||||||
|
{% endfor %}
|
||||||
</VPCs>
|
</VPCs>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</GetHostedZoneResponse>"""
|
</GetHostedZoneResponse>"""
|
||||||
@ -758,3 +805,41 @@ GET_HEALTH_CHECK_RESPONSE = """<?xml version="1.0"?>
|
|||||||
{{ health_check.to_xml() }}
|
{{ health_check.to_xml() }}
|
||||||
</GetHealthCheckResponse>
|
</GetHealthCheckResponse>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
UPDATE_HOSTED_ZONE_COMMENT_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<UpdateHostedZoneCommentResponse>
|
||||||
|
<HostedZone>
|
||||||
|
<Config>
|
||||||
|
{% if zone.comment %}
|
||||||
|
<Comment>{{ zone.comment }}</Comment>
|
||||||
|
{% endif %}
|
||||||
|
<PrivateZone>{{ 'true' if zone.private_zone else 'false' }}</PrivateZone>
|
||||||
|
</Config>
|
||||||
|
<Id>/hostedzone/{{ zone.id }}</Id>
|
||||||
|
<Name>{{ zone.name }}</Name>
|
||||||
|
<ResourceRecordSetCount>{{ zone.rrsets|count }}</ResourceRecordSetCount>
|
||||||
|
</HostedZone>
|
||||||
|
</UpdateHostedZoneCommentResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
ASSOCIATE_VPC_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<AssociateVPCWithHostedZoneResponse>
|
||||||
|
<ChangeInfo>
|
||||||
|
<Comment>{{ comment }}</Comment>
|
||||||
|
<Id>/change/a1b2c3d4</Id>
|
||||||
|
<Status>INSYNC</Status>
|
||||||
|
<SubmittedAt>2017-03-31T01:36:41.958Z</SubmittedAt>
|
||||||
|
</ChangeInfo>
|
||||||
|
</AssociateVPCWithHostedZoneResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
DISASSOCIATE_VPC_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<DisassociateVPCFromHostedZoneResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
|
||||||
|
<ChangeInfo>
|
||||||
|
<Comment>{{ comment }}</Comment>
|
||||||
|
<Id>/change/a1b2c3d4</Id>
|
||||||
|
<Status>INSYNC</Status>
|
||||||
|
<SubmittedAt>2017-03-31T01:36:41.958Z</SubmittedAt>
|
||||||
|
</ChangeInfo>
|
||||||
|
</DisassociateVPCFromHostedZoneResponse>
|
||||||
|
"""
|
||||||
|
@ -17,6 +17,8 @@ url_paths = {
|
|||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)$": Route53().get_or_delete_hostzone_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)$": Route53().get_or_delete_hostzone_response,
|
||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/rrset/?$": Route53().rrset_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/rrset/?$": Route53().rrset_response,
|
||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/dnssec/?$": Route53().get_dnssec_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/dnssec/?$": Route53().get_dnssec_response,
|
||||||
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/associatevpc/?$": Route53().associate_vpc_response,
|
||||||
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzone/(?P<zone_id>[^/]+)/disassociatevpc/?$": Route53().disassociate_vpc_response,
|
||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzonesbyname": Route53().list_hosted_zones_by_name_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzonesbyname": Route53().list_hosted_zones_by_name_response,
|
||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzonesbyvpc": Route53().list_hosted_zones_by_vpc_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzonesbyvpc": Route53().list_hosted_zones_by_vpc_response,
|
||||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzonecount": Route53().get_hosted_zone_count_response,
|
r"{0}/(?P<api_version>[\d_-]+)/hostedzonecount": Route53().get_hosted_zone_count_response,
|
||||||
|
@ -163,6 +163,17 @@ route53:
|
|||||||
- TestAccRoute53Record_longTXTrecord
|
- TestAccRoute53Record_longTXTrecord
|
||||||
- TestAccRoute53Record_doNotAllowOverwrite
|
- TestAccRoute53Record_doNotAllowOverwrite
|
||||||
- TestAccRoute53Record_allowOverwrite
|
- TestAccRoute53Record_allowOverwrite
|
||||||
|
- TestAccRoute53Zone_basic
|
||||||
|
- TestAccRoute53Zone_disappears
|
||||||
|
- TestAccRoute53Zone_multiple
|
||||||
|
- TestAccRoute53Zone_comment
|
||||||
|
- TestAccRoute53Zone_delegationSetID
|
||||||
|
- TestAccRoute53Zone_forceDestroy
|
||||||
|
- TestAccRoute53Zone_ForceDestroy_trailingPeriod
|
||||||
|
- TestAccRoute53Zone_tags
|
||||||
|
- TestAccRoute53Zone_VPC_single
|
||||||
|
- TestAccRoute53Zone_VPC_multiple
|
||||||
|
- TestAccRoute53Zone_VPC_updates
|
||||||
s3:
|
s3:
|
||||||
- TestAccS3BucketPolicy
|
- TestAccS3BucketPolicy
|
||||||
- TestAccS3BucketPublicAccessBlock
|
- TestAccS3BucketPublicAccessBlock
|
||||||
|
@ -506,11 +506,7 @@ def test_hosted_zone_private_zone_preserved():
|
|||||||
hosted_zone = conn.get_hosted_zone(Id=zone_id)
|
hosted_zone = conn.get_hosted_zone(Id=zone_id)
|
||||||
hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True)
|
hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True)
|
||||||
hosted_zone.should.have.key("VPCs")
|
hosted_zone.should.have.key("VPCs")
|
||||||
hosted_zone["VPCs"].should.have.length_of(1)
|
hosted_zone["VPCs"].should.have.length_of(0)
|
||||||
hosted_zone["VPCs"][0].should.have.key("VPCId")
|
|
||||||
hosted_zone["VPCs"][0].should.have.key("VPCRegion")
|
|
||||||
hosted_zone["VPCs"][0]["VPCId"].should.equal("")
|
|
||||||
hosted_zone["VPCs"][0]["VPCRegion"].should.equal("")
|
|
||||||
|
|
||||||
hosted_zones = conn.list_hosted_zones()
|
hosted_zones = conn.list_hosted_zones()
|
||||||
hosted_zones["HostedZones"].should.have.length_of(2)
|
hosted_zones["HostedZones"].should.have.length_of(2)
|
||||||
|
Loading…
Reference in New Issue
Block a user