Skip to content

Commit fe879b5

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add and modify options for "volume create" command"
2 parents 08df1d0 + c9e0c01 commit fe879b5

File tree

6 files changed

+296
-30
lines changed

6 files changed

+296
-30
lines changed

doc/source/command-objects/volume.rst

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,23 @@ Create new volume
1313
.. code:: bash
1414
1515
os volume create
16-
--size <size>
16+
[--size <size>]
1717
[--type <volume-type>]
18-
[--image <image>]
19-
[--snapshot <snapshot>]
20-
[--source <volume>]
18+
[--image <image> | --snapshot <snapshot> | --source <volume> | --source-replicated <replicated-volume>]
2119
[--description <description>]
2220
[--user <user>]
2321
[--project <project>]
2422
[--availability-zone <availability-zone>]
23+
[--consistency-group <consistency-group>]
2524
[--property <key=value> [...] ]
25+
[--hint <key=value> [...] ]
26+
[--multi-attach]
2627
<name>
2728
28-
.. option:: --size <size> (required)
29+
.. option:: --size <size>
2930

3031
Volume size in GB
32+
(Required unless --snapshot or --source or --source-replicated is specified)
3133

3234
.. option:: --type <volume-type>
3335

@@ -46,10 +48,14 @@ Create new volume
4648

4749
Use :option:`\<snapshot\>` as source of volume (name or ID)
4850

49-
.. option:: --source <source>
51+
.. option:: --source <volume>
5052

5153
Volume to clone (name or ID)
5254

55+
.. option:: --source-replicated <replicated-volume>
56+
57+
Replicated volume to clone (name or ID)
58+
5359
.. option:: --description <description>
5460

5561
Volume description
@@ -66,10 +72,23 @@ Create new volume
6672

6773
Create volume in :option:`\<availability-zone\>`
6874

75+
.. option:: --consistency-group <consistency-group>
76+
77+
Consistency group where the new volume belongs to
78+
6979
.. option:: --property <key=value>
7080

7181
Set a property on this volume (repeat option to set multiple properties)
7282

83+
.. option:: --hint <key=value>
84+
85+
Arbitrary scheduler hint key-value pairs to help boot an instance
86+
(repeat option to set multiple hints)
87+
88+
.. option:: --multi-attach
89+
90+
Allow volume to be attached more than once (default to False)
91+
7392
.. _volume_create-name:
7493
.. describe:: <name>
7594

openstackclient/tests/unit/volume/v1/test_volume.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from openstackclient.tests.unit import fakes
2525
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
26+
from openstackclient.tests.unit import utils as tests_utils
2627
from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
2728
from openstackclient.volume.v1 import volume
2829

@@ -411,6 +412,67 @@ def test_volume_create_image_name(self):
411412
self.assertEqual(self.columns, columns)
412413
self.assertEqual(self.datalist, data)
413414

415+
def test_volume_create_with_source(self):
416+
self.volumes_mock.get.return_value = self.new_volume
417+
arglist = [
418+
'--source', self.new_volume.id,
419+
self.new_volume.display_name,
420+
]
421+
verifylist = [
422+
('source', self.new_volume.id),
423+
('name', self.new_volume.display_name),
424+
]
425+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
426+
427+
columns, data = self.cmd.take_action(parsed_args)
428+
429+
self.volumes_mock.create.assert_called_with(
430+
None,
431+
None,
432+
self.new_volume.id,
433+
self.new_volume.display_name,
434+
None,
435+
None,
436+
None,
437+
None,
438+
None,
439+
None,
440+
None,
441+
)
442+
self.assertEqual(self.columns, columns)
443+
self.assertEqual(self.datalist, data)
444+
445+
def test_volume_create_without_size(self):
446+
arglist = [
447+
self.new_volume.display_name,
448+
]
449+
verifylist = [
450+
('name', self.new_volume.display_name),
451+
]
452+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
453+
454+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
455+
parsed_args)
456+
457+
def test_volume_create_with_multi_source(self):
458+
arglist = [
459+
'--image', 'source_image',
460+
'--source', 'source_volume',
461+
'--snapshot', 'source_snapshot',
462+
'--size', str(self.new_volume.size),
463+
self.new_volume.display_name,
464+
]
465+
verifylist = [
466+
('image', 'source_image'),
467+
('source', 'source_volume'),
468+
('snapshot', 'source_snapshot'),
469+
('size', self.new_volume.size),
470+
('name', self.new_volume.display_name),
471+
]
472+
473+
self.assertRaises(tests_utils.ParserException, self.check_parser,
474+
self.cmd, arglist, verifylist)
475+
414476

