fix(route53): Allow upsert for resource records that already exist. (#5788)
This commit is contained in:
parent
3a10220404
commit
ca60f13c45
@ -174,11 +174,11 @@ class DnsNameInvalidForZone(Route53ClientError):
|
|||||||
super().__init__("InvalidChangeBatch", error_msg)
|
super().__init__("InvalidChangeBatch", error_msg)
|
||||||
|
|
||||||
|
|
||||||
class ChangeSetAlreadyExists(Route53ClientError):
|
class ResourceRecordAlreadyExists(Route53ClientError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, action: str, name: str, _type: str):
|
def __init__(self, name: str, _type: str):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
"InvalidChangeBatch",
|
"InvalidChangeBatch",
|
||||||
f"Tried to {action.lower()} resource record set [name='{name}', type='{_type}'] but it already exists",
|
f"Tried to create resource record set [name='{name}', type='{_type}'] but it already exists",
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,7 @@ from moto.route53.exceptions import (
|
|||||||
PublicZoneVPCAssociation,
|
PublicZoneVPCAssociation,
|
||||||
QueryLoggingConfigAlreadyExists,
|
QueryLoggingConfigAlreadyExists,
|
||||||
DnsNameInvalidForZone,
|
DnsNameInvalidForZone,
|
||||||
ChangeSetAlreadyExists,
|
ResourceRecordAlreadyExists,
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
)
|
)
|
||||||
from moto.core import BaseBackend, BackendDict, BaseModel, CloudFormationModel
|
from moto.core import BaseBackend, BackendDict, BaseModel, CloudFormationModel
|
||||||
@ -561,13 +561,11 @@ class Route53Backend(BaseBackend):
|
|||||||
def change_resource_record_sets(self, zoneid, change_list) -> None:
|
def change_resource_record_sets(self, zoneid, change_list) -> None:
|
||||||
the_zone = self.get_hosted_zone(zoneid)
|
the_zone = self.get_hosted_zone(zoneid)
|
||||||
|
|
||||||
for rr in change_list:
|
for value in change_list:
|
||||||
if rr in the_zone.rr_changes:
|
if value["Action"] == "CREATE" and value in the_zone.rr_changes:
|
||||||
name = rr["ResourceRecordSet"]["Name"] + "."
|
name = value["ResourceRecordSet"]["Name"] + "."
|
||||||
_type = rr["ResourceRecordSet"]["Type"]
|
_type = value["ResourceRecordSet"]["Type"]
|
||||||
raise ChangeSetAlreadyExists(
|
raise ResourceRecordAlreadyExists(name=name, _type=_type)
|
||||||
action=rr["Action"], name=name, _type=_type
|
|
||||||
)
|
|
||||||
|
|
||||||
for value in change_list:
|
for value in change_list:
|
||||||
if value["Action"] == "DELETE":
|
if value["Action"] == "DELETE":
|
||||||
|
@ -1169,7 +1169,7 @@ def test_change_resource_record_invalid_action_value():
|
|||||||
|
|
||||||
|
|
||||||
@mock_route53
|
@mock_route53
|
||||||
def test_change_resource_record_set_twice():
|
def test_change_resource_record_set_create__should_fail_when_record_already_exists():
|
||||||
ZONE = "cname.local"
|
ZONE = "cname.local"
|
||||||
FQDN = f"test.{ZONE}"
|
FQDN = f"test.{ZONE}"
|
||||||
FQDN_TARGET = "develop.domain.com"
|
FQDN_TARGET = "develop.domain.com"
|
||||||
@ -1195,8 +1195,54 @@ def test_change_resource_record_set_twice():
|
|||||||
|
|
||||||
with pytest.raises(ClientError) as exc:
|
with pytest.raises(ClientError) as exc:
|
||||||
client.change_resource_record_sets(HostedZoneId=zone_id, ChangeBatch=changes)
|
client.change_resource_record_sets(HostedZoneId=zone_id, ChangeBatch=changes)
|
||||||
|
|
||||||
err = exc.value.response["Error"]
|
err = exc.value.response["Error"]
|
||||||
err["Code"].should.equal("InvalidChangeBatch")
|
err["Code"].should.equal("InvalidChangeBatch")
|
||||||
|
err["Message"].should.equal(
|
||||||
|
"Tried to create resource record set [name='test.cname.local.', type='CNAME'] but it already exists"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_route53
|
||||||
|
def test_change_resource_record_set__should_create_record_when_using_upsert():
|
||||||
|
route53_client = boto3.client("route53", region_name="us-east-1")
|
||||||
|
|
||||||
|
hosted_zone = route53_client.create_hosted_zone(
|
||||||
|
Name="example.com", CallerReference="irrelevant"
|
||||||
|
)["HostedZone"]
|
||||||
|
|
||||||
|
resource_record = {
|
||||||
|
"Name": "test.example.com.",
|
||||||
|
"Type": "CNAME",
|
||||||
|
"TTL": 60,
|
||||||
|
"ResourceRecords": [{"Value": "www.test.example.com"}],
|
||||||
|
}
|
||||||
|
|
||||||
|
route53_client.change_resource_record_sets(
|
||||||
|
HostedZoneId=hosted_zone["Id"],
|
||||||
|
ChangeBatch={
|
||||||
|
"Changes": [{"Action": "UPSERT", "ResourceRecordSet": resource_record}],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
response = route53_client.list_resource_record_sets(HostedZoneId=hosted_zone["Id"])
|
||||||
|
|
||||||
|
# The 1st and 2nd records are NS and SOA records, respectively.
|
||||||
|
len(response["ResourceRecordSets"]).should.equal(3)
|
||||||
|
response["ResourceRecordSets"][2].should.equal(resource_record)
|
||||||
|
|
||||||
|
# a subsequest UPSERT with the same ChangeBatch should succeed as well
|
||||||
|
route53_client.change_resource_record_sets(
|
||||||
|
HostedZoneId=hosted_zone["Id"],
|
||||||
|
ChangeBatch={
|
||||||
|
"Changes": [{"Action": "UPSERT", "ResourceRecordSet": resource_record}],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response = route53_client.list_resource_record_sets(HostedZoneId=hosted_zone["Id"])
|
||||||
|
|
||||||
|
# The 1st and 2nd records are NS and SOA records, respectively.
|
||||||
|
len(response["ResourceRecordSets"]).should.equal(3)
|
||||||
|
response["ResourceRecordSets"][2].should.equal(resource_record)
|
||||||
|
|
||||||
|
|
||||||
@mock_route53
|
@mock_route53
|
||||||
|
Loading…
Reference in New Issue
Block a user