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..9582f1167 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, ) @@ -447,11 +448,22 @@ 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 ) - route = route_table.routes[route_id] + try: + route = route_table.routes[route_id] + except KeyError: + # 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 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():