From 7a67a5676fb82ddb717e6b606cc702c31523b9fa Mon Sep 17 00:00:00 2001 From: Itsuro Oda Date: Thu, 19 Dec 2013 10:51:19 +0900 Subject: [PATCH] Fix lack of extended port's attributes in Metaplugin 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 --- .../plugins/metaplugin/meta_neutron_plugin.py | 46 +++++++++++++++++-- .../tests/unit/metaplugin/test_metaplugin.py | 12 +++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/neutron/plugins/metaplugin/meta_neutron_plugin.py b/neutron/plugins/metaplugin/meta_neutron_plugin.py index 837ae5c80..8a6307dbf 100644 --- a/neutron/plugins/metaplugin/meta_neutron_plugin.py +++ b/neutron/plugins/metaplugin/meta_neutron_plugin.py @@ -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: diff --git a/neutron/tests/unit/metaplugin/test_metaplugin.py b/neutron/tests/unit/metaplugin/test_metaplugin.py index d02ac13a6..3d76656e9 100644 --- a/neutron/tests/unit/metaplugin/test_metaplugin.py +++ b/neutron/tests/unit/metaplugin/test_metaplugin.py @@ -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 -- 2.45.2