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:
		
				
					committed by
					
						
						Steve Martinelli
					
				
			
			
				
	
			
			
			
						parent
						
							11c9695e5e
						
					
				
				
					commit
					659abf4928
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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"""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user