summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKailun Qin <kailun.qin@intel.com>2019-02-27 23:02:52 +0800
committerDean Troyer <dtroyer@gmail.com>2019-03-07 19:39:17 +0000
commitd52920b3878479f7dd549cba1679870b4f00ee33 (patch)
treebdcd9dc1e1a17f93136923928a8eabef52ee853f
parent0a187905c01f6bc2b9855081ac0042f00715dedf (diff)
Add network segment range command object
Add network segment range command object in support of network segment range management. This patch set includes documentation, unit tests and functional tests (currently skipped unit network segment range enabled in Neutron by default) for the following new commands: - "os network segment range create" - "os network segment range delete" - "os network segment range list" - "os network segment range set" - "os network segment range show" Co-authored-by: Allain Legacy <Allain.legacy@windriver.com> [depends on removed by dtroyer as those are all +W and trying to pass the gate, OSC has it's freeze dealine looming] Depends: https://review.openstack.org/624708 Depends: https://review.openstack.org/624709 Depends: https://review.openstack.org/638386 Partially-implements: blueprint network-segment-range-management Change-Id: I335692f2db5be07c1c164f09b13f1abb80b7ba33
Notes
Notes (review): Code-Review+2: Dean Troyer <dtroyer@gmail.com> Workflow+1: Dean Troyer <dtroyer@gmail.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Fri, 08 Mar 2019 02:27:37 +0000 Reviewed-on: https://review.openstack.org/625544 Project: openstack/python-openstackclient Branch: refs/heads/master
-rw-r--r--.zuul.yaml1
-rw-r--r--doc/source/cli/command-objects/network_segment_range.rst168
-rw-r--r--doc/source/cli/commands.rst1
-rw-r--r--openstackclient/network/v2/network_segment_range.py458
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_segment_range.py145
-rw-r--r--openstackclient/tests/unit/network/v2/fakes.py60
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_segment_range.py552
-rw-r--r--releasenotes/notes/bp-network-segment-range-management-0abf03fe03eea149.yaml6
-rw-r--r--setup.cfg6
9 files changed, 1397 insertions, 0 deletions
diff --git a/.zuul.yaml b/.zuul.yaml
index 3ce2f6f..9d3845c 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -113,6 +113,7 @@
113 # NOTE(amotoki): Some neutron features are enabled by devstack plugin 113 # NOTE(amotoki): Some neutron features are enabled by devstack plugin
114 neutron: https://git.openstack.org/openstack/neutron 114 neutron: https://git.openstack.org/openstack/neutron
115 devstack_services: 115 devstack_services:
116 neutron-network-segment-range: true
116 neutron-segments: true 117 neutron-segments: true
117 q-metering: true 118 q-metering: true
118 q-qos: true 119 q-qos: true
diff --git a/doc/source/cli/command-objects/network_segment_range.rst b/doc/source/cli/command-objects/network_segment_range.rst
new file mode 100644
index 0000000..71155d2
--- /dev/null
+++ b/doc/source/cli/command-objects/network_segment_range.rst
@@ -0,0 +1,168 @@
1=====================
2network segment range
3=====================
4
5A **network segment range** is a resource for tenant network segment
6allocation.
7A network segment range exposes the segment range management to be administered
8via the Neutron API. In addition, it introduces the ability for the
9administrator to control the segment ranges globally or on a per-tenant basis.
10
11Network v2
12
13network segment range create
14----------------------------
15
16Create new network segment range
17
18.. program:: network segment range create
19.. code:: bash
20
21 openstack network segment range create
22 (--private | --shared)
23 [--project <project> [--project-domain <project-domain>]]
24 --network-type <network-type>
25 [--physical-network <physical-network-name>]
26 --minimum <minimum-segmentation-id>
27 --maximum <maximum-segmentation-id>
28 <name>
29
30.. option:: --private
31
32 Network segment range is assigned specifically to the project
33
34.. option:: --shared
35
36 Network segment range is shared with other projects
37
38.. option:: --project <project>
39
40 Network segment range owner (name or ID). Optional when the segment
41 range is shared
42
43.. option:: --project-domain <project-domain>
44
45 Domain the project belongs to (name or ID).
46 This can be used in case collisions between project names exist.
47
48.. option:: --physical-network <physical-network-name>
49
50 Physical network name of this network segment range
51
52.. option:: --network-type <network-type>
53
54 Network type of this network segment range
55 (geneve, gre, vlan or vxlan)
56
57.. option:: --minimum <minimum-segmentation-id>
58
59 Minimum segment identifier for this network segment range which is based
60 on the network type, VLAN ID for vlan network type and tunnel ID for
61 geneve, gre and vxlan network types
62
63.. option:: --maximum <maximum-segmentation-id>
64
65 Maximum segment identifier for this network segment range which is based
66 on the network type, VLAN ID for vlan network type and tunnel ID for
67 geneve, gre and vxlan network types
68
69.. _network_segment_range_create-name:
70.. describe:: <name>
71
72 Name of new network segment range
73
74network segment range delete
75----------------------------
76
77Delete network segment range(s)
78
79.. program:: network segment range delete
80.. code:: bash
81
82 openstack network segment range delete
83 <network-segment-range> [<network-segment-range> ...]
84
85.. _network_segment_range_delete-network-segment-range:
86.. describe:: <network-segment-range>
87
88 Network segment range (s) to delete (name or ID)
89
90network segment range list
91--------------------------
92
93List network segment ranges
94
95.. program:: network segment range list
96.. code:: bash
97
98 openstack network segment range list
99 [--long]
100 [--used | --unused]
101 [--available | --unavailable]
102
103.. option:: --long
104
105 List additional fields in output
106
107.. option:: --used
108
109 List network segment ranges that have segments in use
110
111.. option:: --unused
112
113 List network segment ranges that do not have segments not in use
114
115.. option:: --available
116
117 List network segment ranges that have available segments
118
119.. option:: --unavailable
120
121 List network segment ranges without available segments
122
123network segment range set
124-------------------------
125
126Set network segment range properties
127
128.. program:: network segment range set
129.. code:: bash
130
131 openstack network segment range set
132 [--name <name>]
133 [--minimum <minimum-segmentation-id>]
134 [--maximum <maximum-segmentation-id>]
135 <network-segment-range>
136
137.. option:: --name <name>
138
139 Set network segment range name
140
141.. option:: --minimum <minimum-segmentation-id>
142
143 Set network segment range minimum segment identifier
144
145.. option:: --maximum <maximum-segmentation-id>
146
147 Set network segment range maximum segment identifier
148
149.. _network_segment_range_set-network-segment-range:
150.. describe:: <network-segment-range>
151
152 Network segment range to modify (name or ID)
153
154network segment range show
155--------------------------
156
157Display network segment range details
158
159.. program:: network segment range show
160.. code:: bash
161
162 openstack network segment range show
163 <network-segment-range>
164
165.. _network_segment_range_show-network-segment-range:
166.. describe:: <network-segment-range>
167
168 Network segment range to display (name or ID)
diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst
index cdd5e63..e302fda 100644
--- a/doc/source/cli/commands.rst
+++ b/doc/source/cli/commands.rst
@@ -125,6 +125,7 @@ referring to both Compute and Volume quotas.
125* ``network qos policy``: (**Network**) - a QoS policy for network resources 125* ``network qos policy``: (**Network**) - a QoS policy for network resources
126* ``network qos rule type``: (**Network**) - list of QoS available rule types 126* ``network qos rule type``: (**Network**) - list of QoS available rule types
127* ``network segment``: (**Network**) - a segment of a virtual network 127* ``network segment``: (**Network**) - a segment of a virtual network
128* ``network segment range``: (**Network**) - a segment range for tenant network segment allocation
128* ``network service provider``: (**Network**) - a driver providing a network service 129* ``network service provider``: (**Network**) - a driver providing a network service
129* ``object``: (**Object Storage**) a single file in the Object Storage 130* ``object``: (**Object Storage**) a single file in the Object Storage
130* ``object store account``: (**Object Storage**) owns a group of Object Storage resources 131* ``object store account``: (**Object Storage**) owns a group of Object Storage resources
diff --git a/openstackclient/network/v2/network_segment_range.py b/openstackclient/network/v2/network_segment_range.py
new file mode 100644
index 0000000..f5c8ccb
--- /dev/null
+++ b/openstackclient/network/v2/network_segment_range.py
@@ -0,0 +1,458 @@
1# Copyright (c) 2019, Intel Corporation.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16
17"""Network segment action implementations"""
18
19import itertools
20import logging
21
22from osc_lib.command import command
23from osc_lib import exceptions
24from osc_lib import utils
25import six
26
27from openstackclient.i18n import _
28from openstackclient.identity import common as identity_common
29from openstackclient.network import sdk_utils
30
31
32LOG = logging.getLogger(__name__)
33
34
35def _get_columns(item):
36 return sdk_utils.get_osc_show_columns_for_sdk_resource(item, {})
37
38
39def _get_ranges(item):
40 item = [int(i) if isinstance(i, six.string_types) else i for i in item]
41 for a, b in itertools.groupby(enumerate(item), lambda xy: xy[1] - xy[0]):
42 b = list(b)
43 yield "%s-%s" % (b[0][1], b[-1][1]) if b[0][1] != b[-1][1] else \
44 str(b[0][1])
45
46
47def _hack_tuple_value_update_by_index(tup, index, value):
48 lot = list(tup)
49 lot[index] = value
50 return tuple(lot)
51
52
53def _is_prop_empty(columns, props, prop_name):
54 return True if not props[columns.index(prop_name)] else False
55
56
57def _exchange_dict_keys_with_values(orig_dict):
58 updated_dict = dict()
59 for k, v in six.iteritems(orig_dict):
60 k = [k]
61 if not updated_dict.get(v):
62 updated_dict[v] = k
63 else:
64 updated_dict[v].extend(k)
65 return updated_dict
66
67
68def _update_available_from_props(columns, props):
69 index_available = columns.index('available')
70 props = _hack_tuple_value_update_by_index(
71 props, index_available, list(_get_ranges(props[index_available])))
72 return props
73
74
75def _update_used_from_props(columns, props):
76 index_used = columns.index('used')
77 updated_used = _exchange_dict_keys_with_values(props[index_used])
78 for k, v in six.iteritems(updated_used):
79 updated_used[k] = list(_get_ranges(v))
80 props = _hack_tuple_value_update_by_index(
81 props, index_used, updated_used)
82 return props
83
84
85def _update_additional_fields_from_props(columns, props):
86 props = _update_available_from_props(columns, props)
87 props = _update_used_from_props(columns, props)
88 return props
89
90
91class CreateNetworkSegmentRange(command.ShowOne):
92 _description = _("Create new network segment range")
93
94 def get_parser(self, prog_name):
95 parser = super(CreateNetworkSegmentRange, self).get_parser(prog_name)
96 shared_group = parser.add_mutually_exclusive_group()
97 shared_group.add_argument(
98 "--private",
99 dest="private",
100 action="store_true",
101 help=_('Network segment range is assigned specifically to the '
102 'project'),
103 )
104 shared_group.add_argument(
105 "--shared",
106 dest="shared",
107 action="store_true",
108 help=_('Network segment range is shared with other projects'),
109 )
110 parser.add_argument(
111 'name',
112 metavar='<name>',
113 help=_('Name of new network segment range')
114 )
115 parser.add_argument(
116 '--project',
117 metavar='<project>',
118 help=_('Network segment range owner (name or ID). Optional when '
119 'the segment range is shared'),
120 )
121 identity_common.add_project_domain_option_to_parser(parser)
122 parser.add_argument(
123 '--network-type',
124 metavar='<network-type>',
125 choices=['geneve', 'gre', 'vlan', 'vxlan'],
126 required=True,
127 help=_('Network type of this network segment range '
128 '(geneve, gre, vlan or vxlan)'),
129 )
130 parser.add_argument(
131 '--physical-network',
132 metavar='<physical-network-name>',
133 help=_('Physical network name of this network segment range'),
134 )
135 parser.add_argument(
136 '--minimum',
137 metavar='<minimum-segmentation-id>',
138 type=int,
139 required=True,
140 help=_('Minimum segment identifier for this network segment '
141 'range which is based on the network type, VLAN ID for '
142 'vlan network type and tunnel ID for geneve, gre and vxlan '
143 'network types'),
144 )
145 parser.add_argument(
146 '--maximum',
147 metavar='<maximum-segmentation-id>',
148 type=int,
149 required=True,
150 help=_('Maximum segment identifier for this network segment '
151 'range which is based on the network type, VLAN ID for '
152 'vlan network type and tunnel ID for geneve, gre and vxlan '
153 'network types'),
154 )
155
156 return parser
157
158 def take_action(self, parsed_args):
159 network_client = self.app.client_manager.network
160 try:
161 # Verify that the extension exists.
162 network_client.find_extension('network-segment-range',
163 ignore_missing=False)
164 except Exception as e:
165 msg = (_('Network segment range create not supported by '
166 'Network API: %(e)s') % {'e': e})
167 raise exceptions.CommandError(msg)
168
169 identity_client = self.app.client_manager.identity
170
171 if parsed_args.shared and parsed_args.project:
172 msg = _("--project is only allowed with --private")
173 raise exceptions.CommandError(msg)
174
175 if (parsed_args.network_type.lower() != 'vlan' and
176 parsed_args.physical_network):
177 msg = _("--physical-network is only allowed with --network-type "
178 "vlan")
179 raise exceptions.CommandError(msg)
180
181 attrs = {}
182 if parsed_args.shared or parsed_args.private:
183 attrs['shared'] = parsed_args.shared
184 else:
185 # default to be ``shared`` if not specified
186 attrs['shared'] = True
187 attrs['network_type'] = parsed_args.network_type
188 attrs['minimum'] = parsed_args.minimum
189 attrs['maximum'] = parsed_args.maximum
190 if parsed_args.name:
191 attrs['name'] = parsed_args.name
192
193 if parsed_args.project:
194 project_id = identity_common.find_project(
195 identity_client,
196 parsed_args.project,
197 parsed_args.project_domain,
198 ).id
199 if project_id:
200 attrs['project_id'] = project_id
201 else:
202 msg = (_("Failed to create the network segment range for "
203 "project %(project_id)s") % parsed_args.project_id)
204 raise exceptions.CommandError(msg)
205 elif not parsed_args.shared:
206 # default to the current project if no project specified and shared
207 # is not specified.
208 # Get the project id from the current auth.
209 attrs['project_id'] = self.app.client_manager.auth_ref.project_id
210 else:
211 attrs['project_id'] = None
212
213 if parsed_args.physical_network:
214 attrs['physical_network'] = parsed_args.physical_network
215 obj = network_client.create_network_segment_range(**attrs)
216 display_columns, columns = _get_columns(obj)
217 data = utils.get_item_properties(obj, columns)
218 data = _update_additional_fields_from_props(columns, props=data)
219 return (display_columns, data)
220
221
222class DeleteNetworkSegmentRange(command.Command):
223 _description = _("Delete network segment range(s)")
224
225 def get_parser(self, prog_name):
226 parser = super(DeleteNetworkSegmentRange, self).get_parser(prog_name)
227 parser.add_argument(
228 'network_segment_range',
229 metavar='<network-segment-range>',
230 nargs='+',
231 help=_('Network segment range(s) to delete (name or ID)'),
232 )
233 return parser
234
235 def take_action(self, parsed_args):
236 network_client = self.app.client_manager.network
237 try:
238 # Verify that the extension exists.
239 network_client.find_extension('network-segment-range',
240 ignore_missing=False)
241 except Exception as e:
242 msg = (_('Network segment range delete not supported by '
243 'Network API: %(e)s') % {'e': e})
244 raise exceptions.CommandError(msg)
245
246 result = 0
247 for network_segment_range in parsed_args.network_segment_range:
248 try:
249 obj = network_client.find_network_segment_range(
250 network_segment_range, ignore_missing=False)
251 network_client.delete_network_segment_range(obj)
252 except Exception as e:
253 result += 1
254 LOG.error(_("Failed to delete network segment range with "
255 "ID '%(network_segment_range)s': %(e)s"),
256 {'network_segment_range': network_segment_range,
257 'e': e})
258
259 if result > 0:
260 total = len(parsed_args.network_segment_range)
261 msg = (_("%(result)s of %(total)s network segment ranges failed "
262 "to delete.") % {'result': result, 'total': total})
263 raise exceptions.CommandError(msg)
264
265
266class ListNetworkSegmentRange(command.Lister):
267 _description = _("List network segment ranges")
268
269 def get_parser(self, prog_name):
270 parser = super(ListNetworkSegmentRange, self).get_parser(prog_name)
271 parser.add_argument(
272 '--long',
273 action='store_true',
274 help=_('List additional fields in output'),
275 )
276 used_group = parser.add_mutually_exclusive_group()
277 used_group.add_argument(
278 '--used',
279 action='store_true',
280 help=_('List network segment ranges that have segments in use'),
281 )
282 used_group.add_argument(
283 '--unused',
284 action='store_true',
285 help=_('List network segment ranges that have segments '
286 'not in use'),
287 )
288 available_group = parser.add_mutually_exclusive_group()
289 available_group.add_argument(
290 '--available',
291 action='store_true',
292 help=_('List network segment ranges that have available segments'),
293 )
294 available_group.add_argument(
295 '--unavailable',
296 action='store_true',
297 help=_('List network segment ranges without available segments'),
298 )
299 return parser
300
301 def take_action(self, parsed_args):
302 network_client = self.app.client_manager.network
303 try:
304 # Verify that the extension exists.
305 network_client.find_extension('network-segment-range',
306 ignore_missing=False)
307 except Exception as e:
308 msg = (_('Network segment ranges list not supported by '
309 'Network API: %(e)s') % {'e': e})
310 raise exceptions.CommandError(msg)
311
312 filters = {}
313 data = network_client.network_segment_ranges(**filters)
314
315 headers = (
316 'ID',
317 'Name',
318 'Default',
319 'Shared',
320 'Project ID',
321 'Network Type',
322 'Physical Network',
323 'Minimum ID',
324 'Maximum ID'
325 )
326 columns = (
327 'id',
328 'name',
329 'default',
330 'shared',
331 'project_id',
332 'network_type',
333 'physical_network',
334 'minimum',
335 'maximum',
336 )
337 if parsed_args.available or parsed_args.unavailable or \
338 parsed_args.used or parsed_args.unused:
339 # If one of `--available`, `--unavailable`, `--used`,
340 # `--unused` is specified, we assume that additional fields
341 # should be listed in output.
342 parsed_args.long = True
343 if parsed_args.long:
344 headers = headers + (
345 'Used',
346 'Available',
347 )
348 columns = columns + (
349 'used',
350 'available',
351 )
352
353 display_props = tuple()
354 for s in data:
355 props = utils.get_item_properties(s, columns)
356 if parsed_args.available and \
357 _is_prop_empty(columns, props, 'available') or \
358 parsed_args.unavailable and \
359 not _is_prop_empty(columns, props, 'available') or \
360 parsed_args.used and _is_prop_empty(columns, props, 'used') or \
361 parsed_args.unused and \
362 not _is_prop_empty(columns, props, 'used'):
363 continue
364 if parsed_args.long:
365 props = _update_additional_fields_from_props(columns, props)
366 display_props += (props,)
367
368 return headers, display_props
369
370
371class SetNetworkSegmentRange(command.Command):
372 _description = _("Set network segment range properties")
373
374 def get_parser(self, prog_name):
375 parser = super(SetNetworkSegmentRange, self).get_parser(prog_name)
376 parser.add_argument(
377 'network_segment_range',
378 metavar='<network-segment-range>',
379 help=_('Network segment range to modify (name or ID)'),
380 )
381 parser.add_argument(
382 '--name',
383 metavar='<name>',
384 help=_('Set network segment name'),
385 )
386 parser.add_argument(
387 '--minimum',
388 metavar='<minimum-segmentation-id>',
389 type=int,
390 help=_('Set network segment range minimum segment identifier'),
391 )
392 parser.add_argument(
393 '--maximum',
394 metavar='<maximum-segmentation-id>',
395 type=int,
396 help=_('Set network segment range maximum segment identifier'),
397 )
398 return parser
399
400 def take_action(self, parsed_args):
401 network_client = self.app.client_manager.network
402 try:
403 # Verify that the extension exists.
404 network_client.find_extension('network-segment-range',
405 ignore_missing=False)
406 except Exception as e:
407 msg = (_('Network segment range set not supported by '
408 'Network API: %(e)s') % {'e': e})
409 raise exceptions.CommandError(msg)
410
411 if (parsed_args.minimum and not parsed_args.maximum) or \
412 (parsed_args.maximum and not parsed_args.minimum):
413 msg = _("--minimum and --maximum are both required")
414 raise exceptions.CommandError(msg)
415
416 obj = network_client.find_network_segment_range(
417 parsed_args.network_segment_range, ignore_missing=False)
418 attrs = {}
419 if parsed_args.name:
420 attrs['name'] = parsed_args.name
421 if parsed_args.minimum:
422 attrs['minimum'] = parsed_args.minimum
423 if parsed_args.maximum:
424 attrs['maximum'] = parsed_args.maximum
425 network_client.update_network_segment_range(obj, **attrs)
426
427
428class ShowNetworkSegmentRange(command.ShowOne):
429 _description = _("Display network segment range details")
430
431 def get_parser(self, prog_name):
432 parser = super(ShowNetworkSegmentRange, self).get_parser(prog_name)
433 parser.add_argument(
434 'network_segment_range',
435 metavar='<network-segment-range>',
436 help=_('Network segment range to display (name or ID)'),
437 )
438 return parser
439
440 def take_action(self, parsed_args):
441 network_client = self.app.client_manager.network
442 try:
443 # Verify that the extension exists.
444 network_client.find_extension('network-segment-range',
445 ignore_missing=False)
446 except Exception as e:
447 msg = (_('Network segment range show not supported by '
448 'Network API: %(e)s') % {'e': e})
449 raise exceptions.CommandError(msg)
450
451 obj = network_client.find_network_segment_range(
452 parsed_args.network_segment_range,
453 ignore_missing=False
454 )
455 display_columns, columns = _get_columns(obj)
456 data = utils.get_item_properties(obj, columns)
457 data = _update_additional_fields_from_props(columns, props=data)
458 return (display_columns, data)
diff --git a/openstackclient/tests/functional/network/v2/test_network_segment_range.py b/openstackclient/tests/functional/network/v2/test_network_segment_range.py
new file mode 100644
index 0000000..95402dc
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_network_segment_range.py
@@ -0,0 +1,145 @@
1# Copyright (c) 2019, Intel Corporation.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16
17import json
18import uuid
19
20from openstackclient.tests.functional.network.v2 import common
21
22
23class NetworkSegmentRangeTests(common.NetworkTests):
24 """Functional tests for network segment range"""
25
26 def setUp(self):
27 super(NetworkSegmentRangeTests, self).setUp()
28 # Nothing in this class works with Nova Network
29 if not self.haz_network:
30 self.skipTest("No Network service present")
31 self.PROJECT_NAME = uuid.uuid4().hex
32
33 def test_network_segment_range_create_delete(self):
34 # Make a project
35 project_id = json.loads(self.openstack(
36 'project create -f json ' + self.PROJECT_NAME))['id']
37 name = uuid.uuid4().hex
38 json_output = json.loads(self.openstack(
39 ' network segment range create -f json ' +
40 '--private ' +
41 "--project " + self.PROJECT_NAME + " " +
42 '--network-type vxlan ' +
43 '--minimum 2018 ' +
44 '--maximum 2055 ' +
45 name
46 ))
47 self.assertEqual(
48 name,
49 json_output["name"],
50 )
51 self.assertEqual(
52 project_id,
53 json_output["project_id"],
54 )
55
56 raw_output = self.openstack(
57 'network segment range delete ' + name,
58 )
59 self.assertOutput('', raw_output)
60 raw_output_project = self.openstack(
61 'project delete ' + self.PROJECT_NAME)
62 self.assertEqual('', raw_output_project)
63
64 def test_network_segment_range_list(self):
65 name = uuid.uuid4().hex
66 json_output = json.loads(self.openstack(
67 ' network segment range create -f json ' +
68 '--shared ' +
69 '--network-type geneve ' +
70 '--minimum 2018 ' +
71 '--maximum 2055 ' +
72 name
73 ))
74 network_segment_range_id = json_output.get('id')
75 network_segment_range_name = json_output.get('name')
76 self.addCleanup(
77 self.openstack,
78 'network segment range delete ' + network_segment_range_id
79 )
80 self.assertEqual(
81 name,
82 json_output["name"],
83 )
84
85 json_output = json.loads(self.openstack(
86 'network segment list -f json'
87 ))
88 item_map = {
89 item.get('ID'): item.get('Name') for item in json_output
90 }
91 self.assertIn(network_segment_range_id, item_map.keys())
92 self.assertIn(network_segment_range_name, item_map.values())
93
94 def test_network_segment_range_set_show(self):
95 project_id = json.loads(self.openstack(
96 'project create -f json ' + self.PROJECT_NAME))['id']
97 name = uuid.uuid4().hex
98 json_output = json.loads(self.openstack(
99 ' network segment range create -f json ' +
100 '--private ' +
101 "--project " + self.PROJECT_NAME + " " +
102 '--network-type geneve ' +
103 '--minimum 2018 ' +
104 '--maximum 2055 ' +
105 name
106 ))
107 self.addCleanup(
108 self.openstack,
109 'network segment range delete ' + name
110 )
111 self.assertEqual(
112 name,
113 json_output["name"],
114 )
115 self.assertEqual(
116 project_id,
117 json_output["project_id"],
118 )
119
120 new_minimum = '2010'
121 new_maximum = '2060'
122 cmd_output = self.openstack(
123 'network segment range set ' +
124 '--minimum ' + new_minimum + ' ' +
125 '--maximum ' + new_maximum + ' ' +
126 name
127 )
128 self.assertOutput('', cmd_output)
129
130 json_output = json.loads(self.openstack(
131 'network segment range show -f json ' +
132 name
133 ))
134 self.assertEqual(
135 new_minimum,
136 json_output["minimum"],
137 )
138 self.assertEqual(
139 new_maximum,
140 json_output["maximum"],
141 )
142
143 raw_output_project = self.openstack(
144 'project delete ' + self.PROJECT_NAME)
145 self.assertEqual('', raw_output_project)
diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py
index 28e92d1..38c865d 100644
--- a/openstackclient/tests/unit/network/v2/fakes.py
+++ b/openstackclient/tests/unit/network/v2/fakes.py
@@ -538,6 +538,66 @@ class FakeNetworkSegment(object):
538 return network_segments 538 return network_segments
539 539
540 540
541class FakeNetworkSegmentRange(object):
542 """Fake one or more network segment ranges."""
543
544 @staticmethod
545 def create_one_network_segment_range(attrs=None):
546 """Create a fake network segment range.
547
548 :param Dictionary attrs:
549 A dictionary with all attributes
550 :return:
551 A FakeResource object faking the network segment range
552 """
553 attrs = attrs or {}
554
555 # Set default attributes.
556 fake_uuid = uuid.uuid4().hex
557 network_segment_range_attrs = {
558 'id': 'network-segment-range-id-' + fake_uuid,
559 'name': 'network-segment-name-' + fake_uuid,
560 'default': False,
561 'shared': False,
562 'project_id': 'project-id-' + fake_uuid,
563 'network_type': 'vlan',
564 'physical_network': 'physical-network-name-' + fake_uuid,
565 'minimum': 100,
566 'maximum': 106,
567 'used': {104: '3312e4ba67864b2eb53f3f41432f8efc',
568 106: '3312e4ba67864b2eb53f3f41432f8efc'},
569 'available': [100, 101, 102, 103, 105],
570 }
571
572 # Overwrite default attributes.
573 network_segment_range_attrs.update(attrs)
574
575 network_segment_range = fakes.FakeResource(
576 info=copy.deepcopy(network_segment_range_attrs),
577 loaded=True
578 )
579
580 return network_segment_range
581
582 @staticmethod
583 def create_network_segment_ranges(attrs=None, count=2):
584 """Create multiple fake network segment ranges.
585
586 :param Dictionary attrs:
587 A dictionary with all attributes
588 :param int count:
589 The number of network segment ranges to fake
590 :return:
591 A list of FakeResource objects faking the network segment ranges
592 """
593 network_segment_ranges = []
594 for i in range(0, count):
595 network_segment_ranges.append(
596 FakeNetworkSegmentRange.create_one_network_segment_range(attrs)
597 )
598 return network_segment_ranges
599
600
541class FakePort(object): 601class FakePort(object):
542 """Fake one or more ports.""" 602 """Fake one or more ports."""
543 603
diff --git a/openstackclient/tests/unit/network/v2/test_network_segment_range.py b/openstackclient/tests/unit/network/v2/test_network_segment_range.py
new file mode 100644
index 0000000..6387a28
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_network_segment_range.py
@@ -0,0 +1,552 @@
1# Copyright (c) 2019, Intel Corporation.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16
17import mock
18from mock import call
19
20from osc_lib import exceptions
21
22from openstackclient.network.v2 import network_segment_range
23from openstackclient.tests.unit.network.v2 import fakes as network_fakes
24from openstackclient.tests.unit import utils as tests_utils
25
26
27class TestNetworkSegmentRange(network_fakes.TestNetworkV2):
28
29 def setUp(self):
30 super(TestNetworkSegmentRange, self).setUp()
31
32 # Get a shortcut to the network client
33 self.network = self.app.client_manager.network
34
35
36class TestCreateNetworkSegmentRange(TestNetworkSegmentRange):
37
38 # The network segment range to create.
39 _network_segment_range = network_fakes.FakeNetworkSegmentRange.\
40 create_one_network_segment_range()
41
42 columns = (
43 'available',
44 'default',
45 'id',
46 'maximum',
47 'minimum',
48 'name',
49 'network_type',
50 'physical_network',
51 'project_id',
52 'shared',
53 'used',
54 )
55
56 data = (
57 ['100-103', '105'],
58 _network_segment_range.default,
59 _network_segment_range.id,
60 _network_segment_range.maximum,
61 _network_segment_range.minimum,
62 _network_segment_range.name,
63 _network_segment_range.network_type,
64 _network_segment_range.physical_network,
65 _network_segment_range.project_id,
66 _network_segment_range.shared,
67 {'3312e4ba67864b2eb53f3f41432f8efc': ['104', '106']},
68 )
69
70 def setUp(self):
71 super(TestCreateNetworkSegmentRange, self).setUp()
72
73 self.network.find_extension = mock.Mock()
74 self.network.create_network_segment_range = mock.Mock(
75 return_value=self._network_segment_range
76 )
77
78 # Get the command object to test
79 self.cmd = network_segment_range.CreateNetworkSegmentRange(
80 self.app,
81 self.namespace
82 )
83
84 def test_create_no_options(self):
85 # Missing required args should bail here
86 self.assertRaises(tests_utils.ParserException, self.check_parser,
87 self.cmd, [], [])
88
89 def test_create_invalid_network_type(self):
90 arglist = [
91 '--private',
92 '--project', self._network_segment_range.project_id,
93 '--network-type', 'foo',
94 '--minimum', str(self._network_segment_range.minimum),
95 '--maximum', str(self._network_segment_range.maximum),
96 self._network_segment_range.name,
97 ]
98 self.assertRaises(tests_utils.ParserException, self.check_parser,
99 self.cmd, arglist, [])
100
101 def test_create_shared_with_project_id(self):
102 arglist = [
103 '--shared',
104 '--project', self._network_segment_range.project_id,
105 '--network-type', 'vxlan',
106 '--minimum', str(self._network_segment_range.minimum),
107 '--maximum', str(self._network_segment_range.maximum),
108 self._network_segment_range.name,
109 ]
110 verifylist = [
111 ('shared', True),
112 ('project', self._network_segment_range.project_id),
113 ('network_type', 'vxlan'),
114 ('minimum', self._network_segment_range.minimum),
115 ('maximum', self._network_segment_range.maximum),
116 ('name', self._network_segment_range.name),
117 ]
118
119 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
120 self.assertRaises(exceptions.CommandError,
121 self.cmd.take_action,
122 parsed_args)
123
124 def test_create_tunnel_with_physical_network(self):
125 arglist = [
126 '--shared',
127 '--network-type', 'vxlan',
128 '--physical-network', self._network_segment_range.physical_network,
129 '--minimum', str(self._network_segment_range.minimum),
130 '--maximum', str(self._network_segment_range.maximum),
131 self._network_segment_range.name,
132 ]
133 verifylist = [
134 ('shared', True),
135 ('network_type', 'vxlan'),
136 ('physical_network', self._network_segment_range.physical_network),
137 ('minimum', self._network_segment_range.minimum),
138 ('maximum', self._network_segment_range.maximum),
139 ('name', self._network_segment_range.name),
140 ]
141
142 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
143 self.assertRaises(exceptions.CommandError,
144 self.cmd.take_action,
145 parsed_args)
146
147 def test_create_minimum_options(self):
148 arglist = [
149 '--private',
150 '--project', self._network_segment_range.project_id,
151 '--network-type', self._network_segment_range.network_type,
152 '--minimum', str(self._network_segment_range.minimum),
153 '--maximum', str(self._network_segment_range.maximum),
154 self._network_segment_range.name,
155 ]
156 verifylist = [
157 ('shared', self._network_segment_range.shared),
158 ('project', self._network_segment_range.project_id),
159 ('network_type', self._network_segment_range.network_type),
160 ('minimum', self._network_segment_range.minimum),
161 ('maximum', self._network_segment_range.maximum),
162 ('name', self._network_segment_range.name),
163 ]
164
165 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
166 columns, data = self.cmd.take_action(parsed_args)
167
168 self.network.create_network_segment_range.assert_called_once_with(**{
169 'shared': self._network_segment_range.shared,
170 'project_id': mock.ANY,
171 'network_type': self._network_segment_range.network_type,
172 'minimum': self._network_segment_range.minimum,
173 'maximum': self._network_segment_range.maximum,
174 'name': self._network_segment_range.name,
175 })
176
177 self.assertEqual(self.columns, columns)
178 self.assertEqual(self.data, data)
179
180 def test_create_all_options(self):
181 arglist = [
182 '--private',
183 '--project', self._network_segment_range.project_id,
184 '--network-type', self._network_segment_range.network_type,
185 '--physical-network', self._network_segment_range.physical_network,
186 '--minimum', str(self._network_segment_range.minimum),
187 '--maximum', str(self._network_segment_range.maximum),
188 self._network_segment_range.name,
189 ]
190 verifylist = [
191 ('shared', self._network_segment_range.shared),
192 ('project', self._network_segment_range.project_id),
193 ('network_type', self._network_segment_range.network_type),
194 ('physical_network', self._network_segment_range.physical_network),
195 ('minimum', self._network_segment_range.minimum),
196 ('maximum', self._network_segment_range.maximum),
197 ('name', self._network_segment_range.name),
198 ]
199
200 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
201 columns, data = self.cmd.take_action(parsed_args)
202
203 self.network.create_network_segment_range.assert_called_once_with(**{
204 'shared': self._network_segment_range.shared,
205 'project_id': mock.ANY,
206 'network_type': self._network_segment_range.network_type,
207 'physical_network': self._network_segment_range.physical_network,
208 'minimum': self._network_segment_range.minimum,
209 'maximum': self._network_segment_range.maximum,
210 'name': self._network_segment_range.name,
211 })
212
213 self.assertEqual(self.columns, columns)
214 self.assertEqual(self.data, data)
215
216
217class TestDeleteNetworkSegmentRange(TestNetworkSegmentRange):
218
219 # The network segment ranges to delete.
220 _network_segment_ranges = \
221 network_fakes.FakeNetworkSegmentRange.create_network_segment_ranges()
222
223 def setUp(self):
224 super(TestDeleteNetworkSegmentRange, self).setUp()
225
226 self.network.find_extension = mock.Mock()
227 self.network.delete_network_segment_range = mock.Mock(
228 return_value=None)
229 self.network.find_network_segment_range = mock.Mock(
230 side_effect=self._network_segment_ranges
231 )
232
233 # Get the command object to test
234 self.cmd = network_segment_range.DeleteNetworkSegmentRange(
235 self.app,
236 self.namespace
237 )
238
239 def test_delete(self):
240 arglist = [
241 self._network_segment_ranges[0].id,
242 ]
243 verifylist = [
244 ('network_segment_range', [self._network_segment_ranges[0].id]),
245 ]
246 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
247
248 result = self.cmd.take_action(parsed_args)
249
250 self.network.delete_network_segment_range.assert_called_once_with(
251 self._network_segment_ranges[0]
252 )
253 self.assertIsNone(result)
254
255 def test_delete_multiple(self):
256 arglist = []
257 for _network_segment_range in self._network_segment_ranges:
258 arglist.append(_network_segment_range.id)
259 verifylist = [
260 ('network_segment_range', arglist),
261 ]
262 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
263
264 result = self.cmd.take_action(parsed_args)
265
266 calls = []
267 for _network_segment_range in self._network_segment_ranges:
268 calls.append(call(_network_segment_range))
269 self.network.delete_network_segment_range.assert_has_calls(calls)
270 self.assertIsNone(result)
271
272 def test_delete_multiple_with_exception(self):
273 arglist = [
274 self._network_segment_ranges[0].id,
275 'doesnotexist'
276 ]
277 verifylist = [
278 ('network_segment_range',
279 [self._network_segment_ranges[0].id, 'doesnotexist']),
280 ]
281 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
282
283 find_mock_result = [self._network_segment_ranges[0],
284 exceptions.CommandError]
285 self.network.find_network_segment_range = (
286 mock.Mock(side_effect=find_mock_result)
287 )
288
289 try:
290 self.cmd.take_action(parsed_args)
291 self.fail('CommandError should be raised.')
292 except exceptions.CommandError as e:
293 self.assertEqual('1 of 2 network segment ranges failed to delete.',
294 str(e))
295
296 self.network.find_network_segment_range.assert_any_call(
297 self._network_segment_ranges[0].id, ignore_missing=False)
298 self.network.find_network_segment_range.assert_any_call(
299 'doesnotexist', ignore_missing=False)
300 self.network.delete_network_segment_range.assert_called_once_with(
301 self._network_segment_ranges[0]
302 )
303
304
305class TestListNetworkSegmentRange(TestNetworkSegmentRange):
306 _network_segment_ranges = network_fakes.FakeNetworkSegmentRange.\
307 create_network_segment_ranges(count=3)
308
309 columns = (
310 'ID',
311 'Name',
312 'Default',
313 'Shared',
314 'Project ID',
315 'Network Type',
316 'Physical Network',
317 'Minimum ID',
318 'Maximum ID'
319 )
320 columns_long = columns + (
321 'Used',
322 'Available',
323 )
324
325 data = []
326 for _network_segment_range in _network_segment_ranges:
327 data.append((
328 _network_segment_range.id,
329 _network_segment_range.name,
330 _network_segment_range.default,
331 _network_segment_range.shared,
332 _network_segment_range.project_id,
333 _network_segment_range.network_type,
334 _network_segment_range.physical_network,
335 _network_segment_range.minimum,
336 _network_segment_range.maximum,
337 ))
338
339 data_long = []
340 for _network_segment_range in _network_segment_ranges:
341 data_long.append((
342 _network_segment_range.id,
343 _network_segment_range.name,
344 _network_segment_range.default,
345 _network_segment_range.shared,
346 _network_segment_range.project_id,
347 _network_segment_range.network_type,
348 _network_segment_range.physical_network,
349 _network_segment_range.minimum,
350 _network_segment_range.maximum,
351 {'3312e4ba67864b2eb53f3f41432f8efc': ['104', '106']},
352 ['100-103', '105'],
353 ))
354
355 def setUp(self):
356 super(TestListNetworkSegmentRange, self).setUp()
357
358 # Get the command object to test
359 self.cmd = network_segment_range.ListNetworkSegmentRange(
360 self.app, self.namespace)
361
362 self.network.find_extension = mock.Mock()
363 self.network.network_segment_ranges = mock.Mock(
364 return_value=self._network_segment_ranges)
365
366 def test_list_no_option(self):
367 arglist = []
368 verifylist = [
369 ('long', False),
370 ('available', False),
371 ('unavailable', False),
372 ('used', False),
373 ('unused', False),
374 ]
375 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
376
377 columns, data = self.cmd.take_action(parsed_args)
378
379 self.network.network_segment_ranges.assert_called_once_with()
380 self.assertEqual(self.columns, columns)
381 self.assertEqual(self.data, list(data))
382
383 def test_list_long(self):
384 arglist = [
385 '--long',
386 ]
387 verifylist = [
388 ('long', True),
389 ('available', False),
390 ('unavailable', False),
391 ('used', False),
392 ('unused', False),
393 ]
394 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
395
396 columns, data = self.cmd.take_action(parsed_args)
397
398 self.network.network_segment_ranges.assert_called_once_with()
399 self.assertEqual(self.columns_long, columns)
400 self.assertEqual(self.data_long, list(data))
401
402
403class TestSetNetworkSegmentRange(TestNetworkSegmentRange):
404
405 # The network segment range to set.
406 _network_segment_range = network_fakes.FakeNetworkSegmentRange.\
407 create_one_network_segment_range()
408 # The network segment range updated.
409 minimum_updated = _network_segment_range.minimum - 5
410 maximum_updated = _network_segment_range.maximum + 5
411 available_updated = (list(range(minimum_updated, 104)) + [105] +
412 list(range(107, maximum_updated + 1)))
413 _network_segment_range_updated = network_fakes.FakeNetworkSegmentRange.\
414 create_one_network_segment_range(
415 attrs={'minimum': minimum_updated,
416 'maximum': maximum_updated,
417 'used': {104: '3312e4ba67864b2eb53f3f41432f8efc',
418 106: '3312e4ba67864b2eb53f3f41432f8efc'},
419 'available': available_updated}
420 )
421
422 def setUp(self):
423 super(TestSetNetworkSegmentRange, self).setUp()
424
425 self.network.find_extension = mock.Mock()
426 self.network.find_network_segment_range = mock.Mock(
427 return_value=self._network_segment_range
428 )
429
430 # Get the command object to test
431 self.cmd = network_segment_range.SetNetworkSegmentRange(self.app,
432 self.namespace)
433
434 def test_set_no_options(self):
435 arglist = [
436 self._network_segment_range.id,
437 ]
438 verifylist = [
439 ('network_segment_range', self._network_segment_range.id),
440 ]
441
442 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
443 self.network.update_network_segment_range = mock.Mock(
444 return_value=self._network_segment_range
445 )
446 result = self.cmd.take_action(parsed_args)
447
448 self.network.update_network_segment_range.assert_called_once_with(
449 self._network_segment_range, **{}
450 )
451 self.assertIsNone(result)
452
453 def test_set_all_options(self):
454 arglist = [
455 '--name', 'new name',
456 '--minimum', str(self.minimum_updated),
457 '--maximum', str(self.maximum_updated),
458 self._network_segment_range.id,
459 ]
460 verifylist = [
461 ('name', 'new name'),
462 ('minimum', self.minimum_updated),
463 ('maximum', self.maximum_updated),
464 ('network_segment_range', self._network_segment_range.id),
465 ]
466
467 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
468 self.network.update_network_segment_range = mock.Mock(
469 return_value=self._network_segment_range_updated
470 )
471 result = self.cmd.take_action(parsed_args)
472
473 attrs = {
474 'name': 'new name',
475 'minimum': self.minimum_updated,
476 'maximum': self.maximum_updated,
477 }
478 self.network.update_network_segment_range.assert_called_once_with(
479 self._network_segment_range, **attrs
480 )
481 self.assertIsNone(result)
482
483
484class TestShowNetworkSegmentRange(TestNetworkSegmentRange):
485
486 # The network segment range to show.
487 _network_segment_range = network_fakes.FakeNetworkSegmentRange.\
488 create_one_network_segment_range()
489
490 columns = (
491 'available',
492 'default',
493 'id',
494 'maximum',
495 'minimum',
496 'name',
497 'network_type',
498 'physical_network',
499 'project_id',
500 'shared',
501 'used',
502 )
503
504 data = (
505 ['100-103', '105'],
506 _network_segment_range.default,
507 _network_segment_range.id,
508 _network_segment_range.maximum,
509 _network_segment_range.minimum,
510 _network_segment_range.name,
511 _network_segment_range.network_type,
512 _network_segment_range.physical_network,
513 _network_segment_range.project_id,
514 _network_segment_range.shared,
515 {'3312e4ba67864b2eb53f3f41432f8efc': ['104', '106']},
516 )
517
518 def setUp(self):
519 super(TestShowNetworkSegmentRange, self).setUp()
520
521 self.network.find_extension = mock.Mock()
522 self.network.find_network_segment_range = mock.Mock(
523 return_value=self._network_segment_range
524 )
525
526 # Get the command object to test
527 self.cmd = network_segment_range.ShowNetworkSegmentRange(
528 self.app, self.namespace)
529
530 def test_show_no_options(self):
531 # Missing required args should bail here
532 self.assertRaises(tests_utils.ParserException, self.check_parser,
533 self.cmd, [], [])
534
535 def test_show_all_options(self):
536 arglist = [
537 self._network_segment_range.id,
538 ]
539 verifylist = [
540 ('network_segment_range', self._network_segment_range.id),
541 ]
542
543 parsed_args = self.check_parser(self.cmd, arglist, verifylist)
544 columns, data = self.cmd.take_action(parsed_args)
545
546 self.network.find_network_segment_range.assert_called_once_with(
547 self._network_segment_range.id,
548 ignore_missing=False
549 )
550
551 self.assertEqual(self.columns, columns)
552 self.assertEqual(self.data, data)
diff --git a/releasenotes/notes/bp-network-segment-range-management-0abf03fe03eea149.yaml b/releasenotes/notes/bp-network-segment-range-management-0abf03fe03eea149.yaml
new file mode 100644
index 0000000..4ff4f57
--- /dev/null
+++ b/releasenotes/notes/bp-network-segment-range-management-0abf03fe03eea149.yaml
@@ -0,0 +1,6 @@
1---
2features:
3 - Add ``network segment range create``, ``network segment range delete``,
4 ``network segment range list``, ``network segment range show`` and
5 ``network segment range set`` commands.
6 [Blueprint `network-segment-range-management <https://blueprints.launchpad.net/neutron/+spec/network-segment-range-management>`_]
diff --git a/setup.cfg b/setup.cfg
index 48c2247..c73f2ce 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -463,6 +463,12 @@ openstack.network.v2 =
463 network_segment_set = openstackclient.network.v2.network_segment:SetNetworkSegment 463 network_segment_set = openstackclient.network.v2.network_segment:SetNetworkSegment
464 network_segment_show = openstackclient.network.v2.network_segment:ShowNetworkSegment 464 network_segment_show = openstackclient.network.v2.network_segment:ShowNetworkSegment
465 465
466 network_segment_range_create = openstackclient.network.v2.network_segment_range:CreateNetworkSegmentRange
467 network_segment_range_delete = openstackclient.network.v2.network_segment_range:DeleteNetworkSegmentRange
468 network_segment_range_list = openstackclient.network.v2.network_segment_range:ListNetworkSegmentRange
469 network_segment_range_set = openstackclient.network.v2.network_segment_range:SetNetworkSegmentRange
470 network_segment_range_show = openstackclient.network.v2.network_segment_range:ShowNetworkSegmentRange
471
466 network_service_provider_list = openstackclient.network.v2.network_service_provider:ListNetworkServiceProvider 472 network_service_provider_list = openstackclient.network.v2.network_service_provider:ListNetworkServiceProvider
467 473
468 port_create = openstackclient.network.v2.port:CreatePort 474 port_create = openstackclient.network.v2.port:CreatePort