diff --git a/neutron_lib/api/definitions/__init__.py b/neutron_lib/api/definitions/__init__.py index b762abd70..441e1fde0 100644 --- a/neutron_lib/api/definitions/__init__.py +++ b/neutron_lib/api/definitions/__init__.py @@ -99,6 +99,7 @@ from neutron_lib.api.definitions import subnet from neutron_lib.api.definitions import subnet_onboard from neutron_lib.api.definitions import subnet_segmentid_enforce from neutron_lib.api.definitions import subnet_segmentid_writable +from neutron_lib.api.definitions import subnet_service_types from neutron_lib.api.definitions import subnetpool from neutron_lib.api.definitions import subnetpool_prefix_ops from neutron_lib.api.definitions import trunk @@ -200,6 +201,7 @@ _ALL_API_DEFINITIONS = { subnet_onboard, subnet_segmentid_enforce, subnet_segmentid_writable, + subnet_service_types, subnetpool, subnetpool_prefix_ops, trunk, diff --git a/neutron_lib/api/definitions/base.py b/neutron_lib/api/definitions/base.py index e5d1f962d..81d6b10cb 100644 --- a/neutron_lib/api/definitions/base.py +++ b/neutron_lib/api/definitions/base.py @@ -42,6 +42,7 @@ KNOWN_ATTRIBUTES = ( 'prefixlen', 'project_id', 'qos_policy_id', + 'service_types', constants.SHARED, 'status', 'subnets', @@ -135,6 +136,7 @@ KNOWN_EXTENSIONS = ( 'standard-attr-revisions', 'standard-attr-segment', 'standard-attr-timestamp', + 'subnet', 'subnet_allocation', 'subnet_onboard', 'subnetpool-prefix-ops', diff --git a/neutron_lib/api/definitions/subnet_service_types.py b/neutron_lib/api/definitions/subnet_service_types.py new file mode 100644 index 000000000..d3abfee76 --- /dev/null +++ b/neutron_lib/api/definitions/subnet_service_types.py @@ -0,0 +1,43 @@ +# 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 subnet as subnet_def +from neutron_lib import constants + + +ALIAS = 'subnet-service-types' +IS_SHIM_EXTENSION = False +IS_STANDARD_ATTR_EXTENSION = False +NAME = 'Subnet service types' +API_PREFIX = '' +DESCRIPTION = "Provides ability to set the subnet service_types field" +UPDATED_TIMESTAMP = "2016-03-15T18:00:00-00:00" +RESOURCE_NAME = 'service_type' +COLLECTION_NAME = 'service_types' + +RESOURCE_ATTRIBUTE_MAP = { + subnet_def.COLLECTION_NAME: { + COLLECTION_NAME: { + 'allow_post': True, + 'allow_put': True, + 'default': constants.ATTR_NOT_SPECIFIED, + 'validate': {'type:list_of_subnet_service_types': None}, + 'is_visible': True + } + } +} + +SUB_RESOURCE_ATTRIBUTE_MAP = {} +ACTION_MAP = {} +ACTION_STATUS = {} +REQUIRED_EXTENSIONS = [] +OPTIONAL_EXTENSIONS = [] diff --git a/neutron_lib/api/validators/__init__.py b/neutron_lib/api/validators/__init__.py index eff16ba43..896a7bd7d 100644 --- a/neutron_lib/api/validators/__init__.py +++ b/neutron_lib/api/validators/__init__.py @@ -21,6 +21,7 @@ from oslo_utils import netutils from oslo_utils import strutils from oslo_utils import uuidutils import six +from webob import exc from neutron_lib._i18n import _ from neutron_lib import constants @@ -1101,6 +1102,24 @@ def validate_service_plugin_type(data, valid_values=None): raise n_exc.InvalidServiceType(service_type=data) +def validate_subnet_service_types(service_types, valid_values=None): + if service_types: + if not isinstance(service_types, list): + raise exc.HTTPBadRequest( + _("Subnet service types must be a list.")) + + # Include standard prefixes + prefixes = list(constants.DEVICE_OWNER_PREFIXES) + prefixes += constants.DEVICE_OWNER_COMPUTE_PREFIX + + for service_type in service_types: + if not isinstance(service_type, six.text_type): + raise n_exc.InvalidInputSubnetServiceType( + service_type=service_type) + elif not service_type.startswith(tuple(prefixes)): + raise n_exc.InvalidSubnetServiceType(service_type=service_type) + + # Dictionary that maintains a list of validation functions validators = {'type:dict': validate_dict, 'type:dict_or_none': validate_dict_or_none, @@ -1144,7 +1163,9 @@ validators = {'type:dict': validate_dict, 'type:list_of_any_key_specs_or_none': validate_any_key_specs_or_none, 'type:service_plugin_type': validate_service_plugin_type, - 'type:list_of_subnets_or_none': validate_subnet_list_or_none + 'type:list_of_subnets_or_none': validate_subnet_list_or_none, + 'type:list_of_subnet_service_types': + validate_subnet_service_types } diff --git a/neutron_lib/exceptions/__init__.py b/neutron_lib/exceptions/__init__.py index 9f5b73c54..effc18397 100644 --- a/neutron_lib/exceptions/__init__.py +++ b/neutron_lib/exceptions/__init__.py @@ -807,3 +807,12 @@ class ProcessExecutionError(RuntimeError): def __init__(self, message, returncode): super(ProcessExecutionError, self).__init__(message) self.returncode = returncode + + +class InvalidSubnetServiceType(InvalidInput): + message = _("Subnet service type %(service_type)s does not correspond " + "to a valid device owner.") + + +class InvalidInputSubnetServiceType(InvalidInput): + message = _("Subnet service type %(service_type)s is not a string.") diff --git a/neutron_lib/tests/unit/api/definitions/test_subnet_service_types.py b/neutron_lib/tests/unit/api/definitions/test_subnet_service_types.py new file mode 100644 index 000000000..ec0bc2397 --- /dev/null +++ b/neutron_lib/tests/unit/api/definitions/test_subnet_service_types.py @@ -0,0 +1,21 @@ +# 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 subnet as subnet_def +from neutron_lib.api.definitions import subnet_service_types +from neutron_lib.tests.unit.api.definitions import base + + +class SubnetServiceTypesDefinitionTestCase(base.DefinitionBaseTestCase): + extension_module = subnet_service_types + extension_resource = (subnet_def.RESOURCE_NAME,) + extension_attributes = () diff --git a/releasenotes/notes/rehome-subnetservicetypes-apidef-31e2e9564c746317.yaml b/releasenotes/notes/rehome-subnetservicetypes-apidef-31e2e9564c746317.yaml new file mode 100644 index 000000000..c1ffb61bf --- /dev/null +++ b/releasenotes/notes/rehome-subnetservicetypes-apidef-31e2e9564c746317.yaml @@ -0,0 +1,7 @@ +--- +features: + - The ``subnet-service-types`` extension is now available in + ``neutron_lib.api.definitions.subnet_service_types``. + - The ``InvalidSubnetServiceType`` and ``InvalidInputSubnetServiceType`` + exceptions are now available in ``neutron_lib.exceptions``. + - The validation type ``list_of_subnet_service_types`` is now available.