diff --git a/neutron/neutron_plugin_base_v2.py b/neutron/neutron_plugin_base_v2.py index 046ed1ae8..c8d77b93e 100644 --- a/neutron/neutron_plugin_base_v2.py +++ b/neutron/neutron_plugin_base_v2.py @@ -336,3 +336,18 @@ class NeutronPluginBaseV2(object): defined plugin API. """ raise NotImplementedError + + def rpc_workers_supported(self): + """Return whether the plugin supports multiple RPC workers. + + A plugin that supports multiple RPC workers should override the + start_rpc_listener method to ensure that this method returns True and + that start_rpc_listener is called at the appropriate time. + Alternately, a plugin can override this method to customize detection + of support for multiple rpc workers + + .. note:: this method is optional, as it was not part of the originally + defined plugin API. + """ + return (self.__class__.start_rpc_listener != + NeutronPluginBaseV2.start_rpc_listener) diff --git a/neutron/plugins/metaplugin/meta_neutron_plugin.py b/neutron/plugins/metaplugin/meta_neutron_plugin.py index af50ddfe5..26c80f457 100644 --- a/neutron/plugins/metaplugin/meta_neutron_plugin.py +++ b/neutron/plugins/metaplugin/meta_neutron_plugin.py @@ -94,7 +94,7 @@ 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 + self.rpc_flavor = cfg.CONF.META.rpc_flavor topic_save = topics.PLUGIN topic_fake = topic_save + '-metaplugin' for flavor, plugin_provider in plugin_list: @@ -103,7 +103,7 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, # 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: + if self.rpc_flavor and self.rpc_flavor != flavor: topics.PLUGIN = topic_fake self.plugins[flavor] = self._load_plugin(plugin_provider) topics.PLUGIN = topic_save @@ -134,9 +134,9 @@ 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: + if self.rpc_flavor and self.rpc_flavor not in self.plugins: raise exc.Invalid(_('rpc_flavor %s is not plugin list') % - rpc_flavor) + self.rpc_flavor) self.extension_map = {} if not cfg.CONF.META.extension_map == '': @@ -202,6 +202,15 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, flavor = self._get_flavor_by_network_id(context, network['id']) network[FLAVOR_NETWORK] = flavor + def start_rpc_listener(self): + return self.plugins[self.rpc_flavor].start_rpc_listener() + + def rpc_workers_supported(self): + #NOTE: If a plugin which supports multiple RPC workers is desired + # to handle RPC, rpc_flavor must be specified. + return (self.rpc_flavor and + self.plugins[self.rpc_flavor].rpc_workers_supported()) + def create_network(self, context, network): n = network['network'] flavor = n.get(FLAVOR_NETWORK) diff --git a/neutron/service.py b/neutron/service.py index f03515656..9232071cb 100644 --- a/neutron/service.py +++ b/neutron/service.py @@ -25,7 +25,6 @@ from neutron.common import config from neutron.common import legacy from neutron import context from neutron import manager -from neutron import neutron_plugin_base_v2 from neutron.openstack.common.db.sqlalchemy import session from neutron.openstack.common import excutils from neutron.openstack.common import importutils @@ -144,10 +143,9 @@ def serve_rpc(): # If 0 < rpc_workers then start_rpc_listener would be called in a # subprocess and we cannot simply catch the NotImplementedError. It is - # simpler to check this up front by testing whether the plugin overrides - # start_rpc_listener. - base = neutron_plugin_base_v2.NeutronPluginBaseV2 - if plugin.__class__.start_rpc_listener == base.start_rpc_listener: + # simpler to check this up front by testing whether the plugin supports + # multiple RPC workers. + if not plugin.rpc_workers_supported(): LOG.debug(_("Active plugin doesn't implement start_rpc_listener")) if 0 < cfg.CONF.rpc_workers: msg = _("'rpc_workers = %d' ignored because start_rpc_listener " diff --git a/neutron/tests/unit/metaplugin/fake_plugin.py b/neutron/tests/unit/metaplugin/fake_plugin.py index 6653ea25b..0feaafc9a 100644 --- a/neutron/tests/unit/metaplugin/fake_plugin.py +++ b/neutron/tests/unit/metaplugin/fake_plugin.py @@ -70,3 +70,7 @@ class Fake2(Fake1): def fake_func2(self): return 'fake2' + + def start_rpc_listener(self): + # return value is only used to confirm this method was called. + return 'OK' diff --git a/neutron/tests/unit/metaplugin/test_metaplugin.py b/neutron/tests/unit/metaplugin/test_metaplugin.py index 63ddb3fe1..8410ab39c 100644 --- a/neutron/tests/unit/metaplugin/test_metaplugin.py +++ b/neutron/tests/unit/metaplugin/test_metaplugin.py @@ -392,6 +392,8 @@ class MetaNeutronPluginV2TestRpcFlavor(base.BaseTestCase): cfg.CONF.set_override('rpc_flavor', 'fake1', 'META') self.plugin = MetaPluginV2() self.assertEqual(topics.PLUGIN, 'q-plugin') + ret = self.plugin.rpc_workers_supported() + self.assertFalse(ret) def test_invalid_rpc_flavor(self): setup_metaplugin_conf() @@ -399,3 +401,13 @@ class MetaNeutronPluginV2TestRpcFlavor(base.BaseTestCase): self.assertRaises(exc.Invalid, MetaPluginV2) self.assertEqual(topics.PLUGIN, 'q-plugin') + + def test_rpc_flavor_multiple_rpc_workers(self): + setup_metaplugin_conf() + cfg.CONF.set_override('rpc_flavor', 'fake2', 'META') + self.plugin = MetaPluginV2() + self.assertEqual(topics.PLUGIN, 'q-plugin') + ret = self.plugin.rpc_workers_supported() + self.assertTrue(ret) + ret = self.plugin.start_rpc_listener() + self.assertEqual('OK', ret)