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"
|
||||
|
||||
|
||||
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):
|
||||
"""Query log config does not exist."""
|
||||
|
||||
|
@ -11,11 +11,13 @@ from jinja2 import Template
|
||||
from moto.route53.exceptions import (
|
||||
HostedZoneNotEmpty,
|
||||
InvalidInput,
|
||||
LastVPCAssociation,
|
||||
NoSuchCloudWatchLogsLogGroup,
|
||||
NoSuchDelegationSet,
|
||||
NoSuchHealthCheck,
|
||||
NoSuchHostedZone,
|
||||
NoSuchQueryLoggingConfig,
|
||||
PublicZoneVPCAssociation,
|
||||
QueryLoggingConfigAlreadyExists,
|
||||
)
|
||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel, get_account_id
|
||||
@ -236,19 +238,14 @@ class FakeZone(CloudFormationModel):
|
||||
name,
|
||||
id_,
|
||||
private_zone,
|
||||
vpcid=None,
|
||||
vpcregion=None,
|
||||
comment=None,
|
||||
delegation_set=None,
|
||||
):
|
||||
self.name = name
|
||||
self.id = id_
|
||||
self.vpcs = []
|
||||
if comment is not None:
|
||||
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.rrsets = []
|
||||
self.delegation_set = delegation_set
|
||||
@ -287,6 +284,19 @@ class FakeZone(CloudFormationModel):
|
||||
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 predicate(rrset):
|
||||
rrset_name_reversed = reverse_domain_name(rrset.name)
|
||||
@ -420,8 +430,6 @@ class Route53Backend(BaseBackend):
|
||||
name,
|
||||
new_id,
|
||||
private_zone=private_zone,
|
||||
vpcid=vpcid,
|
||||
vpcregion=vpcregion,
|
||||
comment=comment,
|
||||
delegation_set=delegation_set,
|
||||
)
|
||||
@ -433,6 +441,7 @@ class Route53Backend(BaseBackend):
|
||||
"Type": "NS",
|
||||
}
|
||||
new_zone.add_rrset(record_set)
|
||||
new_zone.add_vpc(vpcid, vpcregion)
|
||||
self.zones[new_id] = new_zone
|
||||
return new_zone
|
||||
|
||||
@ -440,6 +449,20 @@ class Route53Backend(BaseBackend):
|
||||
# check if hosted zone exists
|
||||
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):
|
||||
if "Tag" in tags:
|
||||
if isinstance(tags["Tag"], list):
|
||||
@ -545,15 +568,16 @@ class Route53Backend(BaseBackend):
|
||||
for zone in self.list_hosted_zones():
|
||||
if zone.private_zone is True:
|
||||
this_zone = self.get_hosted_zone(zone.id)
|
||||
if this_zone.vpcid == vpc_id:
|
||||
this_id = f"/hostedzone/{zone.id}"
|
||||
zone_list.append(
|
||||
{
|
||||
"HostedZoneId": this_id,
|
||||
"Name": zone.name,
|
||||
"Owner": {"OwningAccount": get_account_id()},
|
||||
}
|
||||
)
|
||||
for vpc in this_zone.vpcs:
|
||||
if vpc["vpc_id"] == vpc_id:
|
||||
this_id = f"/hostedzone/{zone.id}"
|
||||
zone_list.append(
|
||||
{
|
||||
"HostedZoneId": this_id,
|
||||
"Name": zone.name,
|
||||
"Owner": {"OwningAccount": get_account_id()},
|
||||
}
|
||||
)
|
||||
|
||||
return zone_list
|
||||
|
||||
@ -581,6 +605,11 @@ class Route53Backend(BaseBackend):
|
||||
raise HostedZoneNotEmpty()
|
||||
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):
|
||||
health_check_id = str(uuid.uuid4())
|
||||
health_check = HealthCheck(health_check_id, caller_reference, health_check_args)
|
||||
|
@ -114,6 +114,14 @@ class Route53(BaseResponse):
|
||||
elif request.method == "DELETE":
|
||||
route53_backend.delete_hosted_zone(zoneid)
|
||||
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):
|
||||
# returns static response
|
||||
@ -129,6 +137,43 @@ class Route53(BaseResponse):
|
||||
route53_backend.get_dnssec(zoneid)
|
||||
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):
|
||||
self.setup_class(request, full_url, headers)
|
||||
|
||||
@ -544,10 +589,12 @@ GET_HOSTED_ZONE_RESPONSE = """<GetHostedZoneResponse xmlns="https://route53.amaz
|
||||
{% endif %}
|
||||
{% if zone.private_zone %}
|
||||
<VPCs>
|
||||
{% for vpc in zone.vpcs %}
|
||||
<VPC>
|
||||
<VPCId>{{zone.vpcid}}</VPCId>
|
||||
<VPCRegion>{{zone.vpcregion}}</VPCRegion>
|
||||
<VPCId>{{vpc.vpc_id}}</VPCId>
|
||||
<VPCRegion>{{vpc.vpc_region}}</VPCRegion>
|
||||
</VPC>
|
||||
{% endfor %}
|
||||
</VPCs>
|
||||
{% endif %}
|
||||
</GetHostedZoneResponse>"""
|
||||
@ -758,3 +805,41 @@ GET_HEALTH_CHECK_RESPONSE = """<?xml version="1.0"?>
|
||||
{{ health_check.to_xml() }}
|
||||
</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>[^/]+)/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>[^/]+)/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_-]+)/hostedzonesbyvpc": Route53().list_hosted_zones_by_vpc_response,
|
||||
r"{0}/(?P<api_version>[\d_-]+)/hostedzonecount": Route53().get_hosted_zone_count_response,
|
||||
|
@ -163,6 +163,17 @@ route53:
|
||||
- TestAccRoute53Record_longTXTrecord
|
||||
- TestAccRoute53Record_doNotAllowOverwrite
|
||||
- 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:
|
||||
- TestAccS3BucketPolicy
|
||||
- TestAccS3BucketPublicAccessBlock
|
||||
|
@ -506,11 +506,7 @@ def test_hosted_zone_private_zone_preserved():
|
||||
hosted_zone = conn.get_hosted_zone(Id=zone_id)
|
||||
hosted_zone["HostedZone"]["Config"]["PrivateZone"].should.equal(True)
|
||||
hosted_zone.should.have.key("VPCs")
|
||||
hosted_zone["VPCs"].should.have.length_of(1)
|
||||
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_zone["VPCs"].should.have.length_of(0)
|
||||
|
||||
hosted_zones = conn.list_hosted_zones()
|
||||
hosted_zones["HostedZones"].should.have.length_of(2)
|
||||
|
Loading…
Reference in New Issue
Block a user