rehome flavor extension API definition
This patch rehomes the flavor extension API definition into neutron-lib along with it's associated exceptions and validator. Please see the release notes for some minor refactoring that's done as part of this patch. Change-Id: I0229a80bb168bac8dc0fa17fb2b06f1b140d27b4
This commit is contained in:
parent
5e6153b144
commit
3ee0386c31
@ -29,6 +29,7 @@ from neutron_lib.api.definitions import fip64
|
||||
from neutron_lib.api.definitions import firewall
|
||||
from neutron_lib.api.definitions import firewall_v2
|
||||
from neutron_lib.api.definitions import firewallrouterinsertion
|
||||
from neutron_lib.api.definitions import flavors
|
||||
from neutron_lib.api.definitions import ip_allocation
|
||||
from neutron_lib.api.definitions import l2_adjacency
|
||||
from neutron_lib.api.definitions import l3
|
||||
@ -80,6 +81,7 @@ _ALL_API_DEFINITIONS = {
|
||||
firewall,
|
||||
firewall_v2,
|
||||
firewallrouterinsertion,
|
||||
flavors,
|
||||
ip_allocation,
|
||||
l2_adjacency,
|
||||
l3,
|
||||
|
124
neutron_lib/api/definitions/flavors.py
Normal file
124
neutron_lib/api/definitions/flavors.py
Normal file
@ -0,0 +1,124 @@
|
||||
# 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 converters
|
||||
from neutron_lib.db import constants as db_const
|
||||
|
||||
FLAVOR = 'flavor'
|
||||
FLAVORS = FLAVOR + 's'
|
||||
SERVICE_PROFILES = 'service_profiles'
|
||||
NEXT_PROVIDERS = 'next_providers'
|
||||
|
||||
ALIAS = FLAVORS
|
||||
IS_SHIM_EXTENSION = False
|
||||
IS_STANDARD_ATTR_EXTENSION = False
|
||||
NAME = 'Neutron Service Flavors'
|
||||
API_PREFIX = ''
|
||||
DESCRIPTION = 'Flavor specification for Neutron advanced services.'
|
||||
UPDATED_TIMESTAMP = '2015-09-17T10:00:00-00:00'
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
FLAVORS: {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': db_const.NAME_FIELD_SIZE},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string_or_none':
|
||||
db_const.LONG_DESCRIPTION_FIELD_SIZE},
|
||||
'is_visible': True, 'default': ''},
|
||||
'service_type': {'allow_post': True, 'allow_put': False,
|
||||
'validate':
|
||||
{'type:service_plugin_type': None},
|
||||
'is_visible': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {
|
||||
'type:string': db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True},
|
||||
'service_profiles': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'is_visible': True, 'default': []},
|
||||
'enabled': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': converters.convert_to_boolean_if_not_none,
|
||||
'default': True,
|
||||
'is_visible': True},
|
||||
},
|
||||
SERVICE_PROFILES: {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string_or_none':
|
||||
db_const.LONG_DESCRIPTION_FIELD_SIZE},
|
||||
'is_visible': True, 'default': ''},
|
||||
'driver': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string':
|
||||
db_const.LONG_DESCRIPTION_FIELD_SIZE},
|
||||
'is_visible': True,
|
||||
'default': ''},
|
||||
'metainfo': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True,
|
||||
'default': ''},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {
|
||||
'type:string': db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True},
|
||||
'enabled': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': converters.convert_to_boolean_if_not_none,
|
||||
'is_visible': True, 'default': True},
|
||||
},
|
||||
}
|
||||
SUB_RESOURCE_ATTRIBUTE_MAP = {
|
||||
NEXT_PROVIDERS: {
|
||||
'parent': {'collection_name': FLAVORS,
|
||||
'member_name': FLAVOR},
|
||||
'parameters': {'provider': {'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True},
|
||||
'driver': {'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True},
|
||||
'metainfo': {'allow_post': False,
|
||||
'allow_put': False,
|
||||
'is_visible': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {
|
||||
'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}}
|
||||
},
|
||||
SERVICE_PROFILES: {
|
||||
'parent': {'collection_name': FLAVORS,
|
||||
'member_name': FLAVOR},
|
||||
'parameters': {'id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {
|
||||
'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True}}
|
||||
}
|
||||
}
|
||||
ACTION_MAP = {}
|
||||
REQUIRED_EXTENSIONS = []
|
||||
OPTIONAL_EXTENSIONS = []
|
||||
ACTION_STATUS = {}
|
@ -25,6 +25,8 @@ import six
|
||||
from neutron_lib._i18n import _
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -1015,6 +1017,20 @@ def validate_subports(data, valid_values=None):
|
||||
segmentations[segmentation_type].add(segmentation_id)
|
||||
|
||||
|
||||
def validate_service_plugin_type(data, valid_values=None):
|
||||
"""Validates data is a valid service plugin.
|
||||
|
||||
:param data: The service plugin type to validate.
|
||||
:param valid_values: Not used.
|
||||
:returns: None if data is a valid service plugin known to the plugin
|
||||
directory.
|
||||
:raises: InvalidServiceType if data is not a service known by the
|
||||
plugin directory.
|
||||
"""
|
||||
if not directory.get_plugin(data):
|
||||
raise n_exc.InvalidServiceType(service_type=data)
|
||||
|
||||
|
||||
# Dictionary that maintains a list of validation functions
|
||||
validators = {'type:dict': validate_dict,
|
||||
'type:dict_or_none': validate_dict_or_none,
|
||||
@ -1055,7 +1071,8 @@ validators = {'type:dict': validate_dict,
|
||||
'type:integer': validate_integer,
|
||||
'type:list_of_unique_strings': validate_list_of_unique_strings,
|
||||
'type:list_of_any_key_specs_or_none':
|
||||
validate_any_key_specs_or_none}
|
||||
validate_any_key_specs_or_none,
|
||||
'type:service_plugin_type': validate_service_plugin_type}
|
||||
|
||||
|
||||
def _to_validation_type(validation_type):
|
||||
|
@ -531,3 +531,11 @@ class NetworkMacAddressGenerationFailure(ServiceUnavailable):
|
||||
:param net_id: The ID of the network MAC address generation failed on.
|
||||
"""
|
||||
message = _("Unable to generate unique mac on network %(net_id)s.")
|
||||
|
||||
|
||||
class InvalidServiceType(InvalidInput):
|
||||
"""An error due to an invalid service type.
|
||||
|
||||
:param service_type: The service type that's invalid.
|
||||
"""
|
||||
message = _("Invalid service type: %(service_type)s.")
|
||||
|
58
neutron_lib/exceptions/flavors.py
Normal file
58
neutron_lib/exceptions/flavors.py
Normal file
@ -0,0 +1,58 @@
|
||||
# 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._i18n import _
|
||||
from neutron_lib import exceptions
|
||||
|
||||
|
||||
class FlavorNotFound(exceptions.NotFound):
|
||||
message = _("Flavor %(flavor_id)s could not be found.")
|
||||
|
||||
|
||||
class FlavorInUse(exceptions.InUse):
|
||||
message = _("Flavor %(flavor_id)s is used by some service instance.")
|
||||
|
||||
|
||||
class ServiceProfileNotFound(exceptions.NotFound):
|
||||
message = _("Service Profile %(sp_id)s could not be found.")
|
||||
|
||||
|
||||
class ServiceProfileInUse(exceptions.InUse):
|
||||
message = _("Service Profile %(sp_id)s is used by some service instance.")
|
||||
|
||||
|
||||
class FlavorServiceProfileBindingExists(exceptions.Conflict):
|
||||
message = _("Service Profile %(sp_id)s is already associated "
|
||||
"with flavor %(fl_id)s.")
|
||||
|
||||
|
||||
class FlavorServiceProfileBindingNotFound(exceptions.NotFound):
|
||||
message = _("Service Profile %(sp_id)s is not associated "
|
||||
"with flavor %(fl_id)s.")
|
||||
|
||||
|
||||
class ServiceProfileDriverNotFound(exceptions.NotFound):
|
||||
message = _("Service Profile driver %(driver)s could not be found.")
|
||||
|
||||
|
||||
class ServiceProfileEmpty(exceptions.InvalidInput):
|
||||
message = _("Service Profile needs either a driver or metainfo.")
|
||||
|
||||
|
||||
class FlavorDisabled(exceptions.ServiceUnavailable):
|
||||
message = _("Flavor is not enabled.")
|
||||
|
||||
|
||||
class ServiceProfileDisabled(exceptions.ServiceUnavailable):
|
||||
message = _("Service Profile is not enabled.")
|
24
neutron_lib/tests/unit/api/definitions/test_flavors.py
Normal file
24
neutron_lib/tests/unit/api/definitions/test_flavors.py
Normal file
@ -0,0 +1,24 @@
|
||||
# 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.definitions import flavors
|
||||
from neutron_lib.tests.unit.api.definitions import base
|
||||
|
||||
|
||||
class FlavorsDefinitionTestCase(base.DefinitionBaseTestCase):
|
||||
extension_module = flavors
|
||||
extension_resources = (flavors.FLAVORS,
|
||||
flavors.SERVICE_PROFILES,)
|
||||
extension_subresources = (flavors.NEXT_PROVIDERS,
|
||||
flavors.SERVICE_PROFILES,)
|
||||
extension_attributes = ('enabled', 'provider', 'metainfo', 'driver',
|
||||
flavors.SERVICE_PROFILES, 'service_type',)
|
@ -22,6 +22,8 @@ from neutron_lib.api.definitions import extra_dhcp_opt
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib import fixture
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.tests import _base as base
|
||||
|
||||
|
||||
@ -1202,3 +1204,22 @@ class TestAnyKeySpecs(base.BaseTestCase):
|
||||
self.assertIsNone(
|
||||
validators.validate_any_key_specs_or_none(
|
||||
data, key_specs=extra_dhcp_opt.EXTRA_DHCP_OPT_KEY_SPECS))
|
||||
|
||||
|
||||
class TestServicePluginType(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestServicePluginType, self).setUp()
|
||||
self._plugins = directory._PluginDirectory()
|
||||
self._plugins.add_plugin('stype', mock.Mock())
|
||||
self.useFixture(fixture.PluginDirectoryFixture(
|
||||
plugin_directory=self._plugins))
|
||||
|
||||
def test_valid_plugin_type(self):
|
||||
self.assertIsNone(validators.validate_service_plugin_type('stype'))
|
||||
|
||||
def test_invalid_plugin_type(self):
|
||||
self.assertRaisesRegex(
|
||||
n_exc.InvalidServiceType,
|
||||
'Invalid service type',
|
||||
validators.validate_service_plugin_type, 'ntype')
|
||||
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
features:
|
||||
- The ``flavors`` API definition is now available in
|
||||
``neutron_lib.api.definitions.flavors``.
|
||||
- A new ``type:service_plugin_type`` validator has been added that
|
||||
allows a service plugin to be validated at runtime by checking
|
||||
the ``neutron_lib.plugins.directory``.
|
||||
- Exceptions related to the ``flavor`` API have been added to
|
||||
``neutron_lib.exceptions.flavors`` except for
|
||||
``InvalidFlavorServiceType`` which is now a generic
|
||||
``InvalidServiceType`` in ``neutron_lib.exceptions``.
|
Loading…
Reference in New Issue
Block a user