Merge "Add network segment create, delete and update support"
This commit is contained in:
		| @@ -2099,6 +2099,40 @@ class Proxy(proxy.BaseProxy): | ||||
|         return self._list(_security_group_rule.SecurityGroupRule, | ||||
|                           paginated=False, **query) | ||||
|  | ||||
|     def create_segment(self, **attrs): | ||||
|         """Create a new segment from attributes | ||||
|  | ||||
|         .. caution:: | ||||
|            BETA: This API is a work in progress and is subject to change. | ||||
|  | ||||
|         :param dict attrs: Keyword arguments which will be used to create | ||||
|                            a :class:`~openstack.network.v2.segment.Segment`, | ||||
|                            comprised of the properties on the Segment class. | ||||
|  | ||||
|         :returns: The results of segment creation | ||||
|         :rtype: :class:`~openstack.network.v2.segment.Segment` | ||||
|         """ | ||||
|         return self._create(_segment.Segment, **attrs) | ||||
|  | ||||
|     def delete_segment(self, segment, ignore_missing=True): | ||||
|         """Delete a segment | ||||
|  | ||||
|         .. caution:: | ||||
|            BETA: This API is a work in progress and is subject to change. | ||||
|  | ||||
|         :param segment: The value can be either the ID of a segment or a | ||||
|                         :class:`~openstack.network.v2.segment.Segment` | ||||
|                         instance. | ||||
|         :param bool ignore_missing: When set to ``False`` | ||||
|                     :class:`~openstack.exceptions.ResourceNotFound` will be | ||||
|                     raised when the segment does not exist. | ||||
|                     When set to ``True``, no exception will be set when | ||||
|                     attempting to delete a nonexistent segment. | ||||
|  | ||||
|         :returns: ``None`` | ||||
|         """ | ||||
|         self._delete(_segment.Segment, segment, ignore_missing=ignore_missing) | ||||
|  | ||||
|     def find_segment(self, name_or_id, ignore_missing=True): | ||||
|         """Find a single segment | ||||
|  | ||||
| @@ -2141,6 +2175,7 @@ class Proxy(proxy.BaseProxy): | ||||
|         :param kwargs \*\*query: Optional query parameters to be sent to limit | ||||
|             the resources being returned. Available parameters include: | ||||
|  | ||||
|             * name: Name of the segments | ||||
|             * network_id: ID of the network that owns the segments | ||||
|             * network_type: Network type for the segments | ||||
|             * physical_network: Physical network name for the segments | ||||
| @@ -2151,6 +2186,23 @@ class Proxy(proxy.BaseProxy): | ||||
|         """ | ||||
|         return self._list(_segment.Segment, paginated=False, **query) | ||||
|  | ||||
|     def update_segment(self, segment, **attrs): | ||||
|         """Update a segment | ||||
|  | ||||
|         .. caution:: | ||||
|            BETA: This API is a work in progress and is subject to change. | ||||
|  | ||||
|         :param segment: Either the id of a segment or a | ||||
|                         :class:`~openstack.network.v2.segment.Segment` | ||||
|                         instance. | ||||
|         :attrs kwargs: The attributes to update on the segment represented | ||||
|                        by ``value``. | ||||
|  | ||||
|         :returns: The update segment | ||||
|         :rtype: :class:`~openstack.network.v2.segment.Segment` | ||||
|         """ | ||||
|         return self._update(_segment.Segment, segment, **attrs) | ||||
|  | ||||
|     def create_subnet(self, **attrs): | ||||
|         """Create a new subnet from attributes | ||||
|  | ||||
|   | ||||
| @@ -22,24 +22,26 @@ class Segment(resource.Resource): | ||||
|     service = network_service.NetworkService() | ||||
|  | ||||
|     # capabilities | ||||
|     allow_create = False | ||||
|     allow_create = True | ||||
|     allow_retrieve = True | ||||
|     allow_update = False | ||||
|     allow_delete = False | ||||
|     allow_update = True | ||||
|     allow_delete = True | ||||
|     allow_list = True | ||||
|  | ||||
|     # TODO(rtheis): Add description and name properties when support | ||||
|     # is available. | ||||
|  | ||||
|     # Properties | ||||
|     #: The segment description. | ||||
|     description = resource.prop('description') | ||||
|     #: The segment name. | ||||
|     name = resource.prop('name') | ||||
|     #: The ID of the network associated with this segment. | ||||
|     network_id = resource.prop('network_id') | ||||
|     #: The type of network associated with this segment, such as | ||||
|     #: ``flat``, ``gre``, ``vlan`` or ``vxlan``. | ||||
|     #: ``flat``, ``geneve``, ``gre``, ``local``, ``vlan`` or ``vxlan``. | ||||
|     network_type = resource.prop('network_type') | ||||
|     #: The name of the physical network associated with this segment. | ||||
|     physical_network = resource.prop('physical_network') | ||||
|     #: The segmentation ID for this segment. The network type | ||||
|     #: defines the segmentation model, VLAN ID for ``vlan`` network type | ||||
|     #: and tunnel ID for ``gre`` and ``vxlan`` network types. *Type: int* | ||||
|     #: and tunnel ID for ``geneve``, ``gre`` and ``vxlan`` network types. | ||||
|     #: *Type: int* | ||||
|     segmentation_id = resource.prop('segmentation_id', type=int) | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
| # License for the specific language governing permissions and limitations | ||||
| # under the License. | ||||
|  | ||||
| import unittest | ||||
| import uuid | ||||
|  | ||||
| from openstack.network.v2 import network | ||||
| @@ -18,8 +17,6 @@ from openstack.network.v2 import segment | ||||
| from openstack.tests.functional import base | ||||
|  | ||||
|  | ||||
| # NOTE(rtheis): Routed networks is still a WIP and not enabled by default. | ||||
| @unittest.skip("bp/routed-networks") | ||||
| class TestSegment(base.BaseFunctionalTest): | ||||
|  | ||||
|     NETWORK_NAME = uuid.uuid4().hex | ||||
| @@ -28,26 +25,32 @@ class TestSegment(base.BaseFunctionalTest): | ||||
|     SEGMENTATION_ID = None | ||||
|     NETWORK_ID = None | ||||
|     SEGMENT_ID = None | ||||
|     SEGMENT_EXTENSION = None | ||||
|  | ||||
|     @classmethod | ||||
|     def setUpClass(cls): | ||||
|         super(TestSegment, cls).setUpClass() | ||||
|  | ||||
|         # NOTE(rtheis): The segment extension is not yet enabled by default. | ||||
|         # Skip the tests if not enabled. | ||||
|         cls.SEGMENT_EXTENSION = cls.conn.network.find_extension('segment') | ||||
|  | ||||
|         # Create a network to hold the segment. | ||||
|         net = cls.conn.network.create_network(name=cls.NETWORK_NAME) | ||||
|         assert isinstance(net, network.Network) | ||||
|         cls.assertIs(cls.NETWORK_NAME, net.name) | ||||
|         cls.NETWORK_ID = net.id | ||||
|  | ||||
|         # Get the segment for the network. | ||||
|         for seg in cls.conn.network.segments(): | ||||
|             assert isinstance(seg, segment.Segment) | ||||
|             if cls.NETWORK_ID == seg.network_id: | ||||
|                 cls.NETWORK_TYPE = seg.network_type | ||||
|                 cls.PHYSICAL_NETWORK = seg.physical_network | ||||
|                 cls.SEGMENTATION_ID = seg.segmentation_id | ||||
|                 cls.SEGMENT_ID = seg.id | ||||
|                 break | ||||
|         if cls.SEGMENT_EXTENSION: | ||||
|             # Get the segment for the network. | ||||
|             for seg in cls.conn.network.segments(): | ||||
|                 assert isinstance(seg, segment.Segment) | ||||
|                 if cls.NETWORK_ID == seg.network_id: | ||||
|                     cls.NETWORK_TYPE = seg.network_type | ||||
|                     cls.PHYSICAL_NETWORK = seg.physical_network | ||||
|                     cls.SEGMENTATION_ID = seg.segmentation_id | ||||
|                     cls.SEGMENT_ID = seg.id | ||||
|                     break | ||||
|  | ||||
|     @classmethod | ||||
|     def tearDownClass(cls): | ||||
| @@ -55,18 +58,57 @@ class TestSegment(base.BaseFunctionalTest): | ||||
|                                               ignore_missing=False) | ||||
|         cls.assertIs(None, sot) | ||||
|  | ||||
|     def test_create_delete(self): | ||||
|         if self.SEGMENT_EXTENSION: | ||||
|             sot = self.conn.network.create_segment( | ||||
|                 description='test description', | ||||
|                 name='test name', | ||||
|                 network_id=self.NETWORK_ID, | ||||
|                 network_type='geneve', | ||||
|                 segmentation_id=2055, | ||||
|             ) | ||||
|             self.assertIsInstance(sot, segment.Segment) | ||||
|             del_sot = self.conn.network.delete_segment(sot.id) | ||||
|             self.assertEqual('test description', sot.description) | ||||
|             self.assertEqual('test name', sot.name) | ||||
|             self.assertEqual(self.NETWORK_ID, sot.network_id) | ||||
|             self.assertEqual('geneve', sot.network_type) | ||||
|             self.assertIsNone(sot.physical_network) | ||||
|             self.assertEqual(2055, sot.segmentation_id) | ||||
|             self.assertIsNone(del_sot) | ||||
|         else: | ||||
|             self.skipTest('Segment extension disabled') | ||||
|  | ||||
|     def test_find(self): | ||||
|         sot = self.conn.network.find_segment(self.SEGMENT_ID) | ||||
|         self.assertEqual(self.SEGMENT_ID, sot.id) | ||||
|         if self.SEGMENT_EXTENSION: | ||||
|             sot = self.conn.network.find_segment(self.SEGMENT_ID) | ||||
|             self.assertEqual(self.SEGMENT_ID, sot.id) | ||||
|         else: | ||||
|             self.skipTest('Segment extension disabled') | ||||
|  | ||||
|     def test_get(self): | ||||
|         sot = self.conn.network.get_segment(self.SEGMENT_ID) | ||||
|         self.assertEqual(self.SEGMENT_ID, sot.id) | ||||
|         self.assertEqual(self.NETWORK_ID, sot.network_id) | ||||
|         self.assertEqual(self.NETWORK_TYPE, sot.network_type) | ||||
|         self.assertEqual(self.PHYSICAL_NETWORK, sot.physical_network) | ||||
|         self.assertEqual(self.SEGMENTATION_ID, sot.segmentation_id) | ||||
|         if self.SEGMENT_EXTENSION: | ||||
|             sot = self.conn.network.get_segment(self.SEGMENT_ID) | ||||
|             self.assertEqual(self.SEGMENT_ID, sot.id) | ||||
|             self.assertIsNone(sot.name) | ||||
|             self.assertEqual(self.NETWORK_ID, sot.network_id) | ||||
|             self.assertEqual(self.NETWORK_TYPE, sot.network_type) | ||||
|             self.assertEqual(self.PHYSICAL_NETWORK, sot.physical_network) | ||||
|             self.assertEqual(self.SEGMENTATION_ID, sot.segmentation_id) | ||||
|         else: | ||||
|             self.skipTest('Segment extension disabled') | ||||
|  | ||||
|     def test_list(self): | ||||
|         ids = [o.id for o in self.conn.network.segments()] | ||||
|         self.assertIn(self.SEGMENT_ID, ids) | ||||
|         if self.SEGMENT_EXTENSION: | ||||
|             ids = [o.id for o in self.conn.network.segments(name=None)] | ||||
|             self.assertIn(self.SEGMENT_ID, ids) | ||||
|         else: | ||||
|             self.skipTest('Segment extension disabled') | ||||
|  | ||||
|     def test_update(self): | ||||
|         if self.SEGMENT_EXTENSION: | ||||
|             sot = self.conn.network.update_segment(self.SEGMENT_ID, | ||||
|                                                    description='update') | ||||
|             self.assertEqual('update', sot.description) | ||||
|         else: | ||||
|             self.skipTest('Segment extension disabled') | ||||
|   | ||||
| @@ -725,6 +725,15 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase): | ||||
|                          security_group_rule.SecurityGroupRule, | ||||
|                          paginated=False) | ||||
|  | ||||
|     def test_segment_create_attrs(self): | ||||
|         self.verify_create(self.proxy.create_segment, segment.Segment) | ||||
|  | ||||
|     def test_segment_delete(self): | ||||
|         self.verify_delete(self.proxy.delete_segment, segment.Segment, False) | ||||
|  | ||||
|     def test_segment_delete_ignore(self): | ||||
|         self.verify_delete(self.proxy.delete_segment, segment.Segment, True) | ||||
|  | ||||
|     def test_segment_find(self): | ||||
|         self.verify_find(self.proxy.find_segment, segment.Segment) | ||||
|  | ||||
| @@ -734,6 +743,9 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase): | ||||
|     def test_segments(self): | ||||
|         self.verify_list(self.proxy.segments, segment.Segment, paginated=False) | ||||
|  | ||||
|     def test_segment_update(self): | ||||
|         self.verify_update(self.proxy.update_segment, segment.Segment) | ||||
|  | ||||
|     def test_subnet_create_attrs(self): | ||||
|         self.verify_create(self.proxy.create_subnet, subnet.Subnet) | ||||
|  | ||||
|   | ||||
| @@ -16,11 +16,13 @@ from openstack.network.v2 import segment | ||||
|  | ||||
| IDENTIFIER = 'IDENTIFIER' | ||||
| EXAMPLE = { | ||||
|     'description': '1', | ||||
|     'id': IDENTIFIER, | ||||
|     'network_id': '1', | ||||
|     'network_type': 'vxlan', | ||||
|     'name': '2', | ||||
|     'network_id': '3', | ||||
|     'network_type': 'geneve', | ||||
|     'physical_network': None, | ||||
|     'segmentation_id': 2, | ||||
|     'segmentation_id': 4, | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -32,15 +34,17 @@ class TestSegment(testtools.TestCase): | ||||
|         self.assertEqual('segments', sot.resources_key) | ||||
|         self.assertEqual('/segments', sot.base_path) | ||||
|         self.assertEqual('network', sot.service.service_type) | ||||
|         self.assertFalse(sot.allow_create) | ||||
|         self.assertTrue(sot.allow_create) | ||||
|         self.assertTrue(sot.allow_retrieve) | ||||
|         self.assertFalse(sot.allow_update) | ||||
|         self.assertFalse(sot.allow_delete) | ||||
|         self.assertTrue(sot.allow_update) | ||||
|         self.assertTrue(sot.allow_delete) | ||||
|         self.assertTrue(sot.allow_list) | ||||
|  | ||||
|     def test_make_it(self): | ||||
|         sot = segment.Segment(EXAMPLE) | ||||
|         self.assertEqual(EXAMPLE['description'], sot.description) | ||||
|         self.assertEqual(EXAMPLE['id'], sot.id) | ||||
|         self.assertEqual(EXAMPLE['name'], sot.name) | ||||
|         self.assertEqual(EXAMPLE['network_id'], sot.network_id) | ||||
|         self.assertEqual(EXAMPLE['network_type'], sot.network_type) | ||||
|         self.assertEqual(EXAMPLE['physical_network'], sot.physical_network) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jenkins
					Jenkins