From 0bd451f224c0eb3ad4698b89d6979850b0303c83 Mon Sep 17 00:00:00 2001 From: Boden R Date: Wed, 16 Aug 2017 15:08:50 -0600 Subject: [PATCH] rehome multi provider net extension api definition This patch rehomes the multi provider net extension's API definition and exceptions into neutron-lib. In addition a new validation and type is added as well as a utility function for checking duplicate segments. UTs and a release note are also included. Change-Id: If3367e6a14074a6225bba527e8f7e38c51280f85 --- neutron_lib/api/definitions/__init__.py | 2 + .../api/definitions/multiprovidernet.py | 71 +++++++++++++++++++ .../api/validators/multiprovidernet.py | 39 ++++++++++ neutron_lib/exceptions/multiprovidernet.py | 25 +++++++ .../api/definitions/test_multiprovidernet.py | 46 ++++++++++++ .../api/validators/test_multiprovidernet.py | 49 +++++++++++++ ...tiprovidernet-apidef-367e57772e931758.yaml | 8 +++ 7 files changed, 240 insertions(+) create mode 100644 neutron_lib/api/definitions/multiprovidernet.py create mode 100644 neutron_lib/api/validators/multiprovidernet.py create mode 100644 neutron_lib/exceptions/multiprovidernet.py create mode 100644 neutron_lib/tests/unit/api/definitions/test_multiprovidernet.py create mode 100644 neutron_lib/tests/unit/api/validators/test_multiprovidernet.py create mode 100644 releasenotes/notes/rehome-multiprovidernet-apidef-367e57772e931758.yaml diff --git a/neutron_lib/api/definitions/__init__.py b/neutron_lib/api/definitions/__init__.py index 2c4197721..7cc26d195 100644 --- a/neutron_lib/api/definitions/__init__.py +++ b/neutron_lib/api/definitions/__init__.py @@ -40,6 +40,7 @@ from neutron_lib.api.definitions import l3_flavors from neutron_lib.api.definitions import logging from neutron_lib.api.definitions import logging_resource from neutron_lib.api.definitions import metering +from neutron_lib.api.definitions import multiprovidernet from neutron_lib.api.definitions import network from neutron_lib.api.definitions import network_availability_zone from neutron_lib.api.definitions import network_ip_availability @@ -93,6 +94,7 @@ _ALL_API_DEFINITIONS = { logging, logging_resource, metering, + multiprovidernet, network, network_availability_zone, network_ip_availability, diff --git a/neutron_lib/api/definitions/multiprovidernet.py b/neutron_lib/api/definitions/multiprovidernet.py new file mode 100644 index 000000000..f2331552a --- /dev/null +++ b/neutron_lib/api/definitions/multiprovidernet.py @@ -0,0 +1,71 @@ +# Copyright (c) 2013 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 converters +from neutron_lib.api.definitions import network +from neutron_lib.api import validators +from neutron_lib.api.validators import multiprovidernet as mp_validator +from neutron_lib import constants +from neutron_lib.exceptions import multiprovidernet as mp_exc + + +def check_duplicate_segments(segments, is_partial_func=None): + """Helper function checking duplicate segments. + + If is_partial_funcs is specified and not None, then + SegmentsContainDuplicateEntry is raised if two segments are identical and + non partially defined (is_partial_func(segment) == False). + Otherwise SegmentsContainDuplicateEntry is raised if two segment are + identical. + """ + if is_partial_func is not None: + segments = [s for s in segments if not is_partial_func(s)] + fully_specifieds = [tuple(sorted(s.items())) for s in segments] + if len(set(fully_specifieds)) != len(fully_specifieds): + raise mp_exc.SegmentsContainDuplicateEntry() + + +validators.add_validator( + 'network_segments', mp_validator.convert_and_validate_segments) + +SEGMENTS = 'segments' + +ALIAS = 'multi-provider' +IS_SHIM_EXTENSION = False +IS_STANDARD_ATTR_EXTENSION = False +NAME = 'Multi Provider Network' +API_PREFIX = '' +DESCRIPTION = ("Expose mapping of virtual networks to multiple physical " + "networks") +UPDATED_TIMESTAMP = '2013-06-27T10:00:00-00:00' +RESOURCE_NAME = network.RESOURCE_NAME +COLLECTION_NAME = network.COLLECTION_NAME +RESOURCE_ATTRIBUTE_MAP = { + COLLECTION_NAME: { + SEGMENTS: { + 'allow_post': True, 'allow_put': True, + 'validate': {'type:network_segments': None}, + 'convert_list_to': converters.convert_kvp_list_to_dict, + 'default': constants.ATTR_NOT_SPECIFIED, + 'enforce_policy': True, + 'is_visible': True + }, + } +} +SUB_RESOURCE_ATTRIBUTE_MAP = {} +ACTION_MAP = {} +REQUIRED_EXTENSIONS = [] +OPTIONAL_EXTENSIONS = [] +ACTION_STATUS = {} diff --git a/neutron_lib/api/validators/multiprovidernet.py b/neutron_lib/api/validators/multiprovidernet.py new file mode 100644 index 000000000..ebf1bcb11 --- /dev/null +++ b/neutron_lib/api/validators/multiprovidernet.py @@ -0,0 +1,39 @@ +# Copyright (c) 2013 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 webob import exc + +from neutron_lib._i18n import _ +from neutron_lib.api import converters +from neutron_lib.api.definitions import provider_net as pnet +from neutron_lib import constants + + +def convert_and_validate_segments(segments, valid_values=None): + for segment in segments: + segment.setdefault(pnet.NETWORK_TYPE, constants.ATTR_NOT_SPECIFIED) + segment.setdefault(pnet.PHYSICAL_NETWORK, constants.ATTR_NOT_SPECIFIED) + segmentation_id = segment.get(pnet.SEGMENTATION_ID) + if segmentation_id: + segment[pnet.SEGMENTATION_ID] = converters.convert_to_int( + segmentation_id) + else: + segment[pnet.SEGMENTATION_ID] = constants.ATTR_NOT_SPECIFIED + if len(segment) != 3: + msg = (_("Unrecognized attribute(s) '%s'") % + ', '.join(set(segment.keys()) - + set([pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK, + pnet.SEGMENTATION_ID]))) + raise exc.HTTPBadRequest(msg) diff --git a/neutron_lib/exceptions/multiprovidernet.py b/neutron_lib/exceptions/multiprovidernet.py new file mode 100644 index 000000000..97a80ed3d --- /dev/null +++ b/neutron_lib/exceptions/multiprovidernet.py @@ -0,0 +1,25 @@ +# Copyright (c) 2013 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._i18n import _ +from neutron_lib import exceptions + + +class SegmentsSetInConjunctionWithProviders(exceptions.InvalidInput): + message = _("Segments and provider values cannot both be set.") + + +class SegmentsContainDuplicateEntry(exceptions.InvalidInput): + message = _("Duplicate segment entry in request.") diff --git a/neutron_lib/tests/unit/api/definitions/test_multiprovidernet.py b/neutron_lib/tests/unit/api/definitions/test_multiprovidernet.py new file mode 100644 index 000000000..5dce1ec9a --- /dev/null +++ b/neutron_lib/tests/unit/api/definitions/test_multiprovidernet.py @@ -0,0 +1,46 @@ +# 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 multiprovidernet +from neutron_lib.api.definitions import provider_net +from neutron_lib.exceptions import multiprovidernet as mp_exc +from neutron_lib.tests.unit.api.definitions import base +from neutron_lib.tests.unit.api.validators import test_multiprovidernet \ + as test_mpnet + + +class MultiProviderNetworkDefinitionTestCase(base.DefinitionBaseTestCase): + extension_module = multiprovidernet + extension_attributes = (multiprovidernet.SEGMENTS,) + + def test_check_duplicate_segments_with_dups(self): + self.assertRaises(mp_exc.SegmentsContainDuplicateEntry, + multiprovidernet.check_duplicate_segments, + [test_mpnet._build_segment('nt0', 'pn0', 2), + test_mpnet._build_segment('nt0', 'pn0', 2)]) + + def test_check_duplicate_segments_with_dups_and_partial(self): + + def _seg_partial(seg): + return seg[provider_net.PHYSICAL_NETWORK] == 'pn0' + + self.assertIsNone( + multiprovidernet.check_duplicate_segments( + [test_mpnet._build_segment('nt0', 'pn0', 2), + test_mpnet._build_segment('nt1', 'pn1', 2)], + is_partial_func=_seg_partial)) + + def test_check_duplicate_segments_no_dups(self): + self.assertIsNone( + multiprovidernet.check_duplicate_segments( + [test_mpnet._build_segment('nt0', 'pn0', 2), + test_mpnet._build_segment('nt0', 'pn0', 3)])) diff --git a/neutron_lib/tests/unit/api/validators/test_multiprovidernet.py b/neutron_lib/tests/unit/api/validators/test_multiprovidernet.py new file mode 100644 index 000000000..370fd93c6 --- /dev/null +++ b/neutron_lib/tests/unit/api/validators/test_multiprovidernet.py @@ -0,0 +1,49 @@ +# 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 webob import exc + +from neutron_lib.api.definitions import provider_net +from neutron_lib.api.validators import multiprovidernet as mp_validator +from neutron_lib import constants +from neutron_lib.tests import _base as base + + +def _build_segment(net_type=constants.ATTR_NOT_SPECIFIED, + phy_net=constants.ATTR_NOT_SPECIFIED, + seg_id=constants.ATTR_NOT_SPECIFIED): + return { + provider_net.NETWORK_TYPE: net_type, + provider_net.PHYSICAL_NETWORK: phy_net, + provider_net.SEGMENTATION_ID: seg_id + } + + +class TestMultiprovidernetValidators(base.BaseTestCase): + + def test_convert_and_validate_segments_default_values(self): + segs = [{}] + mp_validator.convert_and_validate_segments(segs) + self.assertEqual( + [_build_segment()], segs) + + def test_convert_and_validate_segments_seg_id_to_int(self): + segs = [_build_segment(seg_id="9")] + mp_validator.convert_and_validate_segments(segs) + self.assertEqual(_build_segment(seg_id=9), segs[0]) + + def test_convert_and_validate_segments_invalid_key(self): + segs = [_build_segment(seg_id=2)] + segs[0]['some_key'] = 'some_value' + self.assertRaises(exc.HTTPBadRequest, + mp_validator.convert_and_validate_segments, + segs) diff --git a/releasenotes/notes/rehome-multiprovidernet-apidef-367e57772e931758.yaml b/releasenotes/notes/rehome-multiprovidernet-apidef-367e57772e931758.yaml new file mode 100644 index 000000000..eddbf96f9 --- /dev/null +++ b/releasenotes/notes/rehome-multiprovidernet-apidef-367e57772e931758.yaml @@ -0,0 +1,8 @@ +--- +features: + - The ``multi-provider`` extension's API definition is available in + ``neutron_lib.api.defintions.multiprovidernet``. + - Exceptions for the ``multi-provider`` extension can be found in + ``neutron_lib.exceptions.multiprovidernet``. + - The validation type ``type:network_segments`` is now available for + API attribute validation.