From 0074b943d6efc5526c687cc9ca3857aabc2dbc63 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Sat, 9 Apr 2016 12:15:56 -0700 Subject: [PATCH] Add RouterPort binding to ha interface creation The L3 HA interface cleanup routines during router deletion were occuring after the parent router resource was deleted. This meant that if they failed to delete, they would be orphaned since the parent router was already gone. This order of router delete and then HA delete was intentional because deleting them before calling the parent router delete function would cause them to be deleted before the checks to see if the router was in use. If the router was in use, the HA interface would be removed and would leave an HA router in an inconsitent state. (See I956d0094ae6e2412e859d79feeb4003941d2bb4b for details) This patch just has the L3 HA code add a RouterPort binding for the HA interfaces. This allows the parent router_delete call to delete the HA interfaces automatically after doing the in-use check but before deleting the actual router. In order to avoid a migration in a back-port, this is compatible with previously created routers as well by continuing to call _delete_ha_interfaces after the parent router is deleted. This means that any routers created before this patch will potentially leave orphans that will have to be manually deleted via the port API. Closes-Bug: #1540271 Change-Id: Ifd3e007aaf2a2ed8123275aa3a9f540838e3c003 --- neutron/db/l3_hamode_db.py | 11 +++++++++++ neutron/tests/unit/db/test_l3_hamode_db.py | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py index 701789669e9..478d7f3669a 100644 --- a/neutron/db/l3_hamode_db.py +++ b/neutron/db/l3_hamode_db.py @@ -36,6 +36,7 @@ from neutron.common import utils as n_utils from neutron.db import agents_db from neutron.db.availability_zone import router as router_az_db from neutron.db import common_db_mixin +from neutron.db import l3_db from neutron.db import l3_dvr_db from neutron.db.l3_dvr_db import is_distributed_router from neutron.db import model_base @@ -340,6 +341,10 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, def _create_ha_port_binding(self, context, router_id, port_id): try: with context.session.begin(): + routerportbinding = l3_db.RouterPort( + port_id=port_id, router_id=router_id, + port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF) + context.session.add(routerportbinding) portbinding = L3HARouterAgentPortBinding(port_id=port_id, router_id=router_id) context.session.add(portbinding) @@ -584,6 +589,12 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin, if ha_network: self._delete_vr_id_allocation( context, ha_network, router_db.extra_attributes.ha_vr_id) + # NOTE(kevinbenton): normally the ha interfaces should have + # been automatically removed by the super delete_router call. + # However, that only applies to interfaces created after fix + # Ifd3e007aaf2a2ed8123275aa3a9f540838e3c003 which added the + # RouterPort relationship to ha interfaces. Legacy interfaces + # will be cleaned up by this. self._delete_ha_interfaces(context, router_db.id) # always attempt to cleanup the network as the router is diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py index 60106b349c7..676d4d41080 100644 --- a/neutron/tests/unit/db/test_l3_hamode_db.py +++ b/neutron/tests/unit/db/test_l3_hamode_db.py @@ -807,6 +807,15 @@ class L3HATestCase(L3HATestFramework): self.plugin.get_number_of_agents_for_scheduling, self.admin_ctx) + def test_ha_ports_deleted_in_parent_router_removal(self): + router1 = self._create_router() + # router cleanup should no longer depend on this function for + # newly created routers. + self.plugin._delete_ha_interfaces = mock.Mock() + self.plugin.delete_router(self.admin_ctx, router1['id']) + self.assertEqual([], self.core_plugin.get_ports( + self.admin_ctx, filters={'device_id': [router1['id']]})) + def test_ha_network_deleted_if_no_ha_router_present_two_tenants(self): # Create two routers in different tenants. router1 = self._create_router()