Skip to content

Commit 26ea98b

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add create and list for volume type v2"
2 parents 7442c01 + 659abf4 commit 26ea98b

4 files changed

Lines changed: 253 additions & 1 deletion

File tree

doc/source/command-objects/volume-type.rst

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
volume type
33
===========
44

5-
Volume v1
5+
Volume v1, v2
66

77
volume type create
88
------------------
@@ -13,9 +13,29 @@ Create new volume type
1313
.. code:: bash
1414
1515
os volume type create
16+
[--description <description>]
17+
[--public | --private]
1618
[--property <key=value> [...] ]
1719
<name>
1820
21+
.. option:: --description <description>
22+
23+
New volume type description
24+
25+
.. versionadded:: 2
26+
27+
.. option:: --public
28+
29+
Volume type is accessible to the public
30+
31+
.. versionadded:: 2
32+
33+
.. option:: --private
34+
35+
Volume type is not accessible to the public
36+
37+
.. versionadded:: 2
38+
1939
.. option:: --property <key=value>
2040

2141
Set a property on this volume type (repeat option to set multiple properties)
@@ -57,6 +77,8 @@ List volume types
5777
volume type set
5878
---------------
5979

80+
*Only supported for Volume API v1*
81+
6082
Set volume type properties
6183

6284
.. program:: volume type set
@@ -77,6 +99,8 @@ Set volume type properties
7799
volume type unset
78100
-----------------
79101

102+
*Only supported for Volume API v1*
103+
80104
Unset volume type properties
81105

82106
.. program:: volume type unset

openstackclient/tests/volume/v2/test_type.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,135 @@ def setUp(self):
2828
self.types_mock.reset_mock()
2929

3030

31+
class TestTypeCreate(TestType):
32+
33+
def setUp(self):
34+
super(TestTypeCreate, self).setUp()
35+
36+
self.types_mock.create.return_value = fakes.FakeResource(
37+
None,
38+
copy.deepcopy(volume_fakes.TYPE),
39+
loaded=True,
40+
)
41+
# Get the command object to test
42+
self.cmd = volume_type.CreateVolumeType(self.app, None)
43+
44+
def test_type_create_public(self):
45+
arglist = [
46+
volume_fakes.type_name,
47+
"--description", volume_fakes.type_description,
48+
"--public"
49+
]
50+
verifylist = [
51+
("name", volume_fakes.type_name),
52+
("description", volume_fakes.type_description),
53+
("public", True),
54+
("private", False),
55+
]
56+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
57+
58+
columns, data = self.cmd.take_action(parsed_args)
59+
self.types_mock.create.assert_called_with(
60+
volume_fakes.type_name,
61+
description=volume_fakes.type_description,
62+
public=True,
63+
)
64+
65+
collist = (
66+
'description',
67+
'id',
68+
'name',
69+
)
70+
self.assertEqual(collist, columns)
71+
datalist = (
72+
volume_fakes.type_description,
73+
volume_fakes.type_id,
74+
volume_fakes.type_name,
75+
)
76+
self.assertEqual(datalist, data)
77+
78+
def test_type_create_private(self):
79+
arglist = [
80+
volume_fakes.type_name,
81+
"--description", volume_fakes.type_description,
82+
"--private"
83+
]
84+
verifylist = [
85+
("name", volume_fakes.type_name),
86+
("description", volume_fakes.type_description),
87+
("public", False),
88+
("private", True),
89+
]
90+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
91+
92+
columns, data = self.cmd.take_action(parsed_args)
93+
self.types_mock.create.assert_called_with(
94+
volume_fakes.type_name,
95+
description=volume_fakes.type_description,
96+
private=True,
97+
)
98+
99+
collist = (
100+
'description',
101+
'id',
102+
'name',
103+
)
104+
self.assertEqual(collist, columns)
105+
datalist = (
106+
volume_fakes.type_description,
107+
volume_fakes.type_id,
108+
volume_fakes.type_name,
109+
)
110+
self.assertEqual(datalist, data)
111+
112+
113+
class TestTypeList(TestType):
114+
def setUp(self):
115+
super(TestTypeList, self).setUp()
116+
117+
self.types_mock.list.return_value = [
118+
fakes.FakeResource(
119+
None,
120+
copy.deepcopy(volume_fakes.TYPE),
121+
loaded=True
122+
)
123+
]
124+
# get the command to test
125+
self.cmd = volume_type.ListVolumeType(self.app, None)
126+
127+
def test_type_list_without_options(self):
128+
arglist = []
129+
verifylist = [
130+
("long", False)
131+
]
132+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
133+
134+
columns, data = self.cmd.take_action(parsed_args)
135+
collist = ["ID", "Name"]
136+
self.assertEqual(collist, columns)
137+
datalist = ((
138+
volume_fakes.type_id,
139+
volume_fakes.type_name,
140+
),)
141+
self.assertEqual(datalist, tuple(data))
142+
143+
def test_type_list_with_options(self):
144+
arglist = ["--long"]
145+
verifylist = [("long", True)]
146+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
147+
148+
columns, data = self.cmd.take_action(parsed_args)
149+
collist = ["ID", "Name", "Description", "Properties"]
150+
self.assertEqual(collist, columns)
151+
datalist = ((
152+
volume_fakes.type_id,
153+
volume_fakes.type_name,
154+
volume_fakes.type_description,
155+
"foo='bar'"
156+
),)
157+
self.assertEqual(datalist, tuple(data))
158+
159+
31160
class TestTypeShow(TestType):
32161
def setUp(self):
33162
super(TestTypeShow, self).setUp()

