diff --git a/neutron/manager.py b/neutron/manager.py index c42557ec797..e6ff94ffd22 100644 --- a/neutron/manager.py +++ b/neutron/manager.py @@ -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.""" diff --git a/neutron/tests/unit/test_manager.py b/neutron/tests/unit/test_manager.py index abb4a6b61c5..efe2f486ffb 100644 --- a/neutron/tests/unit/test_manager.py +++ b/neutron/tests/unit/test_manager.py @@ -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",