DVR: handle dvr serviceable port's host change

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 d5a8074ec3 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
This commit is contained in:
Oleg Bondarev 2015-10-22 13:23:21 +03:00 committed by Armando Migliaccio
parent e5e868ca4c
commit 189a6f1bc3
2 changed files with 52 additions and 18 deletions

View 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)

View 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)