From b98704e80b030f3a7db60cf244e29521008e94f2 Mon Sep 17 00:00:00 2001 From: Itsuro Oda Date: Tue, 17 Dec 2013 10:16:51 +0900 Subject: [PATCH] Enable to select an RPC handling plugin under Metaplugin Multiple plugins under metaplugin become 'q-plugin' topic consumers and a request from an agent is handled by one of them randomly. Fortunatly most of RPC callbacks are common for plugins but a problem occurs if an RPC is not supported by the received plugin. This is one of risks when using metaplugin. Fundamental fix of this problem (such as RPC delegation handling of metaplugin) is difficult since each plugin needs to modify. But when only one plugin has plugin specific RPCs and other RPCs are independet of plugins, if the plugin can be selected for RPC handling, the problem does not happen. Typical use case of metaplugin such as combination of an agent-based plugin and a controller-based plugin often applies to this condition. This patch adds 'rpc_flavor' configuration parameter to select an RPC handling plugin. If 'rpc_flavor' is specified, only the specified plugin becomes 'q-plugin' topic consumer. If 'rpc_flavor' is not specified, the behavior is same as previous one. Change-Id: If133b054bba53829cebe63c1e0ebe6099eb1fd95 Closes-bug: #1267330 DocImpact --- etc/neutron/plugins/metaplugin/metaplugin.ini | 3 +++ neutron/plugins/metaplugin/common/config.py | 2 ++ .../plugins/metaplugin/meta_neutron_plugin.py | 16 +++++++++++ .../tests/unit/metaplugin/test_metaplugin.py | 27 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/etc/neutron/plugins/metaplugin/metaplugin.ini b/etc/neutron/plugins/metaplugin/metaplugin.ini index c5fdb9930..45da69b92 100644 --- a/etc/neutron/plugins/metaplugin/metaplugin.ini +++ b/etc/neutron/plugins/metaplugin/metaplugin.ini @@ -16,3 +16,6 @@ default_l3_flavor = 'openvswitch' supported_extension_aliases = 'providernet' # specific method map for each flavor to extensions extension_map = 'get_port_stats:nvp' + +# flavor of which plugin handles RPC +rpc_flavor = diff --git a/neutron/plugins/metaplugin/common/config.py b/neutron/plugins/metaplugin/common/config.py index 1fe8eb790..c9cecd61b 100644 --- a/neutron/plugins/metaplugin/common/config.py +++ b/neutron/plugins/metaplugin/common/config.py @@ -31,6 +31,8 @@ meta_plugin_opts = [ help=_("Supported extension aliases")), cfg.StrOpt('extension_map', default='', help=_("A list of extensions, per plugin, to load.")), + cfg.StrOpt('rpc_flavor', default='', + help=_("Flavor of which plugin handles RPC")), ] proxy_plugin_opts = [ diff --git a/neutron/plugins/metaplugin/meta_neutron_plugin.py b/neutron/plugins/metaplugin/meta_neutron_plugin.py index c1c5df6be..af50ddfe5 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.common import topics from neutron import context as neutron_context from neutron.db import api as db from neutron.db import db_base_plugin_v2 @@ -93,8 +94,19 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, plugin_list = [plugin_set.split(':') for plugin_set in cfg.CONF.META.plugin_list.split(',')] + rpc_flavor = cfg.CONF.META.rpc_flavor + topic_save = topics.PLUGIN + topic_fake = topic_save + '-metaplugin' for flavor, plugin_provider in plugin_list: + # Rename topic used by a plugin other than rpc_flavor during + # loading the plugin instance if rpc_flavor is specified. + # This enforces the plugin specified by rpc_flavor is only + # consumer of 'q-plugin'. It is a bit tricky but there is no + # bad effect. + if rpc_flavor and rpc_flavor != flavor: + topics.PLUGIN = topic_fake self.plugins[flavor] = self._load_plugin(plugin_provider) + topics.PLUGIN = topic_save self.l3_plugins = {} if cfg.CONF.META.l3_plugin_list: @@ -122,6 +134,10 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, self.supported_extension_aliases += ['router', 'ext-gw-mode', 'extraroute'] + if rpc_flavor and rpc_flavor not in self.plugins: + raise exc.Invalid(_('rpc_flavor %s is not plugin list') % + rpc_flavor) + self.extension_map = {} if not cfg.CONF.META.extension_map == '': extension_list = [method_set.split(':') diff --git a/neutron/tests/unit/metaplugin/test_metaplugin.py b/neutron/tests/unit/metaplugin/test_metaplugin.py index 7d6f88948..63ddb3fe1 100644 --- a/neutron/tests/unit/metaplugin/test_metaplugin.py +++ b/neutron/tests/unit/metaplugin/test_metaplugin.py @@ -21,6 +21,8 @@ import mock from oslo.config import cfg import testtools +from neutron.common import exceptions as exc +from neutron.common import topics from neutron import context from neutron.db import api as db from neutron.db import db_base_plugin_v2 @@ -372,3 +374,28 @@ class MetaNeutronPluginV2TestWithoutL3(MetaNeutronPluginV2Test): def test_create_router_flavor_fail(self): self.skipTest("Test case without router") + + +class MetaNeutronPluginV2TestRpcFlavor(base.BaseTestCase): + """Tests for rpc_flavor.""" + + def setUp(self): + super(MetaNeutronPluginV2TestRpcFlavor, self).setUp() + db._ENGINE = None + db._MAKER = None + db.configure_db() + self.addCleanup(db.clear_db) + self.addCleanup(unregister_meta_hooks) + + def test_rpc_flavor(self): + setup_metaplugin_conf() + cfg.CONF.set_override('rpc_flavor', 'fake1', 'META') + self.plugin = MetaPluginV2() + self.assertEqual(topics.PLUGIN, 'q-plugin') + + def test_invalid_rpc_flavor(self): + setup_metaplugin_conf() + cfg.CONF.set_override('rpc_flavor', 'fake-fake', 'META') + self.assertRaises(exc.Invalid, + MetaPluginV2) + self.assertEqual(topics.PLUGIN, 'q-plugin') -- 2.45.2