Route53: change_resource_record_sets(): Relax DELETE validation (#7153)
This commit is contained in:
		
							parent
							
								
									9098554903
								
							
						
					
					
						commit
						dc18556449
					
				@ -11,7 +11,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        service: ["acm"]
 | 
			
		||||
        service: ["acm", "route53"]
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
@ -30,4 +30,7 @@ jobs:
 | 
			
		||||
    - name: Run tests
 | 
			
		||||
      run: |
 | 
			
		||||
        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(".")
 | 
			
		||||
        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):
 | 
			
		||||
    def __init__(
 | 
			
		||||
@ -632,13 +653,8 @@ class Route53Backend(BaseBackend):
 | 
			
		||||
        for value in change_list:
 | 
			
		||||
            if value["Action"] == "DELETE":
 | 
			
		||||
                # 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)
 | 
			
		||||
                corresponding_create["Action"] = "CREATE"
 | 
			
		||||
                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
 | 
			
		||||
                if not the_zone.rr_changes.has_insert_or_update(
 | 
			
		||||
                    value["ResourceRecordSet"]
 | 
			
		||||
                ):
 | 
			
		||||
                    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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
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.create_hosted_zone(
 | 
			
		||||
        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(
 | 
			
		||||
        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(
 | 
			
		||||
        HostedZoneId=hosted_zone_id,
 | 
			
		||||
        ChangeBatch=txt_record_with_special_char_endpoint_payload,
 | 
			
		||||
@ -830,7 +841,7 @@ def test_change_resource_record_set__delete_should_match_create():
 | 
			
		||||
        "HostedZone"
 | 
			
		||||
    ]["Id"]
 | 
			
		||||
 | 
			
		||||
    create_call = client.change_resource_record_sets(
 | 
			
		||||
    client.change_resource_record_sets(
 | 
			
		||||
        HostedZoneId=hosted_zone_id,
 | 
			
		||||
        ChangeBatch={
 | 
			
		||||
            "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:
 | 
			
		||||
        client.change_resource_record_sets(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user