415477
class TestVolumeDelete(TestVolume):
416478

openstackclient/tests/unit/volume/v2/test_volume.py

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
2323
from openstackclient.tests.unit.image.v2 import fakes as image_fakes
24+
from openstackclient.tests.unit import utils as tests_utils
2425
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
2526
from openstackclient.volume.v2 import volume
2627

@@ -45,6 +46,10 @@ def setUp(self):
4546
self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
4647
self.snapshots_mock.reset_mock()
4748

49+
self.consistencygroups_mock = (
50+
self.app.client_manager.volume.consistencygroups)
51+
self.consistencygroups_mock.reset_mock()
52+
4853
def setup_volumes_mock(self, count):
4954
volumes = volume_fakes.FakeVolume.create_volumes(count=count)
5055

@@ -123,25 +128,38 @@ def test_volume_create_min_options(self):
123128
availability_zone=None,
124129
metadata=None,
125130
imageRef=None,
126-
source_volid=None
131+
source_volid=None,
132+
consistencygroup_id=None,
133+
source_replica=None,
134+
multiattach=False,
135+
scheduler_hints=None,
127136
)
128137

129138
self.assertEqual(self.columns, columns)
130139
self.assertEqual(self.datalist, data)
131140

132141
def test_volume_create_options(self):
142+
consistency_group = (
143+
volume_fakes.FakeConsistencyGroup.create_one_consistency_group())
144+
self.consistencygroups_mock.get.return_value = consistency_group
133145
arglist = [
134146
'--size', str(self.new_volume.size),
135147
'--description', self.new_volume.description,
136148
'--type', self.new_volume.volume_type,
137149
'--availability-zone', self.new_volume.availability_zone,
150+
'--consistency-group', consistency_group.id,
151+
'--hint', 'k=v',
152+
'--multi-attach',
138153
self.new_volume.name,
139154
]
140155
verifylist = [
141156
('size', self.new_volume.size),
142157
('description', self.new_volume.description),
143158
('type', self.new_volume.volume_type),
144159
('availability_zone', self.new_volume.availability_zone),
160+
('consistency_group', consistency_group.id),
161+
('hint', {'k': 'v'}),
162+
('multi_attach', True),
145163
('name', self.new_volume.name),
146164
]
147165
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -162,7 +180,11 @@ def test_volume_create_options(self):
162180
availability_zone=self.new_volume.availability_zone,
163181
metadata=None,
164182
imageRef=None,
165-
source_volid=None
183+
source_volid=None,
184+
consistencygroup_id=consistency_group.id,
185+
source_replica=None,
186+
multiattach=True,
187+
scheduler_hints={'k': 'v'},
166188
)
167189

168190
self.assertEqual(self.columns, columns)
@@ -204,7 +226,11 @@ def test_volume_create_user_project_id(self):
204226
availability_zone=None,
205227
metadata=None,
206228
imageRef=None,
207-
source_volid=None
229+
source_volid=None,
230+
consistencygroup_id=None,
231+
source_replica=None,
232+
multiattach=False,
233+
scheduler_hints=None,
208234
)
209235

210236
self.assertEqual(self.columns, columns)
@@ -246,7 +272,11 @@ def test_volume_create_user_project_name(self):
246272
availability_zone=None,
247273
metadata=None,
248274
imageRef=None,
249-
source_volid=None
275+
source_volid=None,
276+
consistencygroup_id=None,
277+
source_replica=None,
278+
multiattach=False,
279+
scheduler_hints=None,
250280
)
251281

252282
self.assertEqual(self.columns, columns)
@@ -282,7 +312,11 @@ def test_volume_create_properties(self):
282312
availability_zone=None,
283313
metadata={'Alpha': 'a', 'Beta': 'b'},
284314
imageRef=None,
285-
source_volid=None
315+
source_volid=None,
316+
consistencygroup_id=None,
317+
source_replica=None,
318+
multiattach=False,
319+
scheduler_hints=None,
286320
)
287321