openstackclient/volume/v2/volume_type.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,79 @@
1717
import logging
1818

1919
from cliff import command
20+
from cliff import lister
2021
from cliff import show
2122
import six
2223

24+
from openstackclient.common import parseractions
2325
from openstackclient.common import utils
2426

2527

28+
class CreateVolumeType(show.ShowOne):
29+
"""Create new volume type"""
30+
31+
log = logging.getLogger(__name__ + ".CreateVolumeType")
32+
33+
def get_parser(self, prog_name):
34+
parser = super(CreateVolumeType, self).get_parser(prog_name)
35+
parser.add_argument(
36+
"name",
37+
metavar="<name>",
38+
help="New volume type name"
39+
)
40+
parser.add_argument(
41+
"--description",
42+
metavar="<description>",
43+
help="New volume type description",
44+
)
45+
public_group = parser.add_mutually_exclusive_group()
46+
public_group.add_argument(
47+
"--public",
48+
dest="public",
49+
action="store_true",
50+
default=False,
51+
help="Volume type is accessible to the public",
52+
)
53+
public_group.add_argument(
54+
"--private",
55+
dest="private",
56+
action="store_true",
57+
default=False,
58+
help="Volume type is not accessible to the public",
59+
)
60+
parser.add_argument(
61+
'--property',
62+
metavar='<key=value>',
63+
action=parseractions.KeyValueAction,
64+
help='Property to add for this volume type'
65+
'(repeat option to set multiple properties)',
66+
)
67+
return parser
68+
69+
def take_action(self, parsed_args):
70+
self.log.debug('take_action(%s)', parsed_args)
71+
72+
volume_client = self.app.client_manager.volume
73+
74+
kwargs = {}
75+
if parsed_args.public:
76+
kwargs['public'] = True
77+
if parsed_args.private:
78+
kwargs['private'] = True
79+
80+
volume_type = volume_client.volume_types.create(
81+
parsed_args.name,
82+
description=parsed_args.description,
83+
**kwargs
84+
)
85+
volume_type._info.pop('extra_specs')
86+
if parsed_args.property:
87+
result = volume_type.set_keys(parsed_args.property)
88+
volume_type._info.update({'properties': utils.format_dict(result)})
89+
90+
return zip(*sorted(six.iteritems(volume_type._info)))
91+
92+
2693
class DeleteVolumeType(command.Command):
2794
"""Delete volume type"""
2895

@@ -46,6 +113,36 @@ def take_action(self, parsed_args):
46113
return
47114

48115

116+
class ListVolumeType(lister.Lister):
117+
"""List volume types"""
118+
119+
log = logging.getLogger(__name__ + '.ListVolumeType')
120+
121+
def get_parser(self, prog_name):
122+
parser = super(ListVolumeType, self).get_parser(prog_name)
123+
parser.add_argument(
124+
'--long',
125+
action='store_true',
126+
default=False,
127+
help='List additional fields in output')
128+
return parser
129+
130+
def take_action(self, parsed_args):
131+
self.log.debug('take_action(%s)', parsed_args)
132+
if parsed_args.long:
133+
columns = ['ID', 'Name', 'Description', 'Extra Specs']
134+
column_headers = ['ID', 'Name', 'Description', 'Properties']
135+
else:
136+
columns = ['ID', 'Name']
137+
column_headers = columns
138+
data = self.app.client_manager.volume.volume_types.list()
139+
return (column_headers,
140+
(utils.get_item_properties(
141+
s, columns,
142+
formatters={'Extra Specs': utils.format_dict},
143+
) for s in data))
144+
145+
49146
class ShowVolumeType(show.ShowOne):
50147
"""Display volume type details"""
51148

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,9 @@ openstack.volume.v2 =
395395
volume_delete = openstackclient.volume.v2.volume:DeleteVolume
396396
volume_show = openstackclient.volume.v2.volume:ShowVolume
397397

398+
volume_type_create = openstackclient.volume.v2.volume_type:CreateVolumeType
398399
volume_type_delete = openstackclient.volume.v2.volume_type:DeleteVolumeType
400+
volume_type_list = openstackclient.volume.v2.volume_type:ListVolumeType
399401
volume_type_show = openstackclient.volume.v2.volume_type:ShowVolumeType
400402

401403
volume_qos_associate = openstackclient.volume.v2.qos_specs:AssociateQos

0 commit comments

Comments
 (0)