Avoid loading same service plugin more than once

In patch [1] requirement that only each service plugin
can be loaded only once was removed.
Unfortunatelly it is not possible that same service plugin
will be instantiate more than once because it may reqister some
callbacks or other things which can't be duplicated.

So this patch adds mechanism which will ensure that each service
plugin class is instantiate only once and reused if necessary.

[1] https://review.openstack.org/#/c/626561/

Closes-Bug: #1816771

Change-Id: Ie6e6cc1bbbe50ff7cfad4e8033e48711569ea020
This commit is contained in:
Slawek Kaplonski 2019-02-21 11:16:03 +01:00
parent 98fdc53c80
commit d802fad8a9
2 changed files with 49 additions and 7 deletions

View File

@ -113,6 +113,9 @@ class NeutronManager(object):
__trace_args__ = {"name": "rpc"}
def __init__(self, options=None, config_file=None):
# Store instances of already loaded plugins to avoid instantiate same
# plugin more than once
self._loaded_plugins = {}
# If no options have been provided, create an empty dict
if not options:
options = {}
@ -166,7 +169,12 @@ class NeutronManager(object):
return self.load_class_for_provider(namespace, plugin_provider)
def _get_plugin_instance(self, namespace, plugin_provider):
return self._get_plugin_class(namespace, plugin_provider)()
plugin_class = self._get_plugin_class(namespace, plugin_provider)
plugin_inst = self._loaded_plugins.get(plugin_class)
if not plugin_inst:
plugin_inst = plugin_class()
self._loaded_plugins[plugin_class] = plugin_inst
return plugin_inst
def _load_services_from_core_plugin(self, plugin):
"""Puts core plugin in service_plugins for supported services."""

View File

@ -16,6 +16,7 @@
import weakref
import fixtures
import mock
from neutron_lib.plugins import constants as lib_const
from neutron_lib.plugins import directory
from oslo_config import cfg
@ -132,11 +133,22 @@ class NeutronManagerTestCase(base.BaseTestCase):
["neutron.tests.unit.dummy_plugin."
"DummyWithRequireServicePlugin"])
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
with mock.patch(
"neutron.tests.unit.dummy_plugin.DummyServicePlugin.__init__",
return_value=None
) as dummy_init_mock, mock.patch(
"neutron.tests.unit.dummy_plugin."
"DummyWithRequireServicePlugin.__init__",
return_value=None
) as dummy_with_require_init_mock:
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
# DUMMY will also be initialized since DUMMY_REQIURE needs it.
# CORE, DUMMY, DUMMY_REQIURE
self.assertEqual(3, len(plugins))
# ensure that DUMMY and DUMMY_REQIURE was instantiate only once:
self.assertEqual(1, dummy_init_mock.call_count)
self.assertEqual(1, dummy_with_require_init_mock.call_count)
def test_load_plugins_with_requirements_with_parent(self):
cfg.CONF.set_override("service_plugins",
@ -145,10 +157,21 @@ class NeutronManagerTestCase(base.BaseTestCase):
"neutron.tests.unit.dummy_plugin."
"DummyWithRequireServicePlugin"])
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
with mock.patch(
"neutron.tests.unit.dummy_plugin.DummyServicePlugin.__init__",
return_value=None
) as dummy_init_mock, mock.patch(
"neutron.tests.unit.dummy_plugin."
"DummyWithRequireServicePlugin.__init__",
return_value=None
) as dummy_with_require_init_mock:
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
# CORE, DUMMY, DUMMY_REQIURE
self.assertEqual(3, len(plugins))
# ensure that DUMMY and DUMMY_REQIURE was instantiate only once:
self.assertEqual(1, dummy_init_mock.call_count)
self.assertEqual(1, dummy_with_require_init_mock.call_count)
def test_load_plugins_with_requirements_child_first(self):
cfg.CONF.set_override("service_plugins",
@ -157,10 +180,21 @@ class NeutronManagerTestCase(base.BaseTestCase):
"neutron.tests.unit.dummy_plugin."
"DummyServicePlugin"])
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
with mock.patch(
"neutron.tests.unit.dummy_plugin.DummyServicePlugin.__init__",
return_value=None
) as dummy_init_mock, mock.patch(
"neutron.tests.unit.dummy_plugin."
"DummyWithRequireServicePlugin.__init__",
return_value=None
) as dummy_with_require_init_mock:
manager.NeutronManager.get_instance()
plugins = directory.get_plugins()
# CORE, DUMMY, DUMMY_REQIURE
self.assertEqual(3, len(plugins))
# ensure that DUMMY and DUMMY_REQIURE was instantiate only once:
self.assertEqual(1, dummy_init_mock.call_count)
self.assertEqual(1, dummy_with_require_init_mock.call_count)
def test_core_plugin_supports_services(self):
cfg.CONF.set_override("core_plugin",