Add create and list for volume type v2

Volume API v2 is missing create and list features.

implements bp: volume-v2

Change-Id: I34a1ae440e9620b1c65546f4f43b369c8661250d
This commit is contained in:
chengkunye 2015-07-17 17:05:23 +08:00 committed by Steve Martinelli
parent 11c9695e5e
commit 659abf4928
4 changed files with 253 additions and 1 deletions

View File

@ -2,7 +2,7 @@
volume type
===========
Volume v1
Volume v1, v2
volume type create
------------------
@ -13,9 +13,29 @@ Create new volume type
.. code:: bash
os volume type create
[--description <description>]
[--public | --private]
[--property <key=value> [...] ]
<name>
.. option:: --description <description>
New volume type description
.. versionadded:: 2
.. option:: --public
Volume type is accessible to the public
.. versionadded:: 2
.. option:: --private
Volume type is not accessible to the public
.. versionadded:: 2
.. option:: --property <key=value>
Set a property on this volume type (repeat option to set multiple properties)
@ -57,6 +77,8 @@ List volume types
volume type set
---------------
*Only supported for Volume API v1*
Set volume type properties
.. program:: volume type set
@ -77,6 +99,8 @@ Set volume type properties
volume type unset
-----------------
*Only supported for Volume API v1*
Unset volume type properties
.. program:: volume type unset

View File

@ -28,6 +28,135 @@ class TestType(volume_fakes.TestVolume):
self.types_mock.reset_mock()
class TestTypeCreate(TestType):
def setUp(self):
super(TestTypeCreate, self).setUp()
self.types_mock.create.return_value = fakes.FakeResource(
None,
copy.deepcopy(volume_fakes.TYPE),
loaded=True,
)
# Get the command object to test
self.cmd = volume_type.CreateVolumeType(self.app, None)
def test_type_create_public(self):
arglist = [
volume_fakes.type_name,
"--description", volume_fakes.type_description,
"--public"
]
verifylist = [
("name", volume_fakes.type_name),
("description", volume_fakes.type_description),
("public", True),
("private", False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.types_mock.create.assert_called_with(
volume_fakes.type_name,
description=volume_fakes.type_description,
public=True,
)
collist = (
'description',
'id',
'name',
)
self.assertEqual(collist, columns)
datalist = (
volume_fakes.type_description,
volume_fakes.type_id,
volume_fakes.type_name,
)
self.assertEqual(datalist, data)
def test_type_create_private(self):
arglist = [
volume_fakes.type_name,
"--description", volume_fakes.type_description,
"--private"
]
verifylist = [
("name", volume_fakes.type_name),
("description", volume_fakes.type_description),
("public", False),
("private", True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.types_mock.create.assert_called_with(
volume_fakes.type_name,
description=volume_fakes.type_description,
private=True,
)
collist = (
'description',
'id',
'name',
)
self.assertEqual(collist, columns)
datalist = (
volume_fakes.type_description,
volume_fakes.type_id,
volume_fakes.type_name,
)
self.assertEqual(datalist, data)
class TestTypeList(TestType):
def setUp(self):
super(TestTypeList, self).setUp()
self.types_mock.list.return_value = [
fakes.FakeResource(
None,
copy.deepcopy(volume_fakes.TYPE),
loaded=True
)
]
# get the command to test
self.cmd = volume_type.ListVolumeType(self.app, None)
def test_type_list_without_options(self):
arglist = []
verifylist = [
("long", False)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
collist = ["ID", "Name"]
self.assertEqual(collist, columns)
datalist = ((
volume_fakes.type_id,
volume_fakes.type_name,
),)
self.assertEqual(datalist, tuple(data))
def test_type_list_with_options(self):
arglist = ["--long"]
verifylist = [("long", True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
collist = ["ID", "Name", "Description", "Properties"]
self.assertEqual(collist, columns)
datalist = ((
volume_fakes.type_id,
volume_fakes.type_name,
volume_fakes.type_description,
"foo='bar'"
),)
self.assertEqual(datalist, tuple(data))
class TestTypeShow(TestType):
def setUp(self):
super(TestTypeShow, self).setUp()

View File

@ -17,12 +17,79 @@
import logging
from cliff import command
from cliff import lister
from cliff import show
import six
from openstackclient.common import parseractions
from openstackclient.common import utils
class CreateVolumeType(show.ShowOne):
"""Create new volume type"""
log = logging.getLogger(__name__ + ".CreateVolumeType")
def get_parser(self, prog_name):
parser = super(CreateVolumeType, self).get_parser(prog_name)
parser.add_argument(
"name",
metavar="<name>",
help="New volume type name"
)
parser.add_argument(
"--description",
metavar="<description>",
help="New volume type description",
)
public_group = parser.add_mutually_exclusive_group()
public_group.add_argument(
"--public",
dest="public",
action="store_true",
default=False,
help="Volume type is accessible to the public",
)
public_group.add_argument(
"--private",
dest="private",
action="store_true",
default=False,
help="Volume type is not accessible to the public",
)
parser.add_argument(
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
help='Property to add for this volume type'
'(repeat option to set multiple properties)',
)
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
volume_client = self.app.client_manager.volume
kwargs = {}
if parsed_args.public:
kwargs['public'] = True
if parsed_args.private:
kwargs['private'] = True
volume_type = volume_client.volume_types.create(
parsed_args.name,
description=parsed_args.description,
**kwargs
)
volume_type._info.pop('extra_specs')
if parsed_args.property:
result = volume_type.set_keys(parsed_args.property)
volume_type._info.update({'properties': utils.format_dict(result)})
return zip(*sorted(six.iteritems(volume_type._info)))
class DeleteVolumeType(command.Command):
"""Delete volume type"""
@ -46,6 +113,36 @@ class DeleteVolumeType(command.Command):
return
class ListVolumeType(lister.Lister):
"""List volume types"""
log = logging.getLogger(__name__ + '.ListVolumeType')
def get_parser(self, prog_name):
parser = super(ListVolumeType, self).get_parser(prog_name)
parser.add_argument(
'--long',
action='store_true',
default=False,
help='List additional fields in output')
return parser
def take_action(self, parsed_args):
self.log.debug('take_action(%s)', parsed_args)
if parsed_args.long:
columns = ['ID', 'Name', 'Description', 'Extra Specs']
column_headers = ['ID', 'Name', 'Description', 'Properties']
else:
columns = ['ID', 'Name']
column_headers = columns
data = self.app.client_manager.volume.volume_types.list()
return (column_headers,
(utils.get_item_properties(
s, columns,
formatters={'Extra Specs': utils.format_dict},
) for s in data))
class ShowVolumeType(show.ShowOne):
"""Display volume type details"""

View File

@ -393,7 +393,9 @@ openstack.volume.v2 =
volume_delete = openstackclient.volume.v2.volume:DeleteVolume
volume_show = openstackclient.volume.v2.volume:ShowVolume
volume_type_create = openstackclient.volume.v2.volume_type:CreateVolumeType
volume_type_delete = openstackclient.volume.v2.volume_type:DeleteVolumeType
volume_type_list = openstackclient.volume.v2.volume_type:ListVolumeType
volume_type_show = openstackclient.volume.v2.volume_type:ShowVolumeType
volume_qos_associate = openstackclient.volume.v2.qos_specs:AssociateQos