From 8fb023ed53aff31f37ebebb94aca4f8e2a188342 Mon Sep 17 00:00:00 2001 From: Itsuro Oda Date: Wed, 2 Apr 2014 13:24:42 +0900 Subject: [PATCH] Add support for multiple RPC workers under Metaplugin Metaplugin needs a fix to support multiple RPC workers properly because a plugin which supports multiple RPC workers cannot initialize RPC connections at plugin initialization. Closes-Bug: #1300570 Change-Id: I584f70abb8969054cd4edc8f914d00f6be930bab --- neutron/neutron_plugin_base_v2.py | 15 +++++++++++++++ .../plugins/metaplugin/meta_neutron_plugin.py | 17 +++++++++++++---- neutron/service.py | 8 +++----- neutron/tests/unit/metaplugin/fake_plugin.py | 4 ++++ .../tests/unit/metaplugin/test_metaplugin.py | 12 ++++++++++++ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/neutron/neutron_plugin_base_v2.py b/neutron/neutron_plugin_base_v2.py index 4f2ec3c69e6..67bd581c82f 100644 --- a/neutron/neutron_plugin_base_v2.py +++ b/neutron/neutron_plugin_base_v2.py @@ -335,3 +335,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 04905132da2..1a2686f3719 100644 --- a/neutron/plugins/metaplugin/meta_neutron_plugin.py +++ b/neutron/plugins/metaplugin/meta_neutron_plugin.py @@ -95,7 +95,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: @@ -104,7 +104,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 @@ -135,9 +135,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 == '': @@ -203,6 +203,15 @@ class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, flavor = self._get_flavor_by_network_id(context, network['id']) network[ext_flavor.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(ext_flavor.FLAVOR_NETWORK) diff --git a/neutron/service.py b/neutron/service.py index 754a68f9058..3258245d10f 100644 --- a/neutron/service.py +++ b/neutron/service.py @@ -24,7 +24,6 @@ from oslo.config import cfg from neutron.common import config 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 @@ -137,10 +136,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 6653ea25b5f..0feaafc9ae6 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 c413c65bc09..43fb761fc8d 100644 --- a/neutron/tests/unit/metaplugin/test_metaplugin.py +++ b/neutron/tests/unit/metaplugin/test_metaplugin.py @@ -393,6 +393,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() @@ -400,3 +402,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)