From 5f2f51d83ae23391b57fc3b39be87aca510e331a Mon Sep 17 00:00:00 2001 From: Boden R Date: Tue, 7 Nov 2017 10:50:01 -0700 Subject: [PATCH] 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 --- neutron_lib/api/extensions.py | 48 +++++++++++++------ neutron_lib/tests/unit/api/test_extensions.py | 7 ++- ...map-and-classmethods-76accdd5c56a3bd4.yaml | 11 +++++ 3 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 releasenotes/notes/subresource-update-attrmap-and-classmethods-76accdd5c56a3bd4.yaml diff --git a/neutron_lib/api/extensions.py b/neutron_lib/api/extensions.py index d7cd26fb4..24bcd7cb9 100644 --- a/neutron_lib/api/extensions.py +++ b/neutron_lib/api/extensions.py @@ -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) diff --git a/neutron_lib/tests/unit/api/test_extensions.py b/neutron_lib/tests/unit/api/test_extensions.py index 5e4a7da39..51fe8ef9c 100644 --- a/neutron_lib/tests/unit/api/test_extensions.py +++ b/neutron_lib/tests/unit/api/test_extensions.py @@ -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, diff --git a/releasenotes/notes/subresource-update-attrmap-and-classmethods-76accdd5c56a3bd4.yaml b/releasenotes/notes/subresource-update-attrmap-and-classmethods-76accdd5c56a3bd4.yaml new file mode 100644 index 000000000..a790f8362 --- /dev/null +++ b/releasenotes/notes/subresource-update-attrmap-and-classmethods-76accdd5c56a3bd4.yaml @@ -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.