From 9cd96fe116ac1d990410cb1135473bd15c1f7dce Mon Sep 17 00:00:00 2001 From: Vivekanandan Narasimhan Date: Wed, 3 Sep 2014 01:48:39 -0700 Subject: [PATCH] DVR to delete router namespaces for service ports Earlier merge that enabled LBaaS in DVR with review #114141 had not covered the removal of DVR router namespace on VIP Port deletion in ml2 plugin. Here we fix the ml2 plugin to attempt namespace removal for all dvr serviced ports. Change-Id: Ie7930ebedb12212886d45294132fefff7296e104 Closes-Bug: #1364839 --- neutron/db/l3_dvrscheduler_db.py | 14 +++--- neutron/plugins/ml2/plugin.py | 9 ++-- neutron/tests/unit/ml2/test_ml2_plugin.py | 53 ++++++++++------------- neutron/tests/unit/test_l3_schedulers.py | 6 +-- 4 files changed, 37 insertions(+), 45 deletions(-) diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index 2797c73a8..a8c9dae94 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -110,7 +110,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): break LOG.debug('DVR: dvr_update_router_addvm %s ', router_id) - def get_dvr_routers_by_vmportid(self, context, port_id): + def get_dvr_routers_by_portid(self, context, port_id): """Gets the dvr routers on vmport subnets.""" router_ids = set() port_dict = self._core_plugin.get_port(context, port_id) @@ -153,9 +153,9 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): return True return False - def dvr_deletens_if_no_vm(self, context, port_id): - """Delete the DVR namespace if no VM exists.""" - router_ids = self.get_dvr_routers_by_vmportid(context, port_id) + def dvr_deletens_if_no_port(self, context, port_id): + """Delete the DVR namespace if no dvr serviced port exists.""" + router_ids = self.get_dvr_routers_by_portid(context, port_id) port_host = ml2_db.get_port_binding_host(port_id) if not router_ids: LOG.debug('No namespaces available for this DVR port %(port)s ' @@ -165,16 +165,16 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): removed_router_info = [] for router_id in router_ids: subnet_ids = self.get_subnet_ids_on_router(context, router_id) - vm_exists_on_subnet = False + port_exists_on_subnet = False for subnet in subnet_ids: if self.check_ports_active_on_host_and_subnet(context, port_host, port_id, subnet): - vm_exists_on_subnet = True + port_exists_on_subnet = True break - if vm_exists_on_subnet: + if port_exists_on_subnet: continue filter_rtr = {'device_id': [router_id], 'device_owner': diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index e6a8d9040..80cae035e 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -964,7 +964,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, network = self.get_network(context, port['network_id']) mech_context = None - if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE: + device_owner = port['device_owner'] + if device_owner == const.DEVICE_OWNER_DVR_INTERFACE: bindings = db.get_dvr_port_bindings(context.session, id) for bind in bindings: mech_context = driver_context.DvrPortContext( @@ -973,8 +974,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, else: mech_context = driver_context.PortContext(self, context, port, network, binding) - if "compute:" in port['device_owner'] and is_dvr_enabled: - router_info = l3plugin.dvr_deletens_if_no_vm(context, id) + if is_dvr_enabled and utils.is_dvr_serviced(device_owner): + router_info = l3plugin.dvr_deletens_if_no_port(context, id) removed_routers += router_info self.mechanism_manager.delete_port_precommit(mech_context) self._delete_port_security_group_bindings(context, id) @@ -985,7 +986,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, l3plugin.dvr_vmarp_table_update(context, id, "del") LOG.debug("Calling delete_port for %(port_id)s owned by %(owner)s" - % {"port_id": id, "owner": port['device_owner']}) + % {"port_id": id, "owner": device_owner}) super(Ml2Plugin, self).delete_port(context, id) # now that we've left db transaction, we are safe to notify diff --git a/neutron/tests/unit/ml2/test_ml2_plugin.py b/neutron/tests/unit/ml2/test_ml2_plugin.py index ca0a061f9..61c00926f 100644 --- a/neutron/tests/unit/ml2/test_ml2_plugin.py +++ b/neutron/tests/unit/ml2/test_ml2_plugin.py @@ -177,6 +177,9 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase): self.assertTrue(utils.is_dvr_serviced( constants.DEVICE_OWNER_LOADBALANCER)) + def test_check_if_dhcp_port_serviced_by_dvr(self): + self.assertTrue(utils.is_dvr_serviced(constants.DEVICE_OWNER_DHCP)) + def test_check_if_port_not_serviced_by_dvr(self): self.assertFalse(utils.is_dvr_serviced( constants.DEVICE_OWNER_ROUTER_INTF)) @@ -205,61 +208,49 @@ class TestMl2DvrPortsV2(TestMl2PortsV2): mock.PropertyMock(return_value=extensions)) self.service_plugins = {'L3_ROUTER_NAT': self.l3plugin} - def test_delete_last_vm_port(self): - fip_set = set() - ns_to_delete = {'host': 'vmhost', 'agent_id': 'vm_l3_agent', + def _test_delete_dvr_serviced_port(self, device_owner, floating_ip=False): + ns_to_delete = {'host': 'myhost', 'agent_id': 'vm_l3_agent', 'router_id': 'my_router'} + fip_set = set() + if floating_ip: + fip_set.add(ns_to_delete['router_id']) with contextlib.nested( mock.patch.object(manager.NeutronManager, 'get_service_plugins', return_value=self.service_plugins), - self.port(do_delete=False, device_owner='compute:None'), + self.port(do_delete=False, + device_owner=device_owner), mock.patch.object(self.l3plugin, 'notify_routers_updated'), mock.patch.object(self.l3plugin, 'disassociate_floatingips', return_value=fip_set), - mock.patch.object(self.l3plugin, 'dvr_deletens_if_no_vm', + mock.patch.object(self.l3plugin, 'dvr_deletens_if_no_port', return_value=[ns_to_delete]), mock.patch.object(self.l3plugin, 'remove_router_from_l3_agent') ) as (get_service_plugin, port, notify, disassociate_floatingips, - ddinv, remove_router_from_l3_agent): + dvr_delns_ifno_port, remove_router_from_l3_agent): port_id = port['port']['id'] self.plugin.delete_port(self.context, port_id) notify.assert_has_calls([mock.call(self.context, fip_set)]) + dvr_delns_ifno_port.assert_called_once_with(self.context, + port['port']['id']) remove_router_from_l3_agent.assert_has_calls([ mock.call(self.context, ns_to_delete['agent_id'], ns_to_delete['router_id']) ]) + def test_delete_last_vm_port(self): + self._test_delete_dvr_serviced_port(device_owner='compute:None') + def test_delete_last_vm_port_with_floatingip(self): - ns_to_delete = {'host': 'vmhost', 'agent_id': 'vm_l3_agent', - 'router_id': 'my_router'} - fip_set = set([ns_to_delete['router_id']]) + self._test_delete_dvr_serviced_port(device_owner='compute:None', + floating_ip=True) - with contextlib.nested( - mock.patch.object(manager.NeutronManager, - 'get_service_plugins', - return_value=self.service_plugins), - self.port(do_delete=False, device_owner='compute:None'), - mock.patch.object(self.l3plugin, 'notify_routers_updated'), - mock.patch.object(self.l3plugin, 'disassociate_floatingips', - return_value=fip_set), - mock.patch.object(self.l3plugin, 'dvr_deletens_if_no_vm', - return_value=[ns_to_delete]), - mock.patch.object(self.l3plugin, 'remove_router_from_l3_agent') - ) as (get_service_plugins, port, notify, disassociate_floatingips, - ddinv, remove_router_from_l3_agent): - - port_id = port['port']['id'] - self.plugin.delete_port(self.context, port_id) - - notify.assert_has_calls([mock.call(self.context, fip_set)]) - remove_router_from_l3_agent.assert_has_calls([ - mock.call(self.context, ns_to_delete['agent_id'], - ns_to_delete['router_id']) - ]) + def test_delete_lbaas_vip_port(self): + self._test_delete_dvr_serviced_port( + device_owner=constants.DEVICE_OWNER_LOADBALANCER) class TestMl2PortBinding(Ml2PluginV2TestCase, diff --git a/neutron/tests/unit/test_l3_schedulers.py b/neutron/tests/unit/test_l3_schedulers.py index fdf823213..b3eb44859 100644 --- a/neutron/tests/unit/test_l3_schedulers.py +++ b/neutron/tests/unit/test_l3_schedulers.py @@ -822,7 +822,7 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase, '.L3AgentNotifyAPI')): self.dut.dvr_update_router_addvm(self.adminContext, port) - def test_get_dvr_routers_by_vmportid(self): + def test_get_dvr_routers_by_portid(self): dvr_port = { 'id': 'dvr_port1', 'device_id': 'r1', @@ -844,8 +844,8 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase, '.get_port', return_value=dvr_port), mock.patch('neutron.db.db_base_plugin_v2.NeutronDbPluginV2' '.get_ports', return_value=[dvr_port])): - router_id = self.dut.get_dvr_routers_by_vmportid(self.adminContext, - dvr_port['id']) + router_id = self.dut.get_dvr_routers_by_portid(self.adminContext, + dvr_port['id']) self.assertEqual(router_id.pop(), r1['id']) def test_get_subnet_ids_on_router(self):