From: Itsuro Oda Date: Thu, 19 Dec 2013 01:51:19 +0000 (+0900) Subject: Fix lack of extended port's attributes in Metaplugin X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=7a67a5676fb82ddb717e6b606cc702c31523b9fa;p=openstack-build%2Fneutron-build.git 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 --- 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