From a039966ba2d81367fbc620ed075a45c78e7584ba Mon Sep 17 00:00:00 2001 From: Boden R Date: Mon, 19 Dec 2016 09:20:27 -0700 Subject: [PATCH] Rehome ServicePluginBase A number of subprojects inherit neutron's ServicePluginBase class [1]. This patch rehomes ServicePluginBase into neutron-lib along with 2 other classes required for the implementation of ServicePluginBase. UTs and a release note are also included. [1] http://codesearch.openstack.org/?q=ServicePluginBase Change-Id: I2b1131ac53e9bfeb42a92f9ef134be6ff4cfe5a3 --- neutron_lib/services/__init__.py | 0 neutron_lib/services/base.py | 92 +++++++++++++++++++ neutron_lib/tests/unit/services/__init__.py | 0 neutron_lib/tests/unit/services/test_base.py | 85 +++++++++++++++++ .../service-plugin-base-a42c2241a2fe0d26.yaml | 4 + 5 files changed, 181 insertions(+) create mode 100644 neutron_lib/services/__init__.py create mode 100644 neutron_lib/services/base.py create mode 100644 neutron_lib/tests/unit/services/__init__.py create mode 100644 neutron_lib/tests/unit/services/test_base.py create mode 100644 releasenotes/notes/service-plugin-base-a42c2241a2fe0d26.yaml diff --git a/neutron_lib/services/__init__.py b/neutron_lib/services/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_lib/services/base.py b/neutron_lib/services/base.py new file mode 100644 index 000000000..e6bd2fe0b --- /dev/null +++ b/neutron_lib/services/base.py @@ -0,0 +1,92 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class _PluginInterface(object): + + @classmethod + def __subclasshook__(cls, klass): + """Checking plugin class. + + The __subclasshook__ method is a class method + that will be called every time a class is tested + using issubclass(klass, _PluginInterface). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + + if not cls.__abstractmethods__: + return NotImplemented + + for method in cls.__abstractmethods__: + if any(method in base.__dict__ for base in klass.__mro__): + continue + return NotImplemented + return True + + +class _WorkerSupportServiceMixin(object): + + @property + def _workers(self): + try: + return self.__workers + except AttributeError: + self.__workers = [] + return self.__workers + + def get_workers(self): + """Returns a collection NeutronWorker instances needed by this service. + + """ + return list(self._workers) + + def add_worker(self, worker): + """Adds NeutronWorker needed for this service + + If a object needs to define workers thread/processes outside of API/RPC + workers then it will call this method to register worker. Should be + called on initialization stage before running services + """ + self._workers.append(worker) + + def add_workers(self, workers): + """Adds NeutronWorker list needed for this service + + The same as add_worker but adds a list of workers + """ + self._workers.extend(workers) + + +@six.add_metaclass(abc.ABCMeta) +class ServicePluginBase(_PluginInterface, + _WorkerSupportServiceMixin): + """Define base interface for any Advanced Service plugin.""" + supported_extension_aliases = [] + + @abc.abstractmethod + def get_plugin_type(self): + """Return one of predefined service types. + + """ + pass + + @abc.abstractmethod + def get_plugin_description(self): + """Return string description of the plugin.""" + pass diff --git a/neutron_lib/tests/unit/services/__init__.py b/neutron_lib/tests/unit/services/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron_lib/tests/unit/services/test_base.py b/neutron_lib/tests/unit/services/test_base.py new file mode 100644 index 000000000..d73c67efe --- /dev/null +++ b/neutron_lib/tests/unit/services/test_base.py @@ -0,0 +1,85 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +from neutron_lib.services import base +from neutron_lib.tests import _base as test_base + + +class _Worker(base._WorkerSupportServiceMixin): + pass + + +class Test_WorkerSupportServiceMixin(test_base.BaseTestCase): + + def setUp(self): + super(Test_WorkerSupportServiceMixin, self).setUp() + self.worker = _Worker() + + def test_allocate_workers(self): + self.assertEqual([], self.worker.get_workers()) + + def test_add_worker(self): + workers = [object(), object()] + for w in workers: + self.worker.add_worker(w) + + self.assertSequenceEqual(workers, self.worker.get_workers()) + + def test_add_workers(self): + workers = [object(), object(), object()] + self.worker.add_workers(workers) + + self.assertSequenceEqual(workers, self.worker.get_workers()) + + +class Test_PluginInterface(test_base.BaseTestCase): + + def test_issubclass_hook(self): + class A(object): + def f(self): + pass + + class B(base._PluginInterface): + @abc.abstractmethod + def f(self): + pass + + self.assertTrue(issubclass(A, B)) + + def test_issubclass_hook_class_without_abstract_methods(self): + class A(object): + def f(self): + pass + + class B(base._PluginInterface): + def f(self): + pass + + self.assertFalse(issubclass(A, B)) + + def test_issubclass_hook_not_all_methods_implemented(self): + class A(object): + def f(self): + pass + + class B(base._PluginInterface): + @abc.abstractmethod + def f(self): + pass + + @abc.abstractmethod + def g(self): + pass + + self.assertFalse(issubclass(A, B)) diff --git a/releasenotes/notes/service-plugin-base-a42c2241a2fe0d26.yaml b/releasenotes/notes/service-plugin-base-a42c2241a2fe0d26.yaml new file mode 100644 index 000000000..cb303d917 --- /dev/null +++ b/releasenotes/notes/service-plugin-base-a42c2241a2fe0d26.yaml @@ -0,0 +1,4 @@ +--- +features: + - The class ``neutron.services.service_base.ServicePluginBase`` is + now available as ``neutron_lib.services.base.ServicePluginBase``.