]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Introduce bulk calls for get device details
authorRossella Sblendido <rsblendido@suse.com>
Wed, 15 Jan 2014 16:10:57 +0000 (17:10 +0100)
committerrossella <rsblendido@suse.com>
Wed, 25 Jun 2014 21:33:10 +0000 (21:33 +0000)
Allow to get multiple devices details instead of just one
This change introduces a new method in the rpc api.

blueprint bulk-get-device-details

Change-Id: I8497256d7f4f2fb48b5cb792e35aaedf63f129fc

21 files changed:
neutron/agent/rpc.py
neutron/plugins/brocade/NeutronPlugin.py
neutron/plugins/hyperv/agent/hyperv_neutron_agent.py
neutron/plugins/hyperv/rpc_callbacks.py
neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py
neutron/plugins/linuxbridge/lb_neutron_plugin.py
neutron/plugins/ml2/rpc.py
neutron/plugins/mlnx/agent/eswitch_neutron_agent.py
neutron/plugins/mlnx/rpc_callbacks.py
neutron/plugins/openvswitch/agent/ovs_neutron_agent.py
neutron/plugins/openvswitch/ovs_neutron_plugin.py
neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py
neutron/tests/unit/hyperv/test_hyperv_rpcapi.py
neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py
neutron/tests/unit/linuxbridge/test_rpcapi.py
neutron/tests/unit/ml2/test_rpcapi.py
neutron/tests/unit/mlnx/test_mlnx_neutron_agent.py
neutron/tests/unit/mlnx/test_rpcapi.py
neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py
neutron/tests/unit/openvswitch/test_ovs_rpcapi.py
neutron/tests/unit/test_agent_rpc.py

index 2f60f125890acc2058713f293c9f05bc35adf24f..c240dae8cf570cb641f6c6b2231a920d7fbbddaf 100644 (file)
@@ -14,6 +14,7 @@
 #    under the License.
 
 import itertools
+from oslo import messaging
 
 from neutron.common import rpc as n_rpc
 from neutron.common import topics
@@ -91,6 +92,24 @@ class PluginApi(n_rpc.RpcProxy):
                                        agent_id=agent_id),
                          topic=self.topic)
 
