]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
ML2: Change port status only when it's bound to the host
authormathieu-rohon <mathieu.rohon@gmail.com>
Sat, 7 Mar 2015 12:30:49 +0000 (13:30 +0100)
committerKyle Mestery <mestery@mestery.com>
Fri, 17 Apr 2015 13:13:38 +0000 (13:13 +0000)
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
neutron/tests/unit/plugins/ml2/test_rpc.py

index 010710a5b9832dce55f71406f5d9d0000432d6d9..882840664ef9653ede48ccb113b761400898f737 100644 (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'],
index facc9f9b56a5aa1e0cb8a0d81ac5bebaea016c9c..56cbdbcb97947cd7baa3f439af7f48a177fb451b 100644 (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'}