]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
DVR: handle dvr serviceable port's host change
authorOleg Bondarev <obondarev@mirantis.com>
Thu, 22 Oct 2015 10:23:21 +0000 (13:23 +0300)
committerArmando Migliaccio <armamig@gmail.com>
Mon, 14 Dec 2015 17:33:36 +0000 (17:33 +0000)
When a VM port's host is changed we need to check if a router
should be unscheduled from old host and send corresponding
notifications.
commit d5a8074ec3c67ed68e64a96827da990f1c34e10f added such
a check when port is unbound. This patch adds similar check
in case of host change (instance live migration)

Closes-Bug: #1508869

Change-Id: I57fa8253b2c88f7b7380a79b841fc424e9e52f19

neutron/db/l3_dvrscheduler_db.py
neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py

index 3d073028288b1fdf893824a6336683f45cbcca3a..c0941c78f4a3be4ff770bd005301eaa958bd36ba 100644 (file)
@@ -491,8 +491,14 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
 
     if new_port and original_port:
         original_device_owner = original_port.get('device_owner', '')
-        if (original_device_owner.startswith('compute') and
-            not new_port.get('device_owner')):
+        new_device_owner = new_port.get('device_owner', '')
+        is_port_no_longer_serviced = (
+            n_utils.is_dvr_serviced(original_device_owner) and
+            not n_utils.is_dvr_serviced(new_device_owner))
+        is_port_moved = (
+            original_port['binding:host_id'] and
+            original_port['binding:host_id'] != new_port['binding:host_id'])
+        if is_port_no_longer_serviced or is_port_moved:
             l3plugin = manager.NeutronManager.get_service_plugins().get(
                 service_constants.L3_ROUTER_NAT)
             context = kwargs['context']
@@ -508,7 +514,8 @@ def _notify_l3_agent_port_update(resource, event, trigger, **kwargs):
                 }
                 _notify_port_delete(
                     event, resource, trigger, **removed_router_args)
-            return
+            if not n_utils.is_dvr_serviced(new_device_owner):
+                return
 
     _notify_l3_agent_new_port(resource, event, trigger, **kwargs)
 
index c65b271c7ab96357ca842cc9f48d7b2ecdcc95e6..a6981f2515472b31660cf2f160e07a76aa870578 100644 (file)
@@ -456,10 +456,13 @@ class L3DvrTestCase(ml2_test_base.ML2TestFramework):
         self.assertEqual(1, len(fixed_ips))
 
     def test_update_vm_port_host_router_update(self):
-        # register l3 agent in dvr mode in addition to existing dvr_snat agent
-        HOST = 'host1'
-        dvr_agent = helpers.register_l3_agent(
-            host=HOST, agent_mode=constants.L3_AGENT_MODE_DVR)
+        # register l3 agents in dvr mode in addition to existing dvr_snat agent
+        HOST1 = 'host1'
+        dvr_agent1 = helpers.register_l3_agent(
+            host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
+        HOST2 = 'host2'
+        dvr_agent2 = helpers.register_l3_agent(
+            host=HOST2, agent_mode=constants.L3_AGENT_MODE_DVR)
         router = self._create_router()
         with self.subnet() as subnet:
             self.l3_plugin.add_router_interface(
@@ -469,24 +472,48 @@ class L3DvrTestCase(ml2_test_base.ML2TestFramework):
             # since there are no vm ports on HOST, at this point the router
             # should be scheduled to only dvr_snat agent
             agents = self.l3_plugin.list_l3_agents_hosting_router(
-                self.context, router['id'])
-            self.assertEqual(1, len(agents['agents']))
-            self.assertEqual(self.l3_agent['id'], agents['agents'][0]['id'])
+                self.context, router['id'])['agents']
+            self.assertEqual(1, len(agents))
+            self.assertEqual(self.l3_agent['id'], agents[0]['id'])
             with mock.patch.object(self.l3_plugin,
                                    '_l3_rpc_notifier') as l3_notifier,\
                     self.port(subnet=subnet,
                               device_owner=DEVICE_OWNER_COMPUTE) as port:
+                self.l3_plugin.agent_notifiers[
+                    constants.AGENT_TYPE_L3] = l3_notifier
                 self.core_plugin.update_port(
                     self.context, port['port']['id'],
-                    {'port': {'binding:host_id': HOST}})
+                    {'port': {'binding:host_id': HOST1}})
 
-                # now router should be scheduled to both agents
+                # now router should be scheduled to dvr_snat agent and
+                # dvr agent on host1
                 agents = self.l3_plugin.list_l3_agents_hosting_router(
-                    self.context, router['id'])
-                self.assertEqual(2, len(agents['agents']))
-                self.assertIn(dvr_agent['id'],
-                              [agent['id'] for agent in agents['agents']])
-                # and notification should only be sent to the agent on HOST
+                    self.context, router['id'])['agents']
+                self.assertEqual(2, len(agents))
+                self.assertIn(dvr_agent1['id'],
+                              [agent['id'] for agent in agents])
+                self.assertNotIn(dvr_agent2['id'],
+                                 [agent['id'] for agent in agents])
+                # and notification should only be sent to the agent on host1
                 l3_notifier.routers_updated_on_host.assert_called_once_with(
-                    self.context, {router['id']}, HOST)
+                    self.context, {router['id']}, HOST1)
                 self.assertFalse(l3_notifier.routers_updated.called)
+
+                # updating port's host (instance migration)
+                l3_notifier.reset_mock()
+                self.core_plugin.update_port(
+                    self.context, port['port']['id'],
+                    {'port': {'binding:host_id': HOST2}})
+                # now router should be scheduled to dvr_snat agent and
+                # dvr agent on host2
+                agents = self.l3_plugin.list_l3_agents_hosting_router(
+                    self.context, router['id'])['agents']
+                self.assertEqual(2, len(agents))
+                self.assertIn(dvr_agent2['id'],
+                              [agent['id'] for agent in agents])
+                self.assertNotIn(dvr_agent1['id'],
+                                 [agent['id'] for agent in agents])
+                l3_notifier.routers_updated_on_host.assert_called_once_with(
+                    self.context, {router['id']}, HOST2)
+                l3_notifier.router_removed_from_agent.assert_called_once_with(
+                    self.context, router['id'], HOST1)