Formalize base service classes

The PluginInterface and WorkerSupportServiceMixin classes
were rehomed to neutron-lib recently [1] and included a private
version of the respective classes. Based on the existing usages
of such [2][3], this patch:
- Renames WorkerSupportServiceMixin as WorkerBase making it
public for consumption [2].
- Collapses _PluginInterface into ServicePluginBase making the
definition more compact and understandable.
- Formalizes the use of ServicePluginBase by updating the
docstring in ExtensionDescriptor to indicate an instance of
ServicePluginBase is used for plugin interfaces. This is kosher
as existing uses today all return extension plugin interfaces that
are subclasses of ServicePluginBase and not PluginInterface.

Also see related neutron consumption patch [4].

[1] https://review.openstack.org/412519/
[2] http://codesearch.openstack.org/?q=WorkerSupportServiceMixin
[3] http://codesearch.openstack.org/?q=PluginInterface
[4] https://review.openstack.org/#/c/441129

Change-Id: I722252b845a4396f1b193459b22e4352c93241e6
This commit is contained in:
Boden R 2017-01-23 07:32:28 -07:00
parent 65fc1a49af
commit c2756c3d98
4 changed files with 49 additions and 36 deletions

View File

@ -106,7 +106,8 @@ class ExtensionDescriptor(object):
def get_plugin_interface(self):
"""Returns an abstract class which defines contract for the plugin.
The abstract class should inherit from extensions.PluginInterface,
The abstract class should inherit from
neutron_lib.services.base.ServicePluginBase.
Methods in this abstract class should be decorated as abstractmethod
"""

View File

@ -15,32 +15,7 @@ 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):
class WorkerBase(object):
@property
def _workers(self):
@ -74,11 +49,31 @@ class _WorkerSupportServiceMixin(object):
@six.add_metaclass(abc.ABCMeta)
class ServicePluginBase(_PluginInterface,
_WorkerSupportServiceMixin):
class ServicePluginBase(WorkerBase):
"""Define base interface for any Advanced Service plugin."""
supported_extension_aliases = []
@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, ServicePluginBase).
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
@abc.abstractmethod
def get_plugin_type(self):
"""Return one of predefined service types.

View File

@ -16,7 +16,7 @@ from neutron_lib.services import base
from neutron_lib.tests import _base as test_base
class _Worker(base._WorkerSupportServiceMixin):
class _Worker(base.WorkerBase):
pass
@ -43,14 +43,21 @@ class Test_WorkerSupportServiceMixin(test_base.BaseTestCase):
self.assertSequenceEqual(workers, self.worker.get_workers())
class Test_PluginInterface(test_base.BaseTestCase):
class TestPluginInterface(test_base.BaseTestCase):
class ServicePluginStub(base.ServicePluginBase):
def get_plugin_type(self):
pass
def get_plugin_description(self):
pass
def test_issubclass_hook(self):
class A(object):
class A(TestPluginInterface.ServicePluginStub):
def f(self):
pass
class B(base._PluginInterface):
class B(base.ServicePluginBase):
@abc.abstractmethod
def f(self):
pass
@ -62,18 +69,18 @@ class Test_PluginInterface(test_base.BaseTestCase):
def f(self):
pass
class B(base._PluginInterface):
class B(base.ServicePluginBase):
def f(self):
pass
self.assertFalse(issubclass(A, B))
def test_issubclass_hook_not_all_methods_implemented(self):
class A(object):
class A(TestPluginInterface.ServicePluginStub):
def f(self):
pass
class B(base._PluginInterface):
class B(base.ServicePluginBase):
@abc.abstractmethod
def f(self):
pass

View File

@ -0,0 +1,10 @@
---
features:
- The ``neutron_lib.api.extensions.ExtensionDescriptor`` class's
``get_plugin_interface`` method now formally only supports
``neutron_lib.services.base.ServicePluginBase``. This change reflects
the existing usage by consumers as almost all are returning
instances of ``ServicePluginBase`` already.
- The class ``WorkerBase`` is now available and provides the same
functionality that's provided by
``neutron.worker.WorkerSupportServiceMixin``.