]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix lack of extended port's attributes in Metaplugin
authorItsuro Oda <oda@valinux.co.jp>
Thu, 19 Dec 2013 01:51:19 +0000 (10:51 +0900)
committerItsuro Oda <oda@valinux.co.jp>
Mon, 10 Mar 2014 01:16:06 +0000 (10:16 +0900)
Previously, there are some extended port's attributes did not
appear in the result of GET port API when using Metaplugin.
This become a critial issue currently since lack of port binding
information disturbs normal port binding operation in a compute
node, for example.

Metaplugin did not delegate get_port/get_ports to target plugins.
This is cause of the problem because right plugin instance is not
passed to a hook which handles extended attributes.
Now, get_port/get_ports of target plugins are called so that
extended port's attributes are handled properly.

Change-Id: Ifed2505a97ceca56c4cedd22efa49adcdf3317b8
Closes-Bug: #1136252

neutron/plugins/metaplugin/meta_neutron_plugin.py
neutron/tests/unit/metaplugin/test_metaplugin.py

index 837ae5c800d3e2d2834f8fc18f0ffd222d56928b..8a6307dbf9e8b9abc0eca2ed98f02f79c69df862 100644 (file)
@@ -18,6 +18,7 @@
 from oslo.config import cfg
 
 from neutron.common import exceptions as exc
+from neutron import context as neutron_context
 from neutron.db import api as db
 from neutron.db import db_base_plugin_v2
 from neutron.db import external_net_db
@@ -42,6 +43,11 @@ def _meta_network_model_hook(context, original_model, query):
                            NetworkFlavor.network_id == models_v2.Network.id)
 
 
+def _meta_port_model_hook(context, original_model, query):
+    return query.join(NetworkFlavor,
+                      NetworkFlavor.network_id == models_v2.Port.network_id)
+
+
 def _meta_flavor_filter_hook(query, filters):
     if FLAVOR_NETWORK in filters:
         return query.filter(NetworkFlavor.flavor ==
@@ -126,7 +132,7 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
 
         # Register hooks.
         # The hooks are applied for each target plugin instance when
-        # calling the base class to get networks so that only records
+        # calling the base class to get networks/ports so that only records
         # which belong to the plugin are selected.
         #NOTE: Doing registration here (within __init__()) is to avoid
         # registration when merely importing this file. This is only
@@ -137,6 +143,12 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             _meta_network_model_hook,
             None,
             _meta_flavor_filter_hook)
+        db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
+            models_v2.Port,
+            'metaplugin_port',
+            _meta_port_model_hook,
+            None,
+            _meta_flavor_filter_hook)
 
     def _load_plugin(self, plugin_provider):
         LOG.debug(_("Plugin location: %s"), plugin_provider)
@@ -255,17 +267,45 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         return plugin.create_port(context, port)
 
     def update_port(self, context, id, port):
-        port_in_db = self.get_port(context, id)
+        port_in_db = self._get_port(context, id)
         plugin = self._get_plugin_by_network_id(context,
                                                 port_in_db['network_id'])
         return plugin.update_port(context, id, port)
 
     def delete_port(self, context, id, l3_port_check=True):
-        port_in_db = self.get_port(context, id)
+        port_in_db = self._get_port(context, id)
         plugin = self._get_plugin_by_network_id(context,
                                                 port_in_db['network_id'])
         return plugin.delete_port(context, id, l3_port_check)
 
+    # This is necessary since there is a case that
+    # NeutronManager.get_plugin()._make_port_dict is called.
+    def _make_port_dict(self, port):
+        context = neutron_context.get_admin_context()
+        plugin = self._get_plugin_by_network_id(context,
+                                                port['network_id'])
+        return plugin._make_port_dict(port)
+
+    def get_port(self, context, id, fields=None):
+        port_in_db = self._get_port(context, id)
+        plugin = self._get_plugin_by_network_id(context,
+                                                port_in_db['network_id'])
+        return plugin.get_port(context, id, fields)
+
+    def get_ports(self, context, filters=None, fields=None):
+        all_ports = []
+        for flavor, plugin in self.plugins.items():
+            if filters:
+                #NOTE: copy each time since a target plugin may modify
+                # plugin_filters.
+                plugin_filters = filters.copy()
+            else:
+                plugin_filters = {}
+            plugin_filters[FLAVOR_NETWORK] = [flavor]
+            ports = plugin.get_ports(context, plugin_filters, fields)
+            all_ports += ports
+        return all_ports
+
     def create_subnet(self, context, subnet):
         s = subnet['subnet']
         if 'network_id' not in s:
index d02ac13a61caf5121c28565cb474611dd2627df3..3d76656e92a6982c5fd10ca02632a9b3ef3b2957 100644 (file)
@@ -75,6 +75,8 @@ def setup_metaplugin_conf(has_l3=True):
 def unregister_meta_hooks():
     db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
         models_v2.Network, 'metaplugin_net', None, None, None)
+    db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
+        models_v2.Port, 'metaplugin_port', None, None, None)
 
 
 class MetaNeutronPluginV2Test(base.BaseTestCase):
@@ -208,10 +210,20 @@ class MetaNeutronPluginV2Test(base.BaseTestCase):
         port1_ret = self.plugin.create_port(self.context, port1)
         port2_ret = self.plugin.create_port(self.context, port2)
         port3_ret = self.plugin.create_port(self.context, port3)
+        ports_all = self.plugin.get_ports(self.context)
 
         self.assertEqual(network_ret1['id'], port1_ret['network_id'])
         self.assertEqual(network_ret2['id'], port2_ret['network_id'])
         self.assertEqual(network_ret3['id'], port3_ret['network_id'])
+        self.assertEqual(3, len(ports_all))
+
+        port1_dict = self.plugin._make_port_dict(port1_ret)
+        port2_dict = self.plugin._make_port_dict(port2_ret)
+        port3_dict = self.plugin._make_port_dict(port3_ret)
+
+        self.assertEqual(port1_dict, port1_ret)
+        self.assertEqual(port2_dict, port2_ret)
+        self.assertEqual(port3_dict, port3_ret)
 
         port1['port']['admin_state_up'] = False
         port2['port']['admin_state_up'] = False