From 0fb3e59e0db4b1f44bf444179ed732e9d1a4167e Mon Sep 17 00:00:00 2001 From: Lewis Gaul Date: Fri, 16 Jun 2023 09:33:54 -0700 Subject: [PATCH 1/3] If route specified in replace_route() doesn't exist then return suitable error response --- moto/ec2/exceptions.py | 8 ++++++++ moto/ec2/models/route_tables.py | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index 6eb8d515e..780ed933c 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -444,6 +444,14 @@ class InvalidParameterValueErrorTagSpotFleetRequest(EC2ClientError): ) +class InvalidParameterValueErrorReplaceRoute(EC2ClientError): + def __init__(self, cidr: str): + super().__init__( + "InvalidParameterValue", + f"There is no route defined for '{cidr}' in the route table. Use CreateRoute instead.", + ) + + class EmptyTagSpecError(EC2ClientError): def __init__(self) -> None: super().__init__( diff --git a/moto/ec2/models/route_tables.py b/moto/ec2/models/route_tables.py index de6217d09..51c8e2e76 100644 --- a/moto/ec2/models/route_tables.py +++ b/moto/ec2/models/route_tables.py @@ -18,6 +18,7 @@ from ..exceptions import ( InvalidRouteTableIdError, InvalidAssociationIdError, InvalidDestinationCIDRBlockParameterError, + InvalidParameterValueErrorReplaceRoute, RouteAlreadyExistsError, RouteNotSupportedError, ) @@ -451,7 +452,18 @@ class RouteBackend: route_id = generate_route_id( route_table.id, destination_cidr_block, destination_ipv6_cidr_block ) - route = route_table.routes[route_id] + try: + route = route_table.routes[route_id] + except KeyError: + cidr = ( + destination_cidr_block + if destination_cidr_block + else destination_ipv6_cidr_block + ) + # This should be 'raise InvalidRouteError(route_table_id, cidr)' in + # line with the delete_route() equivalent, but for some reason AWS + # returns InvalidParameterValue instead in this case. + raise InvalidParameterValueErrorReplaceRoute(cidr) from None route.gateway = None route.nat_gateway = None From b21131c4f6ae04b5cf65a319e45775e0bb2dd11c Mon Sep 17 00:00:00 2001 From: Lewis Gaul Date: Mon, 19 Jun 2023 07:29:49 -0700 Subject: [PATCH 2/3] Add testcase for replace_route() returning InvalidParameterValue error code --- tests/test_ec2/test_route_tables.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_ec2/test_route_tables.py b/tests/test_ec2/test_route_tables.py index 70b70bd67..a20e5b68c 100644 --- a/tests/test_ec2/test_route_tables.py +++ b/tests/test_ec2/test_route_tables.py @@ -643,6 +643,18 @@ def test_routes_replace(): ex.value.response["ResponseMetadata"].should.have.key("RequestId") ex.value.response["Error"]["Code"].should.equal("InvalidRouteTableID.NotFound") + with pytest.raises(ClientError) as ex: + client.replace_route( + RouteTableId=main_route_table.id, + DestinationCidrBlock="1.1.1.1/32", + NetworkInterfaceId=eni.id, + ) + ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + ex.value.response["ResponseMetadata"].should.have.key("RequestId") + # This should be 'InvalidRoute.NotFound' in line with the delete_route() + # equivalent, but for some reason AWS returns InvalidParameterValue instead. + ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue") + @mock_ec2 def test_routes_already_exist(): From 1d8ca4a8520bebc572a43430ed4feeeec0cefff6 Mon Sep 17 00:00:00 2001 From: Lewis Gaul Date: Thu, 22 Jun 2023 04:29:05 -0700 Subject: [PATCH 3/3] Use same structure as delete_route() for determining cidr string --- moto/ec2/models/route_tables.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/moto/ec2/models/route_tables.py b/moto/ec2/models/route_tables.py index 51c8e2e76..9582f1167 100644 --- a/moto/ec2/models/route_tables.py +++ b/moto/ec2/models/route_tables.py @@ -448,6 +448,11 @@ class RouteBackend: interface_id: Optional[str] = None, vpc_peering_connection_id: Optional[str] = None, ) -> Route: + cidr = destination_cidr_block + if destination_ipv6_cidr_block: + cidr = destination_ipv6_cidr_block + if destination_prefix_list_id: + cidr = destination_prefix_list_id route_table = self.get_route_table(route_table_id) route_id = generate_route_id( route_table.id, destination_cidr_block, destination_ipv6_cidr_block @@ -455,11 +460,6 @@ class RouteBackend: try: route = route_table.routes[route_id] except KeyError: - cidr = ( - destination_cidr_block - if destination_cidr_block - else destination_ipv6_cidr_block - ) # This should be 'raise InvalidRouteError(route_table_id, cidr)' in # line with the delete_route() equivalent, but for some reason AWS # returns InvalidParameterValue instead in this case.