From 9b53b82ce7dad551ebc0f02ff667d5345fb7e139 Mon Sep 17 00:00:00 2001 From: mathieu-rohon Date: Sat, 7 Mar 2015 13:30:49 +0100 Subject: [PATCH] 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 --- neutron/plugins/ml2/rpc.py | 15 ++++++++------- neutron/tests/unit/plugins/ml2/test_rpc.py | 22 ++++++++++++++++++++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/neutron/plugins/ml2/rpc.py b/neutron/plugins/ml2/rpc.py index 010710a5b..882840664 100644 --- a/neutron/plugins/ml2/rpc.py +++ b/neutron/plugins/ml2/rpc.py @@ -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'], diff --git a/neutron/tests/unit/plugins/ml2/test_rpc.py b/neutron/tests/unit/plugins/ml2/test_rpc.py index facc9f9b5..56cbdbcb9 100644 --- a/neutron/tests/unit/plugins/ml2/test_rpc.py +++ b/neutron/tests/unit/plugins/ml2/test_rpc.py @@ -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'} -- 2.45.2