Route53: change_resource_record_sets(): Relax DELETE validation (#7153)
This commit is contained in:
parent
9098554903
commit
dc18556449
@ -11,7 +11,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
service: ["acm"]
|
service: ["acm", "route53"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -30,4 +30,7 @@ jobs:
|
|||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
mkdir ~/.aws && touch ~/.aws/credentials && echo -e "[default]\naws_access_key_id = test\naws_secret_access_key = test" > ~/.aws/credentials
|
mkdir ~/.aws && touch ~/.aws/credentials && echo -e "[default]\naws_access_key_id = test\naws_secret_access_key = test" > ~/.aws/credentials
|
||||||
cd other_langs/terraform/${{ matrix.service }} && terraform init && terraform apply --auto-approve
|
cd other_langs/terraform/${{ matrix.service }}
|
||||||
|
terraform init
|
||||||
|
terraform apply --auto-approve
|
||||||
|
terraform apply -destroy --auto-approve
|
||||||
|
@ -314,6 +314,27 @@ class ChangeList(List[Dict[str, Any]]):
|
|||||||
item["ResourceRecordSet"]["Name"] = item["ResourceRecordSet"]["Name"].strip(".")
|
item["ResourceRecordSet"]["Name"] = item["ResourceRecordSet"]["Name"].strip(".")
|
||||||
return super().__contains__(item)
|
return super().__contains__(item)
|
||||||
|
|
||||||
|
def has_insert_or_update(self, new_rr_set: Dict[str, Any]) -> bool:
|
||||||
|
"""
|
||||||
|
Check if a CREATE or UPSERT record exists where the name and type is the same as the provided record
|
||||||
|
If the existing record has TTL/ResourceRecords, the new TTL should have the same
|
||||||
|
"""
|
||||||
|
for change in self:
|
||||||
|
if change["Action"] in ["CREATE", "UPSERT"]:
|
||||||
|
rr_set = change["ResourceRecordSet"]
|
||||||
|
if (
|
||||||
|
rr_set["Name"] == new_rr_set["Name"].strip(".")
|
||||||
|
and rr_set["Type"] == new_rr_set["Type"]
|
||||||
|
):
|
||||||
|
if "TTL" in rr_set:
|
||||||
|
if rr_set["TTL"] == new_rr_set.get("TTL") and rr_set[
|
||||||
|
"ResourceRecords"
|
||||||
|
] == new_rr_set.get("ResourceRecords"):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class FakeZone(CloudFormationModel):
|
class FakeZone(CloudFormationModel):
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -632,13 +653,8 @@ class Route53Backend(BaseBackend):
|
|||||||
for value in change_list:
|
for value in change_list:
|
||||||
if value["Action"] == "DELETE":
|
if value["Action"] == "DELETE":
|
||||||
# To delete a resource record set, you must specify all the same values that you specified when you created it.
|
# To delete a resource record set, you must specify all the same values that you specified when you created it.
|
||||||
corresponding_create = copy.deepcopy(value)
|
if not the_zone.rr_changes.has_insert_or_update(
|
||||||
corresponding_create["Action"] = "CREATE"
|
value["ResourceRecordSet"]
|
||||||
corresponding_upsert = copy.deepcopy(value)
|
|
||||||
corresponding_upsert["Action"] = "UPSERT"
|
|
||||||
if (
|
|
||||||
corresponding_create not in the_zone.rr_changes
|
|
||||||
and corresponding_upsert not in the_zone.rr_changes
|
|
||||||
):
|
):
|
||||||
msg = f"Invalid request: Expected exactly one of [AliasTarget, all of [TTL, and ResourceRecords], or TrafficPolicyInstanceId], but found none in Change with [Action=DELETE, Name={value['ResourceRecordSet']['Name']}, Type={value['ResourceRecordSet']['Type']}, SetIdentifier={value['ResourceRecordSet'].get('SetIdentifier', 'null')}]"
|
msg = f"Invalid request: Expected exactly one of [AliasTarget, all of [TTL, and ResourceRecords], or TrafficPolicyInstanceId], but found none in Change with [Action=DELETE, Name={value['ResourceRecordSet']['Name']}, Type={value['ResourceRecordSet']['Type']}, SetIdentifier={value['ResourceRecordSet'].get('SetIdentifier', 'null')}]"
|
||||||
raise InvalidInput(msg)
|
raise InvalidInput(msg)
|
||||||
|
14
other_langs/terraform/route53/providers.tf
Normal file
14
other_langs/terraform/route53/providers.tf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
provider "aws" {
|
||||||
|
region = "us-east-1"
|
||||||
|
s3_use_path_style = true
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
|
|
||||||
|
endpoints {
|
||||||
|
route53 = "http://localhost:5000"
|
||||||
|
}
|
||||||
|
|
||||||
|
access_key = "my-access-key"
|
||||||
|
secret_key = "my-secret-key"
|
||||||
|
}
|
13
other_langs/terraform/route53/route53.tf
Normal file
13
other_langs/terraform/route53/route53.tf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
resource "aws_route53_zone" "test" {
|
||||||
|
name = "test.co"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "svc_healtchecked_a_record" {
|
||||||
|
zone_id = aws_route53_zone.test.id
|
||||||
|
name = "svc-healthchecked.${aws_route53_zone.test.name}"
|
||||||
|
type = "A"
|
||||||
|
ttl = 60
|
||||||
|
set_identifier = "repl-0"
|
||||||
|
multivalue_answer_routing_policy = true
|
||||||
|
records = ["172.31.0.100", "172.31.0.101"]
|
||||||
|
}
|
@ -729,7 +729,10 @@ def test_change_resource_record_sets_crud_valid():
|
|||||||
|
|
||||||
|
|
||||||
@mock_route53
|
@mock_route53
|
||||||
def test_change_resource_record_sets_crud_valid_with_special_xml_chars():
|
@pytest.mark.parametrize("multi_value_answer", [True, False, None])
|
||||||
|
def test_change_resource_record_sets_crud_valid_with_special_xml_chars(
|
||||||
|
multi_value_answer,
|
||||||
|
):
|
||||||
conn = boto3.client("route53", region_name="us-east-1")
|
conn = boto3.client("route53", region_name="us-east-1")
|
||||||
conn.create_hosted_zone(
|
conn.create_hosted_zone(
|
||||||
Name="db.",
|
Name="db.",
|
||||||
@ -757,6 +760,10 @@ def test_change_resource_record_sets_crud_valid_with_special_xml_chars():
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
if multi_value_answer is not None:
|
||||||
|
txt_record_endpoint_payload["Changes"][0]["ResourceRecordSet"][
|
||||||
|
"MultiValueAnswer"
|
||||||
|
] = multi_value_answer
|
||||||
conn.change_resource_record_sets(
|
conn.change_resource_record_sets(
|
||||||
HostedZoneId=hosted_zone_id, ChangeBatch=txt_record_endpoint_payload
|
HostedZoneId=hosted_zone_id, ChangeBatch=txt_record_endpoint_payload
|
||||||
)
|
)
|
||||||
@ -784,6 +791,10 @@ def test_change_resource_record_sets_crud_valid_with_special_xml_chars():
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
if multi_value_answer is not None:
|
||||||
|
txt_record_with_special_char_endpoint_payload["Changes"][0][
|
||||||
|
"ResourceRecordSet"
|
||||||
|
]["MultiValueAnswer"] = multi_value_answer
|
||||||
conn.change_resource_record_sets(
|
conn.change_resource_record_sets(
|
||||||
HostedZoneId=hosted_zone_id,
|
HostedZoneId=hosted_zone_id,
|
||||||
ChangeBatch=txt_record_with_special_char_endpoint_payload,
|
ChangeBatch=txt_record_with_special_char_endpoint_payload,
|
||||||
@ -830,7 +841,7 @@ def test_change_resource_record_set__delete_should_match_create():
|
|||||||
"HostedZone"
|
"HostedZone"
|
||||||
]["Id"]
|
]["Id"]
|
||||||
|
|
||||||
create_call = client.change_resource_record_sets(
|
client.change_resource_record_sets(
|
||||||
HostedZoneId=hosted_zone_id,
|
HostedZoneId=hosted_zone_id,
|
||||||
ChangeBatch={
|
ChangeBatch={
|
||||||
"Changes": [
|
"Changes": [
|
||||||
@ -846,8 +857,6 @@ def test_change_resource_record_set__delete_should_match_create():
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
waiter = client.get_waiter("resource_record_sets_changed")
|
|
||||||
waiter.wait(Id=create_call["ChangeInfo"]["Id"])
|
|
||||||
|
|
||||||
with pytest.raises(ClientError) as exc:
|
with pytest.raises(ClientError) as exc:
|
||||||
client.change_resource_record_sets(
|
client.change_resource_record_sets(
|
||||||
|
Loading…
Reference in New Issue
Block a user