Route53: list_hosted_zones() now supports pagination (#7328)
This commit is contained in:
parent
2c3f735e85
commit
ff9dda224f
@ -723,7 +723,11 @@ class Route53Backend(BaseBackend):
|
|||||||
the_zone.delete_rrset(record_set)
|
the_zone.delete_rrset(record_set)
|
||||||
the_zone.rr_changes.append(original_change)
|
the_zone.rr_changes.append(original_change)
|
||||||
|
|
||||||
|
@paginate(pagination_model=PAGINATION_MODEL) # type: ignore[misc]
|
||||||
def list_hosted_zones(self) -> List[FakeZone]:
|
def list_hosted_zones(self) -> List[FakeZone]:
|
||||||
|
"""
|
||||||
|
The parameters DelegationSetId and HostedZoneType are not yet implemented
|
||||||
|
"""
|
||||||
return list(self.zones.values())
|
return list(self.zones.values())
|
||||||
|
|
||||||
def list_hosted_zones_by_name(
|
def list_hosted_zones_by_name(
|
||||||
@ -733,7 +737,7 @@ class Route53Backend(BaseBackend):
|
|||||||
dnsname = dnsnames[0]
|
dnsname = dnsnames[0]
|
||||||
if dnsname[-1] != ".":
|
if dnsname[-1] != ".":
|
||||||
dnsname += "."
|
dnsname += "."
|
||||||
zones = [zone for zone in self.list_hosted_zones() if zone.name == dnsname]
|
zones = [zone for zone in self.zones.values() if zone.name == dnsname]
|
||||||
else:
|
else:
|
||||||
dnsname = None
|
dnsname = None
|
||||||
# sort by names, but with domain components reversed
|
# sort by names, but with domain components reversed
|
||||||
@ -745,8 +749,7 @@ class Route53Backend(BaseBackend):
|
|||||||
domains = domains[-1:] + domains[:-1]
|
domains = domains[-1:] + domains[:-1]
|
||||||
return ".".join(reversed(domains))
|
return ".".join(reversed(domains))
|
||||||
|
|
||||||
zones = self.list_hosted_zones()
|
zones = sorted(self.zones.values(), key=sort_key)
|
||||||
zones = sorted(zones, key=sort_key)
|
|
||||||
return dnsname, zones
|
return dnsname, zones
|
||||||
|
|
||||||
def list_hosted_zones_by_vpc(self, vpc_id: str) -> List[Dict[str, Any]]:
|
def list_hosted_zones_by_vpc(self, vpc_id: str) -> List[Dict[str, Any]]:
|
||||||
@ -754,7 +757,7 @@ class Route53Backend(BaseBackend):
|
|||||||
Pagination is not yet implemented
|
Pagination is not yet implemented
|
||||||
"""
|
"""
|
||||||
zone_list = []
|
zone_list = []
|
||||||
for zone in self.list_hosted_zones():
|
for zone in self.zones.values():
|
||||||
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)
|
||||||
for vpc in this_zone.vpcs:
|
for vpc in this_zone.vpcs:
|
||||||
@ -776,10 +779,10 @@ class Route53Backend(BaseBackend):
|
|||||||
return the_zone
|
return the_zone
|
||||||
|
|
||||||
def get_hosted_zone_count(self) -> int:
|
def get_hosted_zone_count(self) -> int:
|
||||||
return len(self.list_hosted_zones())
|
return len(self.zones.values())
|
||||||
|
|
||||||
def get_hosted_zone_by_name(self, name: str) -> Optional[FakeZone]:
|
def get_hosted_zone_by_name(self, name: str) -> Optional[FakeZone]:
|
||||||
for zone in self.list_hosted_zones():
|
for zone in self.zones.values():
|
||||||
if zone.name == name:
|
if zone.name == name:
|
||||||
return zone
|
return zone
|
||||||
return None
|
return None
|
||||||
@ -875,8 +878,7 @@ class Route53Backend(BaseBackend):
|
|||||||
) -> QueryLoggingConfig:
|
) -> QueryLoggingConfig:
|
||||||
"""Process the create_query_logging_config request."""
|
"""Process the create_query_logging_config request."""
|
||||||
# Does the hosted_zone_id exist?
|
# Does the hosted_zone_id exist?
|
||||||
response = self.list_hosted_zones()
|
zones = list(self.zones.values())
|
||||||
zones = list(response) if response else []
|
|
||||||
for zone in zones:
|
for zone in zones:
|
||||||
if zone.id == hosted_zone_id:
|
if zone.id == hosted_zone_id:
|
||||||
break
|
break
|
||||||
@ -940,8 +942,7 @@ class Route53Backend(BaseBackend):
|
|||||||
"""Return a list of query logging configs."""
|
"""Return a list of query logging configs."""
|
||||||
if hosted_zone_id:
|
if hosted_zone_id:
|
||||||
# Does the hosted_zone_id exist?
|
# Does the hosted_zone_id exist?
|
||||||
response = self.list_hosted_zones()
|
zones = list(self.zones.values())
|
||||||
zones = list(response) if response else []
|
|
||||||
for zone in zones:
|
for zone in zones:
|
||||||
if zone.id == hosted_zone_id:
|
if zone.id == hosted_zone_id:
|
||||||
break
|
break
|
||||||
|
@ -81,16 +81,27 @@ class Route53(BaseResponse):
|
|||||||
vpcregion=vpcregion,
|
vpcregion=vpcregion,
|
||||||
delegation_set_id=delegation_set_id,
|
delegation_set_id=delegation_set_id,
|
||||||
)
|
)
|
||||||
template = Template(CREATE_HOSTED_ZONE_RESPONSE)
|
template = Template(CREATE_HOSTED_ZONE_RESPONSE).render(zone=new_zone)
|
||||||
headers = {
|
headers = {
|
||||||
"Location": f"https://route53.amazonaws.com/2013-04-01/hostedzone/{new_zone.id}"
|
"Location": f"https://route53.amazonaws.com/2013-04-01/hostedzone/{new_zone.id}"
|
||||||
}
|
}
|
||||||
return 201, headers, template.render(zone=new_zone)
|
return 201, headers, template
|
||||||
|
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
all_zones = self.backend.list_hosted_zones()
|
max_size = self.querystring.get("maxitems", [None])[0]
|
||||||
template = Template(LIST_HOSTED_ZONES_RESPONSE)
|
if max_size:
|
||||||
return 200, headers, template.render(zones=all_zones)
|
max_size = int(max_size)
|
||||||
|
marker = self.querystring.get("marker", [None])[0]
|
||||||
|
zone_page, next_marker = self.backend.list_hosted_zones(
|
||||||
|
marker=marker, max_size=max_size
|
||||||
|
)
|
||||||
|
template = Template(LIST_HOSTED_ZONES_RESPONSE).render(
|
||||||
|
zones=zone_page,
|
||||||
|
marker=marker,
|
||||||
|
next_marker=next_marker,
|
||||||
|
max_items=max_size,
|
||||||
|
)
|
||||||
|
return 200, headers, template
|
||||||
|
|
||||||
def list_hosted_zones_by_name_response(
|
def list_hosted_zones_by_name_response(
|
||||||
self, request: Any, full_url: str, headers: Any
|
self, request: Any, full_url: str, headers: Any
|
||||||
@ -704,7 +715,10 @@ LIST_HOSTED_ZONES_RESPONSE = """<ListHostedZonesResponse xmlns="https://route53.
|
|||||||
</HostedZone>
|
</HostedZone>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</HostedZones>
|
</HostedZones>
|
||||||
<IsTruncated>false</IsTruncated>
|
{% if marker %}<Marker>{{ marker }}</Marker>{% endif %}
|
||||||
|
{%if next_marker %}<NextMarker>{{ next_marker }}</NextMarker>{% endif %}
|
||||||
|
{%if max_items %}<MaxItems>{{ max_items }}</MaxItems>{% endif %}
|
||||||
|
<IsTruncated>{{ 'true' if next_marker else 'false'}}</IsTruncated>
|
||||||
</ListHostedZonesResponse>"""
|
</ListHostedZonesResponse>"""
|
||||||
|
|
||||||
LIST_HOSTED_ZONES_BY_NAME_RESPONSE = """<ListHostedZonesByNameResponse xmlns="{{ xmlns }}">
|
LIST_HOSTED_ZONES_BY_NAME_RESPONSE = """<ListHostedZonesByNameResponse xmlns="{{ xmlns }}">
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
from .exceptions import InvalidPaginationToken
|
from .exceptions import InvalidPaginationToken
|
||||||
|
|
||||||
PAGINATION_MODEL = {
|
PAGINATION_MODEL = {
|
||||||
|
"list_hosted_zones": {
|
||||||
|
"input_token": "marker",
|
||||||
|
"limit_key": "max_size",
|
||||||
|
"limit_default": 100,
|
||||||
|
"unique_attribute": "id",
|
||||||
|
},
|
||||||
"list_query_logging_configs": {
|
"list_query_logging_configs": {
|
||||||
"input_token": "next_token",
|
"input_token": "next_token",
|
||||||
"limit_key": "max_results",
|
"limit_key": "max_results",
|
||||||
|
@ -602,6 +602,44 @@ def test_list_hosted_zones_by_dns_name():
|
|||||||
assert zones["HostedZones"][3]["CallerReference"] == str(hash("bar"))
|
assert zones["HostedZones"][3]["CallerReference"] == str(hash("bar"))
|
||||||
|
|
||||||
|
|
||||||
|
@mock_aws
|
||||||
|
def test_list_hosted_zones_pagination():
|
||||||
|
conn = boto3.client("route53", region_name="us-east-1")
|
||||||
|
|
||||||
|
for idx in range(150):
|
||||||
|
conn.create_hosted_zone(
|
||||||
|
Name=f"test{idx}.com.", CallerReference=str(hash(f"h{idx}"))
|
||||||
|
)
|
||||||
|
|
||||||
|
page1 = conn.list_hosted_zones()
|
||||||
|
assert "Marker" not in page1
|
||||||
|
assert page1["IsTruncated"] is True
|
||||||
|
assert "NextMarker" in page1
|
||||||
|
assert "MaxItems" not in page1
|
||||||
|
assert len(page1["HostedZones"]) == 100
|
||||||
|
|
||||||
|
page2 = conn.list_hosted_zones(Marker=page1["NextMarker"])
|
||||||
|
assert page2["Marker"] == page1["NextMarker"]
|
||||||
|
assert page2["IsTruncated"] is False
|
||||||
|
assert "NextMarker" not in page2
|
||||||
|
assert "MaxItems" not in page2
|
||||||
|
assert len(page2["HostedZones"]) == 50
|
||||||
|
|
||||||
|
small_page = conn.list_hosted_zones(MaxItems="75")
|
||||||
|
assert "Marker" not in small_page
|
||||||
|
assert small_page["IsTruncated"] is True
|
||||||
|
assert "NextMarker" in small_page
|
||||||
|
assert small_page["MaxItems"] == "75"
|
||||||
|
assert len(small_page["HostedZones"]) == 75
|
||||||
|
|
||||||
|
remainer = conn.list_hosted_zones(Marker=small_page["NextMarker"])
|
||||||
|
assert remainer["Marker"] == small_page["NextMarker"]
|
||||||
|
assert remainer["IsTruncated"] is False
|
||||||
|
assert "NextMarker" not in remainer
|
||||||
|
assert "MaxItems" not in remainer
|
||||||
|
assert len(remainer["HostedZones"]) == 75
|
||||||
|
|
||||||
|
|
||||||
@mock_aws
|
@mock_aws
|
||||||
def test_change_resource_record_sets_crud_valid():
|
def test_change_resource_record_sets_crud_valid():
|
||||||
conn = boto3.client("route53", region_name="us-east-1")
|
conn = boto3.client("route53", region_name="us-east-1")
|
||||||
|
Loading…
Reference in New Issue
Block a user