From cb43134d441daf2002f5df1a98dd0ad5f46d2019 Mon Sep 17 00:00:00 2001 From: Macwan Nevil Date: Fri, 17 Sep 2021 03:19:49 +0530 Subject: [PATCH] fixed route-table vpc-endpoint integration (#4285) --- moto/ec2/models.py | 61 ++++++++++++++++++++--------- moto/ec2/responses/route_tables.py | 33 ++++++++++------ moto/ec2/utils.py | 6 ++- tests/terraform-tests.success.txt | 2 + tests/test_ec2/test_route_tables.py | 16 +++++--- tests/test_ec2/test_vpcs.py | 4 +- 6 files changed, 85 insertions(+), 37 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 4a9ba1460..27de681d0 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -136,7 +136,6 @@ from .utils import ( random_transit_gateway_attachment_id, random_transit_gateway_route_table_id, random_vpc_ep_id, - randor_ipv4_cidr, random_launch_template_id, random_nat_gateway_id, random_transit_gateway_id, @@ -3746,8 +3745,8 @@ class VPCBackend(object): # validates if vpc is present or not. self.get_vpc(vpc_id) + destination_prefix_list_id = None - service_destination_cidr = None if type and type.lower() == "interface": network_interface_ids = [] @@ -3760,10 +3759,10 @@ class VPCBackend(object): else: # considering gateway if type is not mentioned. - service_destination_cidr = randor_ipv4_cidr() + for prefix_list in self.managed_prefix_lists.values(): + if prefix_list.prefix_list_name == service_name: + destination_prefix_list_id = prefix_list.id - for route_table_id in route_table_ids: - self.create_route(route_table_id, service_destination_cidr) if dns_entries: dns_entries = [dns_entries] @@ -3782,15 +3781,23 @@ class VPCBackend(object): security_group_ids, tags, private_dns_enabled, - service_destination_cidr, + destination_prefix_list_id, ) self.vpc_end_points[vpc_endpoint_id] = vpc_end_point + if destination_prefix_list_id: + for route_table_id in route_table_ids: + self.create_route( + route_table_id, + None, + gateway_id=vpc_endpoint_id, + destination_prefix_list_id=destination_prefix_list_id, + ) + return vpc_end_point def delete_vpc_endpoints(self, vpce_ids=[]): - vpce_ids for vpce_id in vpce_ids: vpc_endpoint = self.vpc_end_points.get(vpce_id, None) if vpc_endpoint: @@ -3800,7 +3807,7 @@ class VPCBackend(object): else: for route_table_id in vpc_endpoint.route_table_ids: self.delete_route( - route_table_id, vpc_endpoint.service_destination_cidr + route_table_id, vpc_endpoint.destination_prefix_list_id ) vpc_endpoint.state = "deleted" return True @@ -3839,6 +3846,12 @@ class VPCBackend(object): "availability_zones": availability_zones, } + def get_vpc_end_point(self, vpc_end_point_id): + vpc_end_point = self.vpc_end_points.get(vpc_end_point_id) + if not vpc_end_point: + raise InvalidVpcEndPointIdError(vpc_end_point_id) + return vpc_end_point + class PeeringConnectionStatus(object): def __init__(self, code="initiating-request", message=""): @@ -4863,7 +4876,7 @@ class Route(CloudFormationModel): route_table, destination_cidr_block, destination_ipv6_cidr_block, - prefix_list=None, + destination_prefix_list=None, local=False, gateway=None, instance=None, @@ -4875,12 +4888,15 @@ class Route(CloudFormationModel): carrier_gateway=None, ): self.id = generate_route_id( - route_table.id, destination_cidr_block, destination_ipv6_cidr_block + route_table.id, + destination_cidr_block, + destination_ipv6_cidr_block, + destination_prefix_list.id if destination_prefix_list else None, ) self.route_table = route_table self.destination_cidr_block = destination_cidr_block self.destination_ipv6_cidr_block = destination_ipv6_cidr_block - self.prefix_list = prefix_list + self.destination_prefix_list = destination_prefix_list self.local = local self.gateway = gateway self.instance = instance @@ -4951,7 +4967,7 @@ class VPCEndPoint(TaggedEC2Resource): security_group_ids=None, tags=None, private_dns_enabled=None, - service_destination_cidr=None, + destination_prefix_list_id=None, ): self.ec2_backend = ec2_backend self.id = id @@ -4966,10 +4982,9 @@ class VPCEndPoint(TaggedEC2Resource): self.client_token = client_token self.security_group_ids = security_group_ids self.private_dns_enabled = private_dns_enabled - # self.created_at = utc_date_and_time() self.dns_entries = dns_entries self.add_tags(tags or {}) - self.service_destination_cidr = service_destination_cidr + self.destination_prefix_list_id = destination_prefix_list_id @property def owner_id(self): @@ -5169,7 +5184,7 @@ class RouteBackend(object): transit_gateway = None egress_only_igw = None interface = None - prefix_list = None + destination_prefix_list = None carrier_gateway = None route_table = self.get_route_table(route_table_id) @@ -5184,6 +5199,8 @@ class RouteBackend(object): gateway = self.get_vpn_gateway(gateway_id) elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id: gateway = self.get_internet_gateway(gateway_id) + elif EC2_RESOURCE_TO_PREFIX["vpc-endpoint"] in gateway_id: + gateway = self.get_vpc_end_point(gateway_id) try: if destination_cidr_block: @@ -5198,7 +5215,9 @@ class RouteBackend(object): if transit_gateway_id is not None: transit_gateway = self.transit_gateways.get(transit_gateway_id) if destination_prefix_list_id is not None: - prefix_list = self.managed_prefix_lists.get(destination_prefix_list_id) + destination_prefix_list = self.managed_prefix_lists.get( + destination_prefix_list_id + ) if carrier_gateway_id is not None: carrier_gateway = self.carrier_gateways.get(carrier_gateway_id) @@ -5206,7 +5225,7 @@ class RouteBackend(object): route_table, destination_cidr_block, destination_ipv6_cidr_block, - prefix_list, + destination_prefix_list, local=local, gateway=gateway, instance=self.get_instance(instance_id) if instance_id else None, @@ -5283,12 +5302,18 @@ class RouteBackend(object): return route_table.get(route_id) def delete_route( - self, route_table_id, destination_cidr_block, destination_ipv6_cidr_block=None + self, + route_table_id, + destination_cidr_block, + destination_ipv6_cidr_block=None, + destination_prefix_list_id=None, ): cidr = destination_cidr_block route_table = self.get_route_table(route_table_id) if destination_ipv6_cidr_block: cidr = destination_ipv6_cidr_block + if destination_prefix_list_id: + cidr = destination_prefix_list_id route_id = generate_route_id(route_table_id, cidr) deleted = route_table.routes.pop(route_id, None) if not deleted: diff --git a/moto/ec2/responses/route_tables.py b/moto/ec2/responses/route_tables.py index 3409320b9..ce852f59c 100644 --- a/moto/ec2/responses/route_tables.py +++ b/moto/ec2/responses/route_tables.py @@ -59,8 +59,12 @@ class RouteTables(BaseResponse): route_table_id = self._get_param("RouteTableId") destination_cidr_block = self._get_param("DestinationCidrBlock") destination_ipv6_cidr_block = self._get_param("DestinationIpv6CidrBlock") + destination_prefix_list_id = self._get_param("DestinationPrefixListId") self.ec2_backend.delete_route( - route_table_id, destination_cidr_block, destination_ipv6_cidr_block + route_table_id, + destination_cidr_block, + destination_ipv6_cidr_block, + destination_prefix_list_id, ) template = self.response_template(DELETE_ROUTE_RESPONSE) return template.render() @@ -151,9 +155,13 @@ CREATE_ROUTE_TABLE_RESPONSE = """ {% if route.destination_ipv6_cidr_block %} {{ route.destination_ipv6_cidr_block }} - {% else %} + {% endif %} + {% if route.destination_cidr_block %} {{ route.destination_cidr_block }} {% endif %} + {% if route.destination_prefix_list_id %} + {{ route.destination_prefix_list_id }} + {% endif %} local active @@ -189,19 +197,18 @@ DESCRIBE_ROUTE_TABLES_RESPONSE = """ {% if route.destination_ipv6_cidr_block %} {{ route.destination_ipv6_cidr_block }} - {% else %} - {{ route.destination_cidr_block or "" }} + {% endif %} + {% if route.destination_cidr_block %} + {{ route.destination_cidr_block }} + {% endif %} + {% if route.destination_prefix_list %} + {{ route.destination_prefix_list.id }} {% endif %} {% if route.local %} local CreateRouteTable active {% endif %} - {% if route.prefix_list %} - {{ route.prefix_list.id }} - CreateRoute - active - {% endif %} {% if route.gateway %} {{ route.gateway.id }} CreateRoute @@ -215,27 +222,31 @@ DESCRIBE_ROUTE_TABLES_RESPONSE = """ {% if route.vpc_pcx %} {{ route.vpc_pcx.id }} CreateRoute - blackhole + active {% endif %} {% if route.carrier_gateway %} {{ route.carrier_gateway.id }} CreateRoute - blackhole + active {% endif %} {% if route.nat_gateway %} {{ route.nat_gateway.id }} + CreateRoute active {% endif %} {% if route.egress_only_igw %} {{ route.egress_only_igw.id }} + CreateRoute active {% endif %} {% if route.transit_gateway %} {{ route.transit_gateway.id }} + CreateRoute active {% endif %} {% if route.interface %} {{ route.interface.id }} + CreateRoute active {% endif %} diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index 8ceeb1e16..37de6073a 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -257,9 +257,13 @@ def random_ipv6_cidr(): return "2400:6500:{}:{}::/56".format(random_resource_id(4), random_resource_id(4)) -def generate_route_id(route_table_id, cidr_block, ipv6_cidr_block=None): +def generate_route_id( + route_table_id, cidr_block, ipv6_cidr_block=None, prefix_list=None +): if ipv6_cidr_block and not cidr_block: cidr_block = ipv6_cidr_block + if prefix_list and not cidr_block: + cidr_block = prefix_list return "%s~%s" % (route_table_id, cidr_block) diff --git a/tests/terraform-tests.success.txt b/tests/terraform-tests.success.txt index 83394e12e..531a23e2b 100644 --- a/tests/terraform-tests.success.txt +++ b/tests/terraform-tests.success.txt @@ -115,6 +115,8 @@ TestAccAWSRouteTable_MultipleRoutes TestAccAWSRouteTable_PrefixList_To_InternetGateway TestAccAWSRouteTable_VpcMultipleCidrs TestAccAWSRouteTable_IPv4_To_CarrierGateway +TestAccAWSRouteTable_IPv4_To_InternetGateway +TestAccAWSRouteTable_GatewayVpcEndpoint TestAccAWSSsmDocumentDataSource TestAccAwsEc2ManagedPrefixList TestAccAWSEgressOnlyInternetGateway diff --git a/tests/test_ec2/test_route_tables.py b/tests/test_ec2/test_route_tables.py index 8b92b4b4d..f7c07a5a1 100644 --- a/tests/test_ec2/test_route_tables.py +++ b/tests/test_ec2/test_route_tables.py @@ -502,7 +502,7 @@ def test_routes_vpc_peering_connection(): new_route.gateway_id.should.be.none new_route.instance_id.should.be.none new_route.vpc_peering_connection_id.should.equal(vpc_pcx.id) - new_route.state.should.equal("blackhole") + new_route.state.should.equal("active") new_route.destination_cidr_block.should.equal(ROUTE_CIDR) @@ -748,13 +748,19 @@ def test_create_route_with_egress_only_igw(): route_table = ec2.create_route_table(VpcId=vpc.id) ec2_client.create_route( - RouteTableId=route_table.id, EgressOnlyInternetGatewayId=eigw_id + RouteTableId=route_table.id, + EgressOnlyInternetGatewayId=eigw_id, + DestinationIpv6CidrBlock="::/0", ) route_table.reload() - eigw_route = [r for r in route_table.routes if r.destination_cidr_block == ""][0] - eigw_route.egress_only_internet_gateway_id.should.equal(eigw_id) - eigw_route.state.should.equal("active") + eigw_route = [ + r + for r in route_table.routes_attribute + if r.get("DestinationIpv6CidrBlock") == "::/0" + ][0] + eigw_route.get("EgressOnlyInternetGatewayId").should.equal(eigw_id) + eigw_route.get("State").should.equal("active") @mock_ec2 diff --git a/tests/test_ec2/test_vpcs.py b/tests/test_ec2/test_vpcs.py index 002e9aac6..13151f64d 100644 --- a/tests/test_ec2/test_vpcs.py +++ b/tests/test_ec2/test_vpcs.py @@ -955,13 +955,13 @@ def test_delete_vpc_end_points(): route_table = ec2.create_route_table(VpcId=vpc["Vpc"]["VpcId"]) vpc_end_point1 = ec2.create_vpc_endpoint( VpcId=vpc["Vpc"]["VpcId"], - ServiceName="com.amazonaws.us-east-1.s3", + ServiceName="com.amazonaws.us-west-1.s3", RouteTableIds=[route_table["RouteTable"]["RouteTableId"]], VpcEndpointType="gateway", )["VpcEndpoint"] vpc_end_point2 = ec2.create_vpc_endpoint( VpcId=vpc["Vpc"]["VpcId"], - ServiceName="com.amazonaws.us-east-2.s3", + ServiceName="com.amazonaws.us-west-1.s3", RouteTableIds=[route_table["RouteTable"]["RouteTableId"]], VpcEndpointType="gateway", )