+    def get_devices_details_list(self, context, devices, agent_id):
+        res = []
+        try:
+            res = self.call(context,
+                            self.make_msg('get_devices_details_list',
+                                          devices=devices,
+                                          agent_id=agent_id),
+                            topic=self.topic, version='1.2')
+        except messaging.UnsupportedVersion:
+            res = [
+                self.call(context,
+                          self.make_msg('get_device_details', device=device,
+                                        agent_id=agent_id),
+                          topic=self.topic)
+                for device in devices
+            ]
+        return res
+
     def update_device_down(self, context, device, agent_id, host=None):
         return self.call(context,
                          self.make_msg('update_device_down', device=device,
index bac256a3806a7d0c91af30a89b8b05e4bb0c6240..8b4739066b6aed409b533d4f2541e439c956e064 100644 (file)
@@ -83,10 +83,11 @@ class BridgeRpcCallbacks(n_rpc.RpcCallback,
                          sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
     """Agent callback."""
 
-    RPC_API_VERSION = '1.1'
+    RPC_API_VERSION = '1.2'
     # Device names start with "tap"
     # history
     #   1.1 Support Security Group RPC
+    #   1.2 Support get_devices_details_list
     TAP_PREFIX_LEN = 3
 
     @classmethod
@@ -136,6 +137,16 @@ class BridgeRpcCallbacks(n_rpc.RpcCallback,
             LOG.debug(_("%s can not be found in database"), device)
         return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def update_device_down(self, rpc_context, **kwargs):
         """Device no longer exists on agent."""
 
index 0a06a43a67b007187946bfbd2c6995cbcfe8a451..0f45cc3f389b4df844eaef59a888c7585497f2f9 100644 (file)
@@ -357,21 +357,21 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
             LOG.debug(_("No port %s defined on agent."), port_id)
 
     def _treat_devices_added(self, devices):
-        resync = False
-        for device in devices:
+        try:
+            devices_details_list = self.plugin_rpc.get_devices_details_list(
+                self.context,
+                devices,
+                self.agent_id)
+        except Exception as e:
+            LOG.debug("Unable to get ports details for "
+                      "devices %(devices)s: %(e)s",
+                      {'devices': devices, 'e': e})
+            # resync is needed
+            return True
+
+        for device_details in devices_details_list:
+            device = device_details['device']
             LOG.info(_("Adding port %s"), device)
-            try:
-                device_details = self.plugin_rpc.get_device_details(
-                    self.context,
-                    device,
-                    self.agent_id)
-            except Exception as e:
-                LOG.debug(
-                    _("Unable to get port details for "
-                      "device %(device)s: %(e)s"),
-                    {'device': device, 'e': e})
-                resync = True
-                continue
             if 'port_id' in device_details:
                 LOG.info(
                     _("Port %(device)s updated. Details: %(device_details)s"),
@@ -395,7 +395,7 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
                                                  device,
                                                  self.agent_id,
                                                  cfg.CONF.host)
-        return resync
+        return False
 
     def _treat_devices_removed(self, devices):
         resync = False
index 8f71828e6543497b45932d2fcd255b9742dfcde9..40f018e7404b696ebb6b8c12f738be1cc1e8ebf7 100644 (file)
@@ -30,8 +30,10 @@ class HyperVRpcCallbacks(
         dhcp_rpc_base.DhcpRpcCallbackMixin,
         l3_rpc_base.L3RpcCallbackMixin):
 
-    # Set RPC API version to 1.0 by default.
-    RPC_API_VERSION = '1.1'
+    # history
+    # 1.1 Support Security Group RPC
+    # 1.2 Support get_devices_details_list
+    RPC_API_VERSION = '1.2'
 
     def __init__(self, notifier):
         super(HyperVRpcCallbacks, self).__init__()
@@ -61,6 +63,16 @@ class HyperVRpcCallbacks(
             LOG.debug(_("%s can not be found in database"), device)
         return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def update_device_down(self, rpc_context, **kwargs):
         """Device no longer exists on agent."""
         # TODO(garyk) - live migration and port status
index f6a0c5bc27b3aaf5b35202026d511fb4597ac7ae..fa60b19dd0c7907d146b7b220cf911fac29444b0 100755 (executable)
@@ -861,38 +861,39 @@ class LinuxBridgeNeutronAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin):
         return (resync_a | resync_b)
 
     def treat_devices_added_updated(self, devices):
-        resync = False
+        try:
+            devices_details_list = self.plugin_rpc.get_devices_details_list(
+                self.context, devices, self.agent_id)
+        except Exception as e:
+            LOG.debug("Unable to get port details for "
+                      "%(devices)s: %(e)s",
+                      {'devices': devices, 'e': e})
+            # resync is needed
+            return True
 
-        for device in devices:
-            LOG.debug(_("Treating added or updated device: %s"), device)
-            try:
-                details = self.plugin_rpc.get_device_details(self.context,
-                                                             device,
-                                                             self.agent_id)
-            except Exception as e:
-                LOG.debug(_("Unable to get port details for "
-                            "%(device)s: %(e)s"),
-                          {'device': device, 'e': e})
-                resync = True
-                continue
-            if 'port_id' in details:
+        for device_details in devices_details_list:
+            device = device_details['device']
+            LOG.debug("Port %s added", device)
+
+            if 'port_id' in device_details:
                 LOG.info(_("Port %(device)s updated. Details: %(details)s"),
-                         {'device': device, 'details': details})
-                if details['admin_state_up']:
+                         {'device': device, 'details': device_details})
+                if device_details['admin_state_up']:
                     # create the networking for the port
-                    network_type = details.get('network_type')
+                    network_type = device_details.get('network_type')
                     if network_type:
-                        segmentation_id = details.get('segmentation_id')
+                        segmentation_id = device_details.get('segmentation_id')
                     else:
                         # compatibility with pre-Havana RPC vlan_id encoding
-                        vlan_id = details.get('vlan_id')
+                        vlan_id = device_details.get('vlan_id')
                         (network_type,
                          segmentation_id) = lconst.interpret_vlan_id(vlan_id)
-                    if self.br_mgr.add_interface(details['network_id'],
-                                                 network_type,
-                                                 details['physical_network'],
-                                                 segmentation_id,
-                                                 details['port_id']):
+                    if self.br_mgr.add_interface(
+                        device_details['network_id'],
+                        network_type,
+                        device_details['physical_network'],
+                        segmentation_id,
+                        device_details['port_id']):
 
                         # update plugin about port status
                         self.plugin_rpc.update_device_up(self.context,
@@ -905,11 +906,11 @@ class LinuxBridgeNeutronAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin):
                                                            self.agent_id,
                                                            cfg.CONF.host)
                 else:
-                    self.remove_port_binding(details['network_id'],
-                                             details['port_id'])
+                    self.remove_port_binding(device_details['network_id'],
+                                             device_details['port_id'])
             else:
                 LOG.info(_("Device %s not defined on plugin"), device)
-        return resync
+        return False
 
     def treat_devices_removed(self, devices):
         resync = False
index b1d828dfc91ff15d799a17124a577c1373e8f6d1..89b1354a426f4e17e0aa8fc5c2a7a50c5588b1f5 100644 (file)
@@ -61,7 +61,8 @@ class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback,
 
     # history
     #   1.1 Support Security Group RPC
-    RPC_API_VERSION = '1.1'
+    #   1.2 Support get_devices_details_list
+    RPC_API_VERSION = '1.2'
     # Device names start with "tap"
     TAP_PREFIX_LEN = 3
 
@@ -102,6 +103,16 @@ class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback,
             LOG.debug(_("%s can not be found in database"), device)
         return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def update_device_down(self, rpc_context, **kwargs):
         """Device no longer exists on agent."""
         # TODO(garyk) - live migration and port status
index d58751c94d24a934bb899ee9bdb5f2d8805a511e..72a54f17f283ca97fca9a9b25d69e3f6267e43f7 100644 (file)
@@ -41,10 +41,11 @@ class RpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
                    sg_db_rpc.SecurityGroupServerRpcCallbackMixin,
                    type_tunnel.TunnelRpcCallbackMixin):
 
-    RPC_API_VERSION = '1.1'
+    RPC_API_VERSION = '1.2'
     # history
     #   1.0 Initial version (from openvswitch/linuxbridge)
     #   1.1 Support Security Group RPC
+    #   1.2 Support get_devices_details_list
 
     # FIXME(ihrachys): we can't use n_rpc.RpcCallback here due to
     # inheritance problems
@@ -149,6 +150,16 @@ class RpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
             LOG.debug(_("Returning: %s"), entry)
             return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def _find_segment(self, segments, segment_id):
         for segment in segments:
             if segment[api.ID] == segment_id:
index ecb134cf033b965380ccb0e7f156a123d8f26bc2..e3e0e4feea6c82d4a027d991e6e23c91dcb84de0 100644 (file)
@@ -312,20 +312,22 @@ class MlnxEswitchNeutronAgent(sg_rpc.SecurityGroupAgentRpcMixin):
             LOG.debug(_("No port %s defined on agent."), port_id)
 
     def treat_devices_added(self, devices):
-        resync = False
-        for device in devices:
+        try:
+            devs_details_list = self.plugin_rpc.get_devices_details_list(
+                self.context,
+                devices,
+                self.agent_id)
+        except Exception as e:
+            LOG.debug("Unable to get device details for devices "
+                      "with MAC address %(devices)s: due to %(exc)s",
+                      {'devices': devices, 'exc': e})
+            # resync is needed
+            return True
+
+        for dev_details in devs_details_list:
+            device = dev_details['device']
             LOG.info(_("Adding port with mac %s"), device)
-            try:
-                dev_details = self.plugin_rpc.get_device_details(
-                    self.context,
-                    device,
-                    self.agent_id)
-            except Exception as e:
-                LOG.debug(_("Unable to get device dev_details for device "
-                          "with mac_address %(device)s: due to %(exc)s"),
-                          {'device': device, 'exc': e})
-                resync = True
-                continue
+
             if 'port_id' in dev_details:
                 LOG.info(_("Port %s updated"), device)
                 LOG.debug(_("Device details %s"), str(dev_details))
@@ -343,7 +345,7 @@ class MlnxEswitchNeutronAgent(sg_rpc.SecurityGroupAgentRpcMixin):
             else:
                 LOG.debug(_("Device with mac_address %s not defined "
                           "on Neutron Plugin"), device)
-        return resync
+        return False
 
     def treat_devices_removed(self, devices):
         resync = False
index 279ba57a8085aaa15fe97253ba9908a13a13f277..cd61c3e3a8f73e4b5e0502c7f1b58b1ed6f89398 100644 (file)
@@ -32,7 +32,8 @@ class MlnxRpcCallbacks(n_rpc.RpcCallback,
                        sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
     # History
     #  1.1 Support Security Group RPC
-    RPC_API_VERSION = '1.1'
+    #  1.2 Support get_devices_details_list
+    RPC_API_VERSION = '1.2'
 
     #to be compatible with Linux Bridge Agent on Network Node
     TAP_PREFIX_LEN = 3
@@ -83,6 +84,16 @@ class MlnxRpcCallbacks(n_rpc.RpcCallback,
             LOG.debug(_("%s can not be found in database"), device)
         return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def update_device_down(self, rpc_context, **kwargs):
         """Device no longer exists on agent."""
         agent_id = kwargs.get('agent_id')
index ccc5ff246ac0fd3c1536a653605b7127de0ea450..15fb7ea4e48b534a0602f9d356ff1fea03f50370 100644 (file)
@@ -1078,9 +1078,19 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                     self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
 
     def treat_devices_added_or_updated(self, devices, ovs_restarted):
-        resync = False
-        for device in devices:
-            LOG.debug(_("Processing port %s"), device)
+        try:
+            devices_details_list = self.plugin_rpc.get_devices_details_list(
+                self.context,
+                devices,
+                self.agent_id)
+        except Exception as e:
+            LOG.debug("Unable to get port details for %(devices)s: %(e)s",
+                      {'devices': devices, 'e': e})
+            # resync is needed
+            return True
+        for details in devices_details_list:
+            device = details['device']
+            LOG.debug("Processing port: %s", device)
             port = self.int_br.get_vif_port_by_id(device)
             if not port:
                 # The port has disappeared and should not be processed
@@ -1089,18 +1099,7 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                 LOG.info(_("Port %s was not found on the integration bridge "
                            "and will therefore not be processed"), device)
                 continue
-            try:
-                # TODO(salv-orlando): Provide bulk API for retrieving
-                # details for all devices in one call
-                details = self.plugin_rpc.get_device_details(self.context,
-                                                             device,
-                                                             self.agent_id)
-            except Exception as e:
-                LOG.debug(_("Unable to get port details for "
-                            "%(device)s: %(e)s"),
-                          {'device': device, 'e': e})
-                resync = True
-                continue
+
             if 'port_id' in details:
                 LOG.info(_("Port %(device)s updated. Details: %(details)s"),
                          {'device': device, 'details': details})
@@ -1125,28 +1124,30 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
                 LOG.warn(_("Device %s not defined on plugin"), device)
                 if (port and port.ofport != -1):
                     self.port_dead(port)
-        return resync
+        return False
 
     def treat_ancillary_devices_added(self, devices):
-        resync = False
-        for device in devices:
+        try:
+            devices_details_list = self.plugin_rpc.get_devices_details_list(
+                self.context,
+                devices,
+                self.agent_id)
+        except Exception as e:
+            LOG.debug("Unable to get port details for "
+                      "%(devices)s: %(e)s", {'devices': devices, 'e': e})
+            # resync is needed
+            return True
+
+        for details in devices_details_list:
+            device = details['device']
             LOG.info(_("Ancillary Port %s added"), device)
-            try:
-                self.plugin_rpc.get_device_details(self.context, device,
-                                                   self.agent_id)
-            except Exception as e:
-                LOG.debug(_("Unable to get port details for "
-                            "%(device)s: %(e)s"),
-                          {'device': device, 'e': e})
-                resync = True
-                continue
 
             # update plugin about port status
             self.plugin_rpc.update_device_up(self.context,
                                              device,
                                              self.agent_id,
                                              cfg.CONF.host)
-        return resync
+        return False
 
     def treat_devices_removed(self, devices):
         resync = False
index ebfeacf10f0ad18b7ab325befa65829b7ada713a..d5f8990259232407961ce297bc5562608a9dd8c1 100644 (file)
@@ -65,8 +65,9 @@ class OVSRpcCallbacks(n_rpc.RpcCallback,
     # history
     #   1.0 Initial version
     #   1.1 Support Security Group RPC
+    #   1.2 Support get_devices_details_list
 
-    RPC_API_VERSION = '1.1'
+    RPC_API_VERSION = '1.2'
 
     def __init__(self, notifier, tunnel_type):
         super(OVSRpcCallbacks, self).__init__()
@@ -105,6 +106,16 @@ class OVSRpcCallbacks(n_rpc.RpcCallback,
             LOG.debug(_("%s can not be found in database"), device)
         return entry
 
+    def get_devices_details_list(self, rpc_context, **kwargs):
+        return [
+            self.get_device_details(
+                rpc_context,
+                device=device,
+                **kwargs
+            )
+            for device in kwargs.pop('devices', [])
+        ]
+
     def update_device_down(self, rpc_context, **kwargs):
         """Device no longer exists on agent."""
         agent_id = kwargs.get('agent_id')
index 090c99ccea02c3b57b8ab543f281e318fbb4e6e0..49fc04c0e78f71edc5900cc81ba2fef2b1feb7d6 100644 (file)
@@ -145,7 +145,7 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
         self.assertNotIn(self._FAKE_PORT_ID, self.agent._port_metric_retries)
 
     def test_treat_devices_added_returns_true_for_missing_device(self):
-        attrs = {'get_device_details.side_effect': Exception()}
+        attrs = {'get_devices_details_list.side_effect': Exception()}
         self.agent.plugin_rpc.configure_mock(**attrs)
         self.assertTrue(self.agent._treat_devices_added([{}]))
 
@@ -156,7 +156,7 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
         :param func_name: the function that should be called
         :returns: whether the named function was called
         """
-        attrs = {'get_device_details.return_value': details}
+        attrs = {'get_devices_details_list.return_value': [details]}
         self.agent.plugin_rpc.configure_mock(**attrs)
         with mock.patch.object(self.agent, func_name) as func:
             self.assertFalse(self.agent._treat_devices_added([{}]))
index e04bd0156b39b5a76cb1e3ba8db715e7e111c8a5..4fba320b5fed5cbabb64a32ab3886871893cc2b5 100644 (file)
@@ -35,6 +35,7 @@ class rpcHyperVApiTestCase(base.BaseTestCase):
             self, rpcapi, topic, method, rpc_method, **kwargs):
         ctxt = context.RequestContext('fake_user', 'fake_project')
         expected_retval = 'foo' if method == 'call' else None
+        expected_version = kwargs.pop('version', None)
         expected_msg = rpcapi.make_msg(method, **kwargs)
         if rpc_method == 'cast' and method == 'run_instance':
             kwargs['call'] = False
@@ -45,9 +46,14 @@ class rpcHyperVApiTestCase(base.BaseTestCase):
             retval = getattr(rpcapi, method)(ctxt, **kwargs)
 
         self.assertEqual(retval, expected_retval)
-        expected = [
-            mock.call(ctxt, expected_msg, topic=topic)
-        ]
+        if expected_version:
+            expected = [
+                mock.call(ctxt, expected_msg, topic=topic,
+                          version=expected_version)]
+        else:
+            expected = [
+                mock.call(ctxt, expected_msg, topic=topic)
+            ]
         rpc_method_mock.assert_has_calls(expected)
 
     def test_delete_network(self):
@@ -105,6 +111,15 @@ class rpcHyperVApiTestCase(base.BaseTestCase):
             device='fake_device',
             agent_id='fake_agent_id')
 
+    def test_devices_details_list(self):
+        rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
+        self._test_hyperv_neutron_api(
+            rpcapi, topics.PLUGIN,
+            'get_devices_details_list', rpc_method='call',
+            devices=['fake_device1', 'fake_device2'],
+            agent_id='fake_agent_id',
+            version='1.2')
+
     def test_update_device_down(self):
         rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
         self._test_hyperv_neutron_api(
index f4df6f3aad135ece328a129ae498c9c015df128a..a2a8b1785bd470adecc5bf4e431fc454f20f0051 100644 (file)
@@ -273,17 +273,17 @@ class TestLinuxBridgeAgent(base.BaseTestCase):
 
     def test_treat_devices_added_updated_admin_state_up_true(self):
         agent = self.agent
-        mock_details = {'port_id': 'port123',
+        mock_details = {'device': 'dev123',
+                        'port_id': 'port123',
                         'network_id': 'net123',
                         'admin_state_up': True,
                         'network_type': 'vlan',
                         'segmentation_id': 100,
                         'physical_network': 'physnet1'}
         agent.plugin_rpc = mock.Mock()
-        agent.plugin_rpc.get_device_details.return_value = mock_details
+        agent.plugin_rpc.get_devices_details_list.return_value = [mock_details]
         agent.br_mgr = mock.Mock()
         agent.br_mgr.add_interface.return_value = True
-
         resync_needed = agent.treat_devices_added_updated(set(['tap1']))
 
         self.assertFalse(resync_needed)
@@ -293,21 +293,22 @@ class TestLinuxBridgeAgent(base.BaseTestCase):
         self.assertTrue(agent.plugin_rpc.update_device_up.called)
 
     def test_treat_devices_added_updated_admin_state_up_false(self):
-        mock_details = {'port_id': 'port123',
+        agent = self.agent
+        mock_details = {'device': 'dev123',
+                        'port_id': 'port123',
                         'network_id': 'net123',
                         'admin_state_up': False,
                         'network_type': 'vlan',
                         'segmentation_id': 100,
                         'physical_network': 'physnet1'}
-        self.agent.plugin_rpc = mock.Mock()
-        self.agent.plugin_rpc.get_device_details.return_value = mock_details
-        self.agent.remove_port_binding = mock.Mock()
-
-        resync_needed = self.agent.treat_devices_added_updated(set(['tap1']))
+        agent.plugin_rpc = mock.Mock()
+        agent.plugin_rpc.get_devices_details_list.return_value = [mock_details]
+        agent.remove_port_binding = mock.Mock()
+        resync_needed = agent.treat_devices_added_updated(set(['tap1']))
 
         self.assertFalse(resync_needed)
-        self.agent.remove_port_binding.assert_called_with('net123', 'port123')
-        self.assertFalse(self.agent.plugin_rpc.update_device_up.called)
+        agent.remove_port_binding.assert_called_with('net123', 'port123')
+        self.assertFalse(agent.plugin_rpc.update_device_up.called)
 
 
 class TestLinuxBridgeManager(base.BaseTestCase):
index 78346c67de2d7ff3b50b418807276d49b595d0bc..4d59b1a988ae06489113aa7ed15e2c5103ef6d28 100644 (file)
@@ -31,6 +31,9 @@ class rpcApiTestCase(base.BaseTestCase):
                      expected_msg=None, **kwargs):
         ctxt = context.RequestContext('fake_user', 'fake_project')
         expected_retval = 'foo' if method == 'call' else None
+        expected_kwargs = {'topic': topic}
+        if 'version' in kwargs:
+            expected_kwargs['version'] = kwargs.pop('version')
         if not expected_msg:
             expected_msg = rpcapi.make_msg(method, **kwargs)
         if rpc_method == 'cast' and method == 'run_instance':
@@ -53,7 +56,6 @@ class rpcApiTestCase(base.BaseTestCase):
 
         self.assertEqual(expected_retval, retval)
         expected_args = [ctxt, expected_msg]
-        expected_kwargs = {'topic': topic}
 
         # skip the first argument which is 'self'
         for arg, expected_arg in zip(self.fake_args[1:], expected_args):
@@ -113,6 +115,14 @@ class rpcApiTestCase(base.BaseTestCase):
                           device='fake_device',
                           agent_id='fake_agent_id')
 
+    def test_devices_details_list(self):
+        rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
+        self._test_lb_api(rpcapi, topics.PLUGIN,
+                          'get_devices_details_list', rpc_method='call',
+                          devices=['fake_device1', 'fake_device2'],
+                          agent_id='fake_agent_id',
+                          version='1.2')
+
     def test_update_device_down(self):
         rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
         self._test_lb_api(rpcapi, topics.PLUGIN,
index c552546ac076f4d852d00cd62cc82fe7f40fa60a..763642d0fdeaf4821c506184eeb2ceacba28f46f 100644 (file)
@@ -33,6 +33,7 @@ class RpcApiTestCase(base.BaseTestCase):
     def _test_rpc_api(self, rpcapi, topic, method, rpc_method, **kwargs):
         ctxt = context.RequestContext('fake_user', 'fake_project')
         expected_retval = 'foo' if method == 'call' else None
+        expected_version = kwargs.pop('version', None)
         expected_msg = rpcapi.make_msg(method, **kwargs)
         if rpc_method == 'cast' and method == 'run_instance':
             kwargs['call'] = False
@@ -43,9 +44,14 @@ class RpcApiTestCase(base.BaseTestCase):
             retval = getattr(rpcapi, method)(ctxt, **kwargs)
 
         self.assertEqual(retval, expected_retval)
-        expected = [
-            mock.call(ctxt, expected_msg, topic=topic)
-        ]
+        if expected_version:
+            expected = [
+                mock.call(ctxt, expected_msg, topic=topic,
+                          version=expected_version)]
+        else:
+            expected = [
+                mock.call(ctxt, expected_msg, topic=topic)
+            ]
         rpc_method_mock.assert_has_calls(expected)
 
     def test_delete_network(self):
@@ -85,6 +91,14 @@ class RpcApiTestCase(base.BaseTestCase):
                            device='fake_device',
                            agent_id='fake_agent_id')
 
+    def test_devices_details_list(self):
+        rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
+        self._test_rpc_api(rpcapi, topics.PLUGIN,
+                           'get_devices_details_list', rpc_method='call',
+                           devices=['fake_device1', 'fake_device2'],
+                           agent_id='fake_agent_id',
+                           version='1.2')
+
     def test_update_device_down(self):
         rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
         self._test_rpc_api(rpcapi, topics.PLUGIN,
index 4c0eb2d2d775cce76b12fb6532007170f4b78a17..f45bece67e5a91abc1cae5c42dc0cd1090a6efd9 100644 (file)
@@ -76,7 +76,7 @@ class TestEswitchAgent(base.BaseTestCase):
         self.agent.eswitch.get_vnics_mac.return_value = []
 
     def test_treat_devices_added_returns_true_for_missing_device(self):
-        attrs = {'get_device_details.side_effect': Exception()}
+        attrs = {'get_devices_details_list.side_effect': Exception()}
         self.agent.plugin_rpc.configure_mock(**attrs)
         with contextlib.nested(
             mock.patch('neutron.plugins.mlnx.agent.eswitch_neutron_agent.'
@@ -95,8 +95,9 @@ class TestEswitchAgent(base.BaseTestCase):
             mock.patch('neutron.plugins.mlnx.agent.eswitch_neutron_agent.'
                        'EswitchManager.get_vnics_mac',
                        return_value=[]),
-            mock.patch.object(self.agent.plugin_rpc, 'get_device_details',
-                              return_value=details),
+            mock.patch.object(self.agent.plugin_rpc,
+                              'get_devices_details_list',
+                              return_value=[details]),
             mock.patch.object(self.agent.plugin_rpc, 'update_device_up'),
             mock.patch.object(self.agent, func_name)
         ) as (vnics_fn, get_dev_fn, upd_dev_up, func):
index 674ba03e9ea62a760b450b4a8f337247128051e5..3f4ef9d1dbe7a67fa6bad93323875db24d12ebbd 100644 (file)
@@ -33,6 +33,9 @@ class rpcApiTestCase(base.BaseTestCase):
                        expected_msg=None, **kwargs):
         ctxt = context.RequestContext('fake_user', 'fake_project')
         expected_retval = 'foo' if method == 'call' else None
+        expected_kwargs = {'topic': topic}
+        if 'version' in kwargs:
+            expected_kwargs['version'] = kwargs.pop('version')
         if not expected_msg:
             expected_msg = rpcapi.make_msg(method, **kwargs)
         if rpc_method == 'cast' and method == 'run_instance':
@@ -55,7 +58,6 @@ class rpcApiTestCase(base.BaseTestCase):
 
         self.assertEqual(expected_retval, retval)
         expected_args = [ctxt, expected_msg]
-        expected_kwargs = {'topic': topic}
 
         # skip the first argument which is 'self'
         for arg, expected_arg in zip(self.fake_args[1:], expected_args):
@@ -136,6 +138,14 @@ class rpcApiTestCase(base.BaseTestCase):
                             device='fake_device',
                             agent_id='fake_agent_id')
 
+    def test_devices_details_list(self):
+        rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
+        self._test_mlnx_api(rpcapi, topics.PLUGIN,
+                            'get_devices_details_list', rpc_method='call',
+                            devices=['fake_device1', 'fake_device1'],
+                            agent_id='fake_agent_id',
+                            version='1.2')
+
     def test_update_device_down(self):
         rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
         self._test_mlnx_api(rpcapi, topics.PLUGIN,
index df49b3ce712d9c5566553451eea9f762b281e1f1..ec0bb59db9ee34b8f5968a0dca6fa8539e28d441 100644 (file)
@@ -281,7 +281,8 @@ class TestOvsNeutronAgent(base.BaseTestCase):
 
     def test_treat_devices_added_returns_true_for_missing_device(self):
         with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'get_device_details',
+            mock.patch.object(self.agent.plugin_rpc,
+                              'get_devices_details_list',
                               side_effect=Exception()),
             mock.patch.object(self.agent.int_br, 'get_vif_port_by_id',
                               return_value=mock.Mock())):
@@ -297,8 +298,9 @@ class TestOvsNeutronAgent(base.BaseTestCase):
         :returns: whether the named function was called
         """
         with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'get_device_details',
-                              return_value=details),
+            mock.patch.object(self.agent.plugin_rpc,
+                              'get_devices_details_list',
+                              return_value=[details]),
             mock.patch.object(self.agent.int_br, 'get_vif_port_by_id',
                               return_value=port),
             mock.patch.object(self.agent.plugin_rpc, 'update_device_up'),
@@ -344,8 +346,9 @@ class TestOvsNeutronAgent(base.BaseTestCase):
                              'segmentation_id': 'bar',
                              'network_type': 'baz'}
         with contextlib.nested(
-            mock.patch.object(self.agent.plugin_rpc, 'get_device_details',
-                              return_value=fake_details_dict),
+            mock.patch.object(self.agent.plugin_rpc,
+                              'get_devices_details_list',
+                              return_value=[fake_details_dict]),
             mock.patch.object(self.agent.int_br, 'get_vif_port_by_id',
                               return_value=mock.MagicMock()),
             mock.patch.object(self.agent.plugin_rpc, 'update_device_up'),
index aca9d8b98cea0523118a625f70d6e777ffc0648d..7ef6202926ee4d46ddfc795ef51e72f8def8f683 100644 (file)
@@ -31,6 +31,9 @@ class rpcApiTestCase(base.BaseTestCase):
     def _test_ovs_api(self, rpcapi, topic, method, rpc_method, **kwargs):
         ctxt = context.RequestContext('fake_user', 'fake_project')
         expected_retval = 'foo' if method == 'call' else None
+        expected_kwargs = {'topic': topic}
+        if 'version' in kwargs:
+            expected_kwargs['version'] = kwargs.pop('version')
         expected_msg = rpcapi.make_msg(method, **kwargs)
         if rpc_method == 'cast' and method == 'run_instance':
             kwargs['call'] = False
@@ -52,7 +55,6 @@ class rpcApiTestCase(base.BaseTestCase):
 
         self.assertEqual(retval, expected_retval)
         expected_args = [ctxt, expected_msg]
-        expected_kwargs = {'topic': topic}
 
         # skip the first argument which is 'self'
         for arg, expected_arg in zip(self.fake_args[1:], expected_args):
@@ -97,6 +99,14 @@ class rpcApiTestCase(base.BaseTestCase):
                            device='fake_device',
                            agent_id='fake_agent_id')
 
+    def test_devices_details_list(self):
+        rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
+        self._test_ovs_api(rpcapi, topics.PLUGIN,
+                           'get_devices_details_list', rpc_method='call',
+                           devices=['fake_device1', 'fake_device2'],
+                           agent_id='fake_agent_id',
+                           version='1.2')
+
     def test_update_device_down(self):
         rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
         self._test_ovs_api(rpcapi, topics.PLUGIN,
index c2fa4121191eaf7ed1269579aadf1216613693c7..a182b49bd73191577a60367bc5329300ffa9a04c 100644 (file)
@@ -14,6 +14,7 @@
 #    under the License.
 
 import mock
+from oslo import messaging
 
 from neutron.agent import rpc
 from neutron.openstack.common import context
@@ -37,6 +38,21 @@ class AgentRPCPluginApi(base.BaseTestCase):
     def test_get_device_details(self):
         self._test_rpc_call('get_device_details')
 
+    def test_get_devices_details_list(self):
+        self._test_rpc_call('get_devices_details_list')
+
+    def test_devices_details_list_unsupported(self):
+        agent = rpc.PluginApi('fake_topic')
+        ctxt = context.RequestContext('fake_user', 'fake_project')
+        expect_val_get_device_details = 'foo'
+        expect_val = [expect_val_get_device_details]
+        with mock.patch('neutron.common.rpc.RpcProxy.call') as rpc_call:
+            rpc_call.side_effect = [messaging.UnsupportedVersion('1.2'),
+                                    expect_val_get_device_details]
+            func_obj = getattr(agent, 'get_devices_details_list')
+            actual_val = func_obj(ctxt, ['fake_device'], 'fake_agent_id')
+        self.assertEqual(actual_val, expect_val)
+
     def test_update_device_down(self):
         self._test_rpc_call('update_device_down')