Add ExtensionDescriptor to neutron-lib
When a subproject wants to create a class to extend the Neutron API, that class inherits from ExtensionDescriptor. This change pulls ExtensionDescriptor over to neutron-lib so that subprojects can inherit from it. This class is almost entirely abstract. This is used by nearly every neutron stadium project. Change-Id: I4e9ba9c0c7fd4c5f449f11b4f401fa265ae7ea43
This commit is contained in:
parent
08cefc5e0e
commit
bbd71c45c6
144
neutron_lib/api/extensions.py
Normal file
144
neutron_lib/api/extensions.py
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
# Copyright 2011 OpenStack Foundation.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 ExtensionDescriptor(object):
|
||||||
|
"""Base class that defines the contract for extensions."""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_name(self):
|
||||||
|
"""The name of the extension.
|
||||||
|
|
||||||
|
e.g. 'Fox In Socks'
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_alias(self):
|
||||||
|
"""The alias for the extension.
|
||||||
|
|
||||||
|
e.g. 'FOXNSOX'
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_description(self):
|
||||||
|
"""Friendly description for the extension.
|
||||||
|
|
||||||
|
e.g. 'The Fox In Socks Extension'
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_updated(self):
|
||||||
|
"""The timestamp when the extension was last updated.
|
||||||
|
|
||||||
|
e.g. '2011-01-22T13:25:27-06:00'
|
||||||
|
"""
|
||||||
|
# NOTE(justinsb): Not sure of the purpose of this is, vs the XML NS
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
"""List of extensions.ResourceExtension extension objects.
|
||||||
|
|
||||||
|
Resources define new nouns, and are accessible through URLs.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
"""List of extensions.ActionExtension extension objects.
|
||||||
|
|
||||||
|
Actions are verbs callable from the API.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_request_extensions(self):
|
||||||
|
"""List of extensions.RequestException extension objects.
|
||||||
|
|
||||||
|
Request extensions are used to handle custom request data.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
"""Retrieve extended resources or attributes for core resources.
|
||||||
|
|
||||||
|
Extended attributes are implemented by a core plugin similarly
|
||||||
|
to the attributes defined in the core, and can appear in
|
||||||
|
request and response messages. Their names are scoped with the
|
||||||
|
extension's prefix. The core API version is passed to this
|
||||||
|
function, which must return a
|
||||||
|
map[<resource_name>][<attribute_name>][<attribute_property>]
|
||||||
|
specifying the extended resource attribute properties required
|
||||||
|
by that API version.
|
||||||
|
|
||||||
|
Extension can add resources and their attr definitions too.
|
||||||
|
The returned map can be integrated into RESOURCE_ATTRIBUTE_MAP.
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_plugin_interface(self):
|
||||||
|
"""Returns an abstract class which defines contract for the plugin.
|
||||||
|
|
||||||
|
The abstract class should inherit from extensions.PluginInterface,
|
||||||
|
Methods in this abstract class should be decorated as abstractmethod
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_required_extensions(self):
|
||||||
|
"""Returns a list of extensions to be processed before this one."""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_optional_extensions(self):
|
||||||
|
"""Returns a list of extensions to be processed before this one.
|
||||||
|
|
||||||
|
Unlike get_required_extensions. This will not fail the loading of
|
||||||
|
the extension if one of these extensions is not present. This is
|
||||||
|
useful for an extension that extends multiple resources across
|
||||||
|
other extensions that should still work for the remaining extensions
|
||||||
|
when one is missing.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def update_attributes_map(self, extended_attributes,
|
||||||
|
extension_attrs_map=None):
|
||||||
|
"""Update attributes map for this extension.
|
||||||
|
|
||||||
|
This is default method for extending an extension's attributes map.
|
||||||
|
An extension can use this method and supplying its own resource
|
||||||
|
attribute map in extension_attrs_map argument to extend all its
|
||||||
|
attributes that needs to be extended.
|
||||||
|
|
||||||
|
If an extension does not implement update_attributes_map, the method
|
||||||
|
does nothing and just return.
|
||||||
|
"""
|
||||||
|
if not extension_attrs_map:
|
||||||
|
return
|
||||||
|
|
||||||
|
for resource, attrs in extension_attrs_map.items():
|
||||||
|
extended_attrs = extended_attributes.get(resource)
|
||||||
|
if extended_attrs:
|
||||||
|
attrs.update(extended_attrs)
|
||||||
|
|
||||||
|
def get_pecan_resources(self):
|
||||||
|
"""List of PecanResourceExtension extension objects.
|
||||||
|
|
||||||
|
Resources define new nouns, and are accessible through URLs.
|
||||||
|
The controllers associated with each instance of
|
||||||
|
extensions.ResourceExtension should be a subclass of
|
||||||
|
neutron.pecan_wsgi.controllers.utils.NeutronPecanController.
|
||||||
|
|
||||||
|
If a resource is defined in both get_resources and get_pecan_resources,
|
||||||
|
the resource defined in get_pecan_resources will take precedence.
|
||||||
|
"""
|
||||||
|
return []
|
83
neutron_lib/tests/unit/api/test_extensions.py
Normal file
83
neutron_lib/tests/unit/api/test_extensions.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Copyright 2016 OpenStack Foundation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from neutron_lib.api import extensions
|
||||||
|
from neutron_lib.tests import _base as base
|
||||||
|
|
||||||
|
|
||||||
|
class InheritFromExtensionDescriptor(extensions.ExtensionDescriptor):
|
||||||
|
"""Class to inherit from ExtensionDescriptor to test its methods
|
||||||
|
|
||||||
|
Because ExtensionDescriptor is an abstract class, in order to test methods
|
||||||
|
we need to create something to inherit from it so we have something
|
||||||
|
instantiatable. The only things defined here are those that are required
|
||||||
|
because in ExtensionDescriptor they are marked as @abc.abstractmethod.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_alias(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_updated(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_attributes_map_save(self, extended_attributes,
|
||||||
|
extension_attrs_map=None):
|
||||||
|
"""Update attributes map for this extension.
|
||||||
|
|
||||||
|
This is default method for extending an extension's attributes map.
|
||||||
|
An extension can use this method and supplying its own resource
|
||||||
|
attribute map in extension_attrs_map argument to extend all its
|
||||||
|
attributes that needs to be extended.
|
||||||
|
|
||||||
|
If an extension does not implement update_attributes_map, the method
|
||||||
|
does nothing and just return.
|
||||||
|
"""
|
||||||
|
if not extension_attrs_map:
|
||||||
|
return
|
||||||
|
|
||||||
|
for resource, attrs in extension_attrs_map.items():
|
||||||
|
extended_attrs = extended_attributes.get(resource)
|
||||||
|
if extended_attrs:
|
||||||
|
attrs.update(extended_attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestExtensionDescriptor(base.BaseTestCase):
|
||||||
|
|
||||||
|
def _setup_attribute_maps(self):
|
||||||
|
self.extended_attributes = {'resource_one': {'one': 'first'},
|
||||||
|
'resource_two': {'two': 'second'}}
|
||||||
|
self.extension_attrs_map = {'resource_one': {'three': 'third'}}
|
||||||
|
|
||||||
|
def test_update_attributes_map_works(self):
|
||||||
|
self._setup_attribute_maps()
|
||||||
|
extension_description = InheritFromExtensionDescriptor()
|
||||||
|
extension_description.update_attributes_map(self.extended_attributes,
|
||||||
|
self.extension_attrs_map)
|
||||||
|
self.assertEqual(self.extension_attrs_map,
|
||||||
|
{'resource_one': {'one': 'first',
|
||||||
|
'three': 'third'}})
|
||||||
|
|
||||||
|
def test_update_attributes_map_short_circuit_exit(self):
|
||||||
|
self._setup_attribute_maps()
|
||||||
|
extension_description = InheritFromExtensionDescriptor()
|
||||||
|
extension_description.update_attributes_map(self.extended_attributes)
|
||||||
|
self.assertEqual(self.extension_attrs_map,
|
||||||
|
{'resource_one': {'three': 'third'}})
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- The ExtensionDescriptor class moved from neutron.api.extensions to
|
||||||
|
neutron_lib.api.extensions.
|
Loading…
Reference in New Issue
Block a user