diff --git a/neutron/plugins/metaplugin/meta_neutron_plugin.py b/neutron/plugins/metaplugin/meta_neutron_plugin.py index 4657d46702..837ae5c800 100644 --- a/neutron/plugins/metaplugin/meta_neutron_plugin.py +++ b/neutron/plugins/metaplugin/meta_neutron_plugin.py @@ -36,6 +36,19 @@ from neutron.plugins.metaplugin.meta_models_v2 import (NetworkFlavor, LOG = logging.getLogger(__name__) +# Hooks used to select records which belong a target plugin. +def _meta_network_model_hook(context, original_model, query): + return query.outerjoin(NetworkFlavor, + NetworkFlavor.network_id == models_v2.Network.id) + + +def _meta_flavor_filter_hook(query, filters): + if FLAVOR_NETWORK in filters: + return query.filter(NetworkFlavor.flavor == + filters[FLAVOR_NETWORK][0]) + return query + + # Metaplugin Exceptions class FlavorNotFound(exc.NotFound): message = _("Flavor %(flavor)s could not be found") @@ -111,6 +124,20 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, for method_name, flavor in extension_list: self.extension_map[method_name] = flavor + # Register hooks. + # The hooks are applied for each target plugin instance when + # calling the base class to get networks 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 + # for running whole unit tests. + db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook( + models_v2.Network, + 'metaplugin_net', + _meta_network_model_hook, + None, + _meta_flavor_filter_hook) + def _load_plugin(self, plugin_provider): LOG.debug(_("Plugin location: %s"), plugin_provider) plugin_klass = importutils.import_class(plugin_provider) @@ -190,28 +217,24 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, del net['id'] return net - def get_networks_with_flavor(self, context, filters=None, - fields=None): - collection = self._model_query(context, models_v2.Network) - model = NetworkFlavor - collection = collection.join(model, - models_v2.Network.id == model.network_id) - if filters: - for key, value in filters.iteritems(): - if key == FLAVOR_NETWORK: - column = NetworkFlavor.flavor - else: - column = getattr(models_v2.Network, key, None) - if column: - collection = collection.filter(column.in_(value)) - return [self._make_network_dict(c, fields) for c in collection] - def get_networks(self, context, filters=None, fields=None): - nets = self.get_networks_with_flavor(context, filters, None) - if filters: - nets = self._filter_nets_l3(context, nets, filters) - nets = [self.get_network(context, net['id'], fields) - for net in nets] + nets = [] + for flavor, plugin in self.plugins.items(): + if (filters and FLAVOR_NETWORK in filters and + not flavor in filters[FLAVOR_NETWORK]): + continue + 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] + plugin_nets = plugin.get_networks(context, plugin_filters, fields) + for net in plugin_nets: + if not fields or FLAVOR_NETWORK in fields: + net[FLAVOR_NETWORK] = flavor + nets.append(net) return nets def _get_flavor_by_network_id(self, context, network_id): diff --git a/neutron/tests/unit/metaplugin/test_basic.py b/neutron/tests/unit/metaplugin/test_basic.py index 876b824d00..de407fd809 100644 --- a/neutron/tests/unit/metaplugin/test_basic.py +++ b/neutron/tests/unit/metaplugin/test_basic.py @@ -14,6 +14,7 @@ # limitations under the License. from neutron.tests.unit.metaplugin.test_metaplugin import setup_metaplugin_conf +from neutron.tests.unit.metaplugin.test_metaplugin import unregister_meta_hooks from neutron.tests.unit import test_db_plugin as test_plugin from neutron.tests.unit import test_l3_plugin @@ -31,6 +32,7 @@ class MetaPluginV2DBTestCase(test_plugin.NeutronDbPluginV2TestCase): # same signature. setup_metaplugin_conf() ext_mgr = ext_mgr or test_l3_plugin.L3TestExtensionManager() + self.addCleanup(unregister_meta_hooks) super(MetaPluginV2DBTestCase, self).setUp( plugin=self._plugin_name, ext_mgr=ext_mgr, service_plugins=service_plugins) diff --git a/neutron/tests/unit/metaplugin/test_metaplugin.py b/neutron/tests/unit/metaplugin/test_metaplugin.py index 6e70703d34..d02ac13a61 100644 --- a/neutron/tests/unit/metaplugin/test_metaplugin.py +++ b/neutron/tests/unit/metaplugin/test_metaplugin.py @@ -23,6 +23,8 @@ import testtools from neutron import context from neutron.db import api as db +from neutron.db import db_base_plugin_v2 +from neutron.db import models_v2 from neutron.extensions.flavor import (FLAVOR_NETWORK, FLAVOR_ROUTER) from neutron.openstack.common import uuidutils from neutron.plugins.metaplugin.meta_neutron_plugin import FlavorNotFound @@ -68,6 +70,13 @@ def setup_metaplugin_conf(has_l3=True): 'neutron.openstack.common.rpc.impl_fake') +# Hooks registered by metaplugin must not exist for other plugins UT. +# So hooks must be unregistered (overwrite to None in fact). +def unregister_meta_hooks(): + db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook( + models_v2.Network, 'metaplugin_net', None, None, None) + + class MetaNeutronPluginV2Test(base.BaseTestCase): """Class conisting of MetaNeutronPluginV2 unit tests.""" @@ -82,6 +91,7 @@ class MetaNeutronPluginV2Test(base.BaseTestCase): db.configure_db() self.addCleanup(db.clear_db) + self.addCleanup(unregister_meta_hooks) setup_metaplugin_conf(self.has_l3)