ML2: Change port status only when it's bound to the host

Currently, nothing prevents the port status to be changed to BUILD
state when get_device_details() is sent by a host that doesn't own
the port.
In some cases the port might stay in BUILD state.
This could happen during a live-migration, or for multi-hosted ports
such as HA ports.
This commit allows the port status modification only if the port
is bound to the host that is asking for it.

Closes-Bug: #1439857
Closes-Bug: #1438040
Closes-Bug: #1416933

Change-Id: I9b3673f453abbafaaa4f78542fcfebe8dc93f2bb
This commit is contained in:
mathieu-rohon 2015-03-07 13:30:49 +01:00 committed by Kyle Mestery
parent c48ba4c7b0
commit 9b53b82ce7
2 changed files with 28 additions and 9 deletions

View File

@ -96,13 +96,14 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
'vif_type': port[portbindings.VIF_TYPE]})
return {'device': device}
new_status = (q_const.PORT_STATUS_BUILD if port['admin_state_up']
else q_const.PORT_STATUS_DOWN)
if port['status'] != new_status:
plugin.update_port_status(rpc_context,
port_id,
new_status,
host)
if (not host or host == port_context.host):
new_status = (q_const.PORT_STATUS_BUILD if port['admin_state_up']
else q_const.PORT_STATUS_DOWN)
if port['status'] != new_status:
plugin.update_port_status(rpc_context,
port_id,
new_status,
host)
entry = {'device': device,
'network_id': port['network_id'],

View File

@ -88,6 +88,7 @@ class RpcCallbacksTestCase(base.BaseTestCase):
def test_get_device_details_port_status_equal_new_status(self):
port = collections.defaultdict(lambda: 'fake')
self.plugin.get_bound_port_context().current = port
self.plugin.port_bound_to_host = mock.MagicMock(return_value=True)
for admin_state_up in (True, False):
new_status = (constants.PORT_STATUS_BUILD if admin_state_up
else constants.PORT_STATUS_DOWN)
@ -98,8 +99,7 @@ class RpcCallbacksTestCase(base.BaseTestCase):
port['admin_state_up'] = admin_state_up
port['status'] = status
self.plugin.update_port_status.reset_mock()
self.callbacks.get_device_details('fake_context',
host='fake_host')
self.callbacks.get_device_details('fake_context')
self.assertEqual(status == new_status,
not self.plugin.update_port_status.called)
@ -113,6 +113,24 @@ class RpcCallbacksTestCase(base.BaseTestCase):
cached_networks=cached_networks)
self.assertTrue('fake_port' in cached_networks)
def test_get_device_details_wrong_host(self):
port = collections.defaultdict(lambda: 'fake')
port_context = self.plugin.get_bound_port_context()
port_context.current = port
port_context.host = 'fake'
self.plugin.update_port_status.reset_mock()
self.callbacks.get_device_details('fake_context',
host='fake_host')
self.assertFalse(self.plugin.update_port_status.called)
def test_get_device_details_port_no_host(self):
port = collections.defaultdict(lambda: 'fake')
port_context = self.plugin.get_bound_port_context()
port_context.current = port
self.plugin.update_port_status.reset_mock()
self.callbacks.get_device_details('fake_context')
self.assertTrue(self.plugin.update_port_status.called)
def test_get_devices_details_list(self):
devices = [1, 2, 3, 4, 5]
kwargs = {'host': 'fake_host', 'agent_id': 'fake_agent_id'}