Route53 - Error on batch changes that are too large (#4674)

This commit is contained in:
Bert Blommers 2021-12-10 08:47:27 -01:00 committed by GitHub
parent 7776668a5a
commit 3d105361ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 148 additions and 1 deletions

View File

@ -72,3 +72,12 @@ class QueryLoggingConfigAlreadyExists(Route53ClientError):
def __init__(self):
message = "A query logging configuration already exists for this hosted zone"
super().__init__("QueryLoggingConfigAlreadyExists", message)
class InvalidChangeBatch(Route53ClientError):
code = 400
def __init__(self):
message = "Number of records limit of 1000 exceeded."
super().__init__("InvalidChangeBatch", message)

View File

@ -6,7 +6,7 @@ from jinja2 import Template
import xmltodict
from moto.core.responses import BaseResponse
from moto.route53.exceptions import Route53ClientError
from moto.route53.exceptions import Route53ClientError, InvalidChangeBatch
from moto.route53.models import route53_backend
XMLNS = "https://route53.amazonaws.com/doc/2013-04-01/"
@ -112,6 +112,23 @@ class Route53(BaseResponse):
]["Change"]
]
# Enforce quotas https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests-changeresourcerecordsets
# - A request cannot contain more than 1,000 ResourceRecord elements. When the value of the Action element is UPSERT, each ResourceRecord element is counted twice.
effective_rr_count = 0
for value in change_list:
record_set = value["ResourceRecordSet"]
if (
"ResourceRecords" not in record_set
or not record_set["ResourceRecords"]
):
continue
resource_records = list(record_set["ResourceRecords"].values())[0]
effective_rr_count += len(resource_records)
if value["Action"] == "UPSERT":
effective_rr_count += len(resource_records)
if effective_rr_count > 1000:
raise InvalidChangeBatch
error_msg = route53_backend.change_resource_record_sets(zoneid, change_list)
if error_msg:
return 400, headers, error_msg

View File

@ -1472,3 +1472,124 @@ def test_get_change():
response["ChangeInfo"]["Id"].should.equal(change_id)
response["ChangeInfo"]["Status"].should.equal("INSYNC")
@mock_route53
def test_change_resource_record_sets_records_limit():
conn = boto3.client("route53", region_name="us-east-1")
conn.create_hosted_zone(
Name="db.",
CallerReference=str(hash("foo")),
HostedZoneConfig=dict(PrivateZone=True, Comment="db"),
)
zones = conn.list_hosted_zones_by_name(DNSName="db.")
len(zones["HostedZones"]).should.equal(1)
zones["HostedZones"][0]["Name"].should.equal("db.")
hosted_zone_id = zones["HostedZones"][0]["Id"]
# Changes creating exactly 1,000 resource records.
changes = []
for ci in range(4):
resourcerecords = []
for rri in range(250):
resourcerecords.append({"Value": "127.0.0.%d" % (rri)})
changes.append(
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "foo%d.db." % (ci),
"Type": "A",
"TTL": 10,
"ResourceRecords": resourcerecords,
},
}
)
create_1000_resource_records_payload = {
"Comment": "Create four records with 250 resource records each",
"Changes": changes,
}
conn.change_resource_record_sets(
HostedZoneId=hosted_zone_id, ChangeBatch=create_1000_resource_records_payload
)
# Changes creating over 1,000 resource records.
too_many_changes = create_1000_resource_records_payload["Changes"].copy()
too_many_changes.append(
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "toomany.db.",
"Type": "A",
"TTL": 10,
"ResourceRecords": [{"Value": "127.0.0.1"}],
},
}
)
create_1001_resource_records_payload = {
"Comment": "Create four records with 250 resource records each, plus one more",
"Changes": too_many_changes,
}
with pytest.raises(ClientError) as exc:
conn.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch=create_1001_resource_records_payload,
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidChangeBatch")
# Changes upserting exactly 500 resource records.
changes = []
for ci in range(2):
resourcerecords = []
for rri in range(250):
resourcerecords.append({"Value": "127.0.0.%d" % (rri)})
changes.append(
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "foo%d.db." % (ci),
"Type": "A",
"TTL": 10,
"ResourceRecords": resourcerecords,
},
}
)
upsert_500_resource_records_payload = {
"Comment": "Upsert two records with 250 resource records each",
"Changes": changes,
}
conn.change_resource_record_sets(
HostedZoneId=hosted_zone_id, ChangeBatch=upsert_500_resource_records_payload
)
# Changes upserting over 1,000 resource records.
too_many_changes = upsert_500_resource_records_payload["Changes"].copy()
too_many_changes.append(
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "toomany.db.",
"Type": "A",
"TTL": 10,
"ResourceRecords": [{"Value": "127.0.0.1"}],
},
}
)
upsert_501_resource_records_payload = {
"Comment": "Upsert two records with 250 resource records each, plus one more",
"Changes": too_many_changes,
}
with pytest.raises(ClientError) as exc:
conn.change_resource_record_sets(
HostedZoneId=hosted_zone_id, ChangeBatch=upsert_501_resource_records_payload
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidChangeBatch")
err["Message"].should.equal("Number of records limit of 1000 exceeded.")