288322
self.assertEqual(self.columns, columns)
@@ -321,6 +355,10 @@ def test_volume_create_image_id(self):
321355
metadata=None,
322356
imageRef=image.id,
323357
source_volid=None,
358+
consistencygroup_id=None,
359+
source_replica=None,
360+
multiattach=False,
361+
scheduler_hints=None,
324362
)
325363

326364
self.assertEqual(self.columns, columns)
@@ -358,7 +396,11 @@ def test_volume_create_image_name(self):
358396
availability_zone=None,
359397
metadata=None,
360398
imageRef=image.id,
361-
source_volid=None
399+
source_volid=None,
400+
consistencygroup_id=None,
401+
source_replica=None,
402+
multiattach=False,
403+
scheduler_hints=None,
362404
)
363405

364406
self.assertEqual(self.columns, columns)
@@ -368,12 +410,10 @@ def test_volume_create_with_snapshot(self):
368410
snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
369411
self.new_volume.snapshot_id = snapshot.id
370412
arglist = [
371-
'--size', str(self.new_volume.size),
372413
'--snapshot', self.new_volume.snapshot_id,
373414
self.new_volume.name,
374415
]
375416
verifylist = [
376-
('size', self.new_volume.size),
377417
('snapshot', self.new_volume.snapshot_id),
378418
('name', self.new_volume.name),
379419
]
@@ -387,7 +427,7 @@ def test_volume_create_with_snapshot(self):
387427
columns, data = self.cmd.take_action(parsed_args)
388428

389429
self.volumes_mock.create.assert_called_once_with(
390-
size=self.new_volume.size,
430+
size=None,
391431
snapshot_id=snapshot.id,
392432
name=self.new_volume.name,
393433
description=None,
@@ -397,12 +437,83 @@ def test_volume_create_with_snapshot(self):
397437
availability_zone=None,
398438
metadata=None,
399439
imageRef=None,
400-
source_volid=None
440+
source_volid=None,
441+
consistencygroup_id=None,
442+
source_replica=None,
443+
multiattach=False,
444+
scheduler_hints=None,
401445
)
402446

403447
self.assertEqual(self.columns, columns)
404448
self.assertEqual(self.datalist, data)
405449

450+
def test_volume_create_with_source_replicated(self):
451+
self.volumes_mock.get.return_value = self.new_volume
452+
arglist = [
453+
'--source-replicated', self.new_volume.id,
454+
self.new_volume.name,
455+
]
456+
verifylist = [
457+
('source_replicated', self.new_volume.id),
458+
('name', self.new_volume.name),
459+
]
460+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
461+
462+
columns, data = self.cmd.take_action(parsed_args)
463+
self.volumes_mock.create.assert_called_once_with(
464+
size=None,
465+
snapshot_id=None,
466+
name=self.new_volume.name,
467+
description=None,
468+
volume_type=None,
469+
user_id=None,
470+
project_id=None,
471+
availability_zone=None,
472+
metadata=None,
473+
imageRef=None,
474+
source_volid=None,
475+
consistencygroup_id=None,
476+
source_replica=self.new_volume.id,
477+
multiattach=False,
478+
scheduler_hints=None,
479+
)
480+
481+
self.assertEqual(self.columns, columns)
482+
self.assertEqual(self.datalist, data)
483+
484+
def test_volume_create_without_size(self):
485+
arglist = [
486+
self.new_volume.name,
487+
]
488+
verifylist = [
489+
('name', self.new_volume.name),
490+
]
491+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
492+
493+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
494+
parsed_args)
495+
496+
def test_volume_create_with_multi_source(self):
497+
arglist = [
498+
'--image', 'source_image',
499+
'--source', 'source_volume',
500+
'--snapshot', 'source_snapshot',
501+
'--source-replicated', 'source_replicated_volume',
502+
'--size', str(self.new_volume.size),
503+
self.new_volume.name,
504+
]
505+
verifylist = [
506+
('image', 'source_image'),
507+
('source', 'source_volume'),
508+
('snapshot', 'source_snapshot'),
509+
('source-replicated', 'source_replicated_volume'),
510+
('size', self.new_volume.size),
511+
('name', self.new_volume.name),
512+
]
513+
514+
self.assertRaises(tests_utils.ParserException, self.check_parser,
515+
self.cmd, arglist, verifylist)
516+
406517

407518
class TestVolumeDelete(TestVolume):
408519

0 commit comments

Comments
 (0)