class methods and sub resources in base api ext

Today the get_extended_resources method of our APIExtensionDescriptor
class does not account for the SUB_RESOURCE_ATTRIBUTE_MAP and as a
result callers of update_attributes_map will also not see the sub
resources.

This patch updates get_extended_resources to include the sub resources
as well.

Note that today in neutron, we have both uses:
- neutron.extensions.qos.Qos.get_extended_resources uses sub resources.
- neutron.extensions.flavors.Flavors.get_extended_resources does not
use the sub resource map.

In addition this patch changes the methods defined in the
APIExtensionDescriptor to be class methods rather than instance methods.
There is no real instance data to maintain and in addition consumers
need a way to access the update_attributes_map method without having
to import and create a concrete neutron extension instance [1].

[1] http://codesearch.openstack.org/?q=%5C(%5C)%5C.update_attributes_map%5C(

Change-Id: I8ae11633962a48de6e8559b85447b8c8c753d705
This commit is contained in:
Boden R 2017-11-07 10:50:01 -07:00 committed by Ihar Hrachyshka
parent ca47ee87e6
commit 5f2f51d83a
3 changed files with 49 additions and 17 deletions

View File

@ -220,32 +220,50 @@ class APIExtensionDescriptor(ExtensionDescriptor):
cls._assert_api_definition('UPDATED_TIMESTAMP')
return cls.api_definition.UPDATED_TIMESTAMP
def get_extended_resources(self, version):
"""Retrieve the resource attribute map for the API definition."""
@classmethod
def get_extended_resources(cls, version):
"""Retrieve the extended resource map for the API definition.
:param version: The API version to retrieve the resource attribute
map for.
:returns: The extended resource map for the underlying API definition
if the version is 2.0. The extended resource map returned includes
both the API definition's RESOURCE_ATTRIBUTE_MAP and
SUB_RESOURCE_ATTRIBUTE_MAP where applicable. If the version is
not 2.0, an empty dict is returned.
"""
if version == "2.0":
self._assert_api_definition('RESOURCE_ATTRIBUTE_MAP')
return self.api_definition.RESOURCE_ATTRIBUTE_MAP
cls._assert_api_definition('RESOURCE_ATTRIBUTE_MAP')
cls._assert_api_definition('SUB_RESOURCE_ATTRIBUTE_MAP')
# support api defs that use None for sub attr map
sub_attrs = cls.api_definition.SUB_RESOURCE_ATTRIBUTE_MAP or {}
return dict(
list(cls.api_definition.RESOURCE_ATTRIBUTE_MAP.items()) +
list(sub_attrs.items()))
else:
return {}
def get_required_extensions(self):
@classmethod
def get_required_extensions(cls):
"""Returns the API definition's required extensions."""
self._assert_api_definition('REQUIRED_EXTENSIONS')
return self.api_definition.REQUIRED_EXTENSIONS
cls._assert_api_definition('REQUIRED_EXTENSIONS')
return cls.api_definition.REQUIRED_EXTENSIONS
def get_optional_extensions(self):
@classmethod
def get_optional_extensions(cls):
"""Returns the API definition's optional extensions."""
self._assert_api_definition('OPTIONAL_EXTENSIONS')
return self.api_definition.OPTIONAL_EXTENSIONS
cls._assert_api_definition('OPTIONAL_EXTENSIONS')
return cls.api_definition.OPTIONAL_EXTENSIONS
def update_attributes_map(self, attributes, extension_attrs_map=None):
@classmethod
def update_attributes_map(cls, attributes, extension_attrs_map=None):
"""Update attributes map for this extension.
Behaves like ExtensionDescriptor.update_attributes_map(), but
if extension_attrs_map is not given the extension's API
definition RESOURCE_ATTRIBUTE_MAP is used.
if extension_attrs_map is not given the dict returned from
self.get_extended_resources('2.0') is used.
"""
if extension_attrs_map is None:
extension_attrs_map = self.get_extended_resources('2.0')
super(APIExtensionDescriptor, self).update_attributes_map(
extension_attrs_map = cls.get_extended_resources('2.0')
super(APIExtensionDescriptor, cls()).update_attributes_map(
attributes, extension_attrs_map=extension_attrs_map)

View File

@ -119,6 +119,7 @@ class TestAPIExtensionDescriptor(base.BaseTestCase):
DESCRIPTION = 'A test API definition'
UPDATED_TIMESTAMP = '2017-02-01T10:00:00-00:00'
RESOURCE_ATTRIBUTE_MAP = {'ports': {}}
SUB_RESOURCE_ATTRIBUTE_MAP = {'ports': {'debug': {}}}
REQUIRED_EXTENSIONS = ['l3']
OPTIONAL_EXTENSIONS = ['fw']
@ -162,8 +163,10 @@ class TestAPIExtensionDescriptor(base.BaseTestCase):
self.assertRaises(NotImplementedError, _EmptyAPIDefinition.get_updated)
def test_get_extended_resources_v2(self):
self.assertEqual(self.RESOURCE_ATTRIBUTE_MAP,
self.extn.get_extended_resources('2.0'))
self.assertEqual(
dict(list(self.RESOURCE_ATTRIBUTE_MAP.items()) +
list(self.SUB_RESOURCE_ATTRIBUTE_MAP.items())),
self.extn.get_extended_resources('2.0'))
def test_get_extended_resources_v2_unset(self):
self.assertRaises(NotImplementedError,

View File

@ -0,0 +1,11 @@
---
features:
- All methods defined in ``APIExtensionDescriptor`` are now class methods.
This allows consumers to call them without a reference to an actual
extension object instance.
fixes:
- The ``get_extended_resources`` method of the ``APIExtensionDescriptor``
was updated to also include the underlying API definition's
``SUB_RESOURCE_ATTRIBUTE_MAP`` in the returned dict. As a result, the
``update_attributes_map`` method now also includes the sub-resources if no
``extension_attrs_map`` is passed to it.