From 76326b19cc9a5550e209eb1ae1f489656e714193 Mon Sep 17 00:00:00 2001 From: Kailun Qin Date: Sat, 15 Dec 2018 23:21:54 +0800 Subject: [PATCH] Add network segment range resource Add network segment range resource in support of network segment range management. This patch set includes the following: - Network segment range resource - Proxy CRUD interfaces for the network segment range resource - Documentation updates - Unit tests - Function tests (currently skipped) Co-authored-by: Allain Legacy Partially-implements: blueprint network-segment-range-management Change-Id: I62ddf40387fd589e788ac45235fbe6bdc6612ad8 --- doc/source/user/resources/network/index.rst | 1 + .../network/v2/network_segment_range.rst | 13 ++ openstack/network/v2/_proxy.py | 118 ++++++++++++++++++ openstack/network/v2/network_segment_range.py | 71 +++++++++++ .../network/v2/test_network_segment_range.py | 99 +++++++++++++++ .../network/v2/test_network_segment_range.py | 64 ++++++++++ openstack/tests/unit/network/v2/test_proxy.py | 30 +++++ 7 files changed, 396 insertions(+) create mode 100644 doc/source/user/resources/network/v2/network_segment_range.rst create mode 100644 openstack/network/v2/network_segment_range.py create mode 100644 openstack/tests/functional/network/v2/test_network_segment_range.py create mode 100644 openstack/tests/unit/network/v2/test_network_segment_range.py diff --git a/doc/source/user/resources/network/index.rst b/doc/source/user/resources/network/index.rst index 21da8cf9f..9011b0c90 100644 --- a/doc/source/user/resources/network/index.rst +++ b/doc/source/user/resources/network/index.rst @@ -18,6 +18,7 @@ Network Resources v2/metering_label_rule v2/network v2/network_ip_availability + v2/network_segment_range v2/pool v2/pool_member v2/port diff --git a/doc/source/user/resources/network/v2/network_segment_range.rst b/doc/source/user/resources/network/v2/network_segment_range.rst new file mode 100644 index 000000000..1f2c55ddf --- /dev/null +++ b/doc/source/user/resources/network/v2/network_segment_range.rst @@ -0,0 +1,13 @@ +openstack.network.v2.network_segment_range +========================================== + +.. automodule:: openstack.network.v2.network_segment_range + +The NetworkSegmentRange Class +----------------------------- + +The ``NetworkSegmentRange`` class inherits from :class:`~openstack.resource +.Resource`. + +.. autoclass:: openstack.network.v2.network_segment_range.NetworkSegmentRange + :members: diff --git a/openstack/network/v2/_proxy.py b/openstack/network/v2/_proxy.py index c7dd6e4a3..bc0966be8 100644 --- a/openstack/network/v2/_proxy.py +++ b/openstack/network/v2/_proxy.py @@ -29,6 +29,8 @@ from openstack.network.v2 import metering_label as _metering_label from openstack.network.v2 import metering_label_rule as _metering_label_rule from openstack.network.v2 import network as _network from openstack.network.v2 import network_ip_availability +from openstack.network.v2 import network_segment_range as \ + _network_segment_range from openstack.network.v2 import pool as _pool from openstack.network.v2 import pool_member as _pool_member from openstack.network.v2 import port as _port @@ -1345,6 +1347,122 @@ class Proxy(proxy.Proxy): return self._list(network_ip_availability.NetworkIPAvailability, paginated=False, **query) + def create_network_segment_range(self, **attrs): + """Create a new network segment range from attributes + + :param dict attrs: Keyword arguments which will be used to create a + :class:`~openstack.network.v2. + network_segment_range.NetworkSegmentRange`, + comprised of the properties on the + NetworkSegmentRange class. + + :returns: The results of network segment range creation + :rtype: :class:`~openstack.network.v2.network_segment_range + .NetworkSegmentRange` + """ + return self._create(_network_segment_range.NetworkSegmentRange, + **attrs) + + def delete_network_segment_range(self, network_segment_range, + ignore_missing=True): + """Delete a network segment range + + :param network_segment_range: The value can be either the ID of a + network segment range or a + :class:`~openstack.network.v2.network_segment_range. + NetworkSegmentRange` instance. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the network segment range does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent network segment range. + + :returns: ``None`` + """ + self._delete(_network_segment_range.NetworkSegmentRange, + network_segment_range, ignore_missing=ignore_missing) + + def find_network_segment_range(self, name_or_id, ignore_missing=True, + **args): + """Find a single network segment range + + :param name_or_id: The name or ID of a network segment range. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :param dict args: Any additional parameters to be passed into + underlying methods. such as query filters. + :returns: One :class:`~openstack.network.v2.network_segment_range + .NetworkSegmentRange` or None + """ + return self._find(_network_segment_range.NetworkSegmentRange, + name_or_id, ignore_missing=ignore_missing, **args) + + def get_network_segment_range(self, network_segment_range): + """Get a single network segment range + + :param network_segment_range: The value can be the ID of a network + segment range or a :class:`~openstack.network.v2. + network_segment_range.NetworkSegmentRange` instance. + + :returns: One :class:`~openstack.network.v2._network_segment_range. + NetworkSegmentRange` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_network_segment_range.NetworkSegmentRange, + network_segment_range) + + def network_segment_ranges(self, **query): + """Return a generator of network segment ranges + + :param kwargs query: Optional query parameters to be sent to limit + the resources being returned. Available parameters include: + + * ``name``: Name of the segments + * ``default``: The network segment range is loaded from the host + configuration file. + * ``shared``: The network segment range is shared with other + projects + * ``project_id``: ID of the project that owns the network + segment range + * ``network_type``: Network type for the network segment ranges + * ``physical_network``: Physical network name for the network + segment ranges + * ``minimum``: Minimum segmentation ID for the network segment + ranges + * ``maximum``: Maximum Segmentation ID for the network segment + ranges + * ``used``: Mapping of which segmentation ID in the range is + used by which tenant + * ``available``: List of available segmentation IDs in this + network segment range + + :returns: A generator of network segment range objects + :rtype: :class:`~openstack.network.v2._network_segment_range. + NetworkSegmentRange` + """ + return self._list(_network_segment_range.NetworkSegmentRange, + paginated=False, **query) + + def update_network_segment_range(self, network_segment_range, **attrs): + """Update a network segment range + + :param network_segment_range: Either the id of a network segment range + or a :class:`~openstack.network.v2._network_segment_range. + NetworkSegmentRange` instance. + :attrs kwargs: The attributes to update on the network segment range + represented by ``value``. + + :returns: The updated network segment range + :rtype: :class:`~openstack.network.v2._network_segment_range. + NetworkSegmentRange` + """ + return self._update(_network_segment_range.NetworkSegmentRange, + network_segment_range, **attrs) + def create_pool(self, **attrs): """Create a new pool from attributes diff --git a/openstack/network/v2/network_segment_range.py b/openstack/network/v2/network_segment_range.py new file mode 100644 index 000000000..2512f242d --- /dev/null +++ b/openstack/network/v2/network_segment_range.py @@ -0,0 +1,71 @@ +# Copyright (c) 2018, Intel Corporation. +# 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 openstack import resource + + +class NetworkSegmentRange(resource.Resource): + resource_key = 'network_segment_range' + resources_key = 'network_segment_ranges' + base_path = '/network_segment_ranges' + + # capabilities + allow_create = True + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'name', 'default', 'shared', 'project_id', + 'network_type', 'physical_network', 'minimum', 'maximum', + 'used', 'available' + ) + + # Properties + #: The network segment range name. + name = resource.Body('name') + #: The network segment range is loaded from the host configuration file. + #: *Type: bool* + default = resource.Body('default', type=bool) + #: The network segment range is shared with other projects. + #: *Type: bool* + shared = resource.Body('shared', type=bool) + #: The ID of the project associated with this network segment range. + project_id = resource.Body('project_id') + #: The type of network associated with this network segment range, such as + #: ``geneve``, ``gre``, ``vlan`` or ``vxlan``. + network_type = resource.Body('network_type') + #: The name of the physical network associated with this network segment + #: range. + physical_network = resource.Body('physical_network') + #: The minimum segmentation ID for this network segment range. The + #: network type defines the segmentation model, VLAN ID for ``vlan`` + #: network type and tunnel ID for ``geneve``, ``gre`` and ``vxlan`` + #: network types. + #: *Type: int* + minimum = resource.Body('minimum', type=int) + #: The maximum segmentation ID for this network segment range. The + #: network type defines the segmentation model, VLAN ID for ``vlan`` + #: network type and tunnel ID for ``geneve``, ``gre`` and ``vxlan`` + #: network types. + #: *Type: int* + maximum = resource.Body('maximum', type=int) + #: Mapping of which segmentation ID in the range is used by which tenant. + #: *Type: dict* + used = resource.Body('used', type=dict) + #: List of available segmentation IDs in this network segment range. + #: *Type: list* + available = resource.Body('available', type=list) diff --git a/openstack/tests/functional/network/v2/test_network_segment_range.py b/openstack/tests/functional/network/v2/test_network_segment_range.py new file mode 100644 index 000000000..d626d72f0 --- /dev/null +++ b/openstack/tests/functional/network/v2/test_network_segment_range.py @@ -0,0 +1,99 @@ +# Copyright (c) 2018, Intel Corporation. +# 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 openstack.network.v2 import network_segment_range +from openstack.tests.functional import base + + +class TestNetworkSegmentRange(base.BaseFunctionalTest): + + NETWORK_SEGMENT_RANGE_ID = None + NAME = 'test_name' + DEFAULT = False + SHARED = False + PROJECT_ID = '2018' + NETWORK_TYPE = 'vlan' + PHYSICAL_NETWORK = 'phys_net' + MINIMUM = 100 + MAXIMUM = 200 + + def setUp(self): + super(TestNetworkSegmentRange, self).setUp() + + # NOTE(kailun): The network segment range extension is not yet enabled + # by default. + # Skip the tests if not enabled. + if not self.conn.network.find_extension('network-segment-range'): + self.skipTest('Network Segment Range extension disabled') + + test_seg_range = self.conn.network.create_network_segment_range( + name=self.NAME, + default=self.DEFAULT, + shared=self.SHARED, + project_id=self.PROJECT_ID, + network_type=self.NETWORK_TYPE, + physical_network=self.PHYSICAL_NETWORK, + minimum=self.MINIMUM, + maximum=self.MAXIMUM, + ) + self.assertIsInstance(test_seg_range, + network_segment_range.NetworkSegmentRange) + self.NETWORK_SEGMENT_RANGE_ID = test_seg_range.id + self.assertEqual(self.NAME, test_seg_range.name) + self.assertEqual(self.DEFAULT, test_seg_range.default) + self.assertEqual(self.SHARED, test_seg_range.shared) + self.assertEqual(self.PROJECT_ID, test_seg_range.project_id) + self.assertEqual(self.NETWORK_TYPE, test_seg_range.network_type) + self.assertEqual(self.PHYSICAL_NETWORK, + test_seg_range.physical_network) + self.assertEqual(self.MINIMUM, test_seg_range.minimum) + self.assertEqual(self.MAXIMUM, test_seg_range.maximum) + + def tearDown(self): + super(TestNetworkSegmentRange, self).tearDown() + + def test_create_delete(self): + del_test_seg_range = self.conn.network.delete_network_segment_range( + self.NETWORK_SEGMENT_RANGE_ID) + self.assertIsNone(del_test_seg_range) + + def test_find(self): + test_seg_range = self.conn.network.find_network_segment_range( + self.NETWORK_SEGMENT_RANGE_ID) + self.assertEqual(self.NETWORK_SEGMENT_RANGE_ID, test_seg_range.id) + + def test_get(self): + test_seg_range = self.conn.network.get_network_segment_range( + self.NETWORK_SEGMENT_RANGE_ID) + self.assertEqual(self.NETWORK_SEGMENT_RANGE_ID, test_seg_range.id) + self.assertEqual(self.NAME, test_seg_range.name) + self.assertEqual(self.DEFAULT, test_seg_range.default) + self.assertEqual(self.SHARED, test_seg_range.shared) + self.assertEqual(self.PROJECT_ID, test_seg_range.project_id) + self.assertEqual(self.NETWORK_TYPE, test_seg_range.network_type) + self.assertEqual(self.PHYSICAL_NETWORK, + test_seg_range.physical_network) + self.assertEqual(self.MINIMUM, test_seg_range.minimum) + self.assertEqual(self.MAXIMUM, test_seg_range.maximum) + + def test_list(self): + ids = [o.id for o in self.conn.network.network_segment_ranges( + name=None)] + self.assertIn(self.NETWORK_SEGMENT_RANGE_ID, ids) + + def test_update(self): + update_seg_range = self.conn.network.update_segment( + self.NETWORK_SEGMENT_RANGE_ID, name='update_test_name') + self.assertEqual('update_test_name', update_seg_range.name) diff --git a/openstack/tests/unit/network/v2/test_network_segment_range.py b/openstack/tests/unit/network/v2/test_network_segment_range.py new file mode 100644 index 000000000..9a76cc234 --- /dev/null +++ b/openstack/tests/unit/network/v2/test_network_segment_range.py @@ -0,0 +1,64 @@ +# Copyright (c) 2018, Intel Corporation. +# 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 openstack.tests.unit import base + +from openstack.network.v2 import network_segment_range + +IDENTIFIER = 'IDENTIFIER' +EXAMPLE = { + 'id': IDENTIFIER, + 'name': '1', + 'default': False, + 'shared': False, + 'project_id': '2', + 'network_type': '3', + 'physical_network': '4', + 'minimum': 5, + 'maximum': 6, + 'used': {}, + 'available': [], +} + + +class TestNetworkSegmentRange(base.TestCase): + + def test_basic(self): + test_seg_range = network_segment_range.NetworkSegmentRange() + self.assertEqual('network_segment_range', test_seg_range.resource_key) + self.assertEqual('network_segment_ranges', + test_seg_range.resources_key) + self.assertEqual('/network_segment_ranges', test_seg_range.base_path) + + self.assertTrue(test_seg_range.allow_create) + self.assertTrue(test_seg_range.allow_fetch) + self.assertTrue(test_seg_range.allow_commit) + self.assertTrue(test_seg_range.allow_delete) + self.assertTrue(test_seg_range.allow_list) + + def test_make_it(self): + test_seg_range = network_segment_range.NetworkSegmentRange(**EXAMPLE) + self.assertEqual(EXAMPLE['id'], test_seg_range.id) + self.assertEqual(EXAMPLE['name'], test_seg_range.name) + self.assertEqual(EXAMPLE['default'], test_seg_range.default) + self.assertEqual(EXAMPLE['shared'], test_seg_range.shared) + self.assertEqual(EXAMPLE['project_id'], test_seg_range.project_id) + self.assertEqual(EXAMPLE['network_type'], test_seg_range.network_type) + self.assertEqual(EXAMPLE['physical_network'], + test_seg_range.physical_network) + self.assertEqual(EXAMPLE['minimum'], test_seg_range.minimum) + self.assertEqual(EXAMPLE['maximum'], test_seg_range.maximum) + self.assertEqual(EXAMPLE['used'], test_seg_range.used) + self.assertEqual(EXAMPLE['available'], test_seg_range.available) diff --git a/openstack/tests/unit/network/v2/test_proxy.py b/openstack/tests/unit/network/v2/test_proxy.py index 5f5bef458..2a7d98be2 100644 --- a/openstack/tests/unit/network/v2/test_proxy.py +++ b/openstack/tests/unit/network/v2/test_proxy.py @@ -32,6 +32,7 @@ from openstack.network.v2 import metering_label from openstack.network.v2 import metering_label_rule from openstack.network.v2 import network from openstack.network.v2 import network_ip_availability +from openstack.network.v2 import network_segment_range from openstack.network.v2 import pool from openstack.network.v2 import pool_member from openstack.network.v2 import port @@ -962,6 +963,35 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase): self.verify_update(self.proxy.update_firewall_rule, firewall_rule.FirewallRule) + def test_network_segment_range_create_attrs(self): + self.verify_create(self.proxy.create_network_segment_range, + network_segment_range.NetworkSegmentRange) + + def test_network_segment_range_delete(self): + self.verify_delete(self.proxy.delete_network_segment_range, + network_segment_range.NetworkSegmentRange, False) + + def test_network_segment_range_delete_ignore(self): + self.verify_delete(self.proxy.delete_network_segment_range, + network_segment_range.NetworkSegmentRange, True) + + def test_network_segment_range_find(self): + self.verify_find(self.proxy.find_network_segment_range, + network_segment_range.NetworkSegmentRange) + + def test_network_segment_range_get(self): + self.verify_get(self.proxy.get_network_segment_range, + network_segment_range.NetworkSegmentRange) + + def test_network_segment_ranges(self): + self.verify_list(self.proxy.network_segment_ranges, + network_segment_range.NetworkSegmentRange, + paginated=False) + + def test_network_segment_range_update(self): + self.verify_update(self.proxy.update_network_segment_range, + network_segment_range.NetworkSegmentRange) + def test_security_group_create_attrs(self): self.verify_create(self.proxy.create_security_group, security_group.SecurityGroup)