Add volume backend pool list command
Adds an equivalent for "cinder get-pools" with "volume backend pool list" and "cinder get-pools --detail" with "volume backend pool list --long". Story: 1655624 Task: 136949 Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com> Change-Id: I826c9946ffe11340d44ad57914f72fc2a72b6938
This commit is contained in:
		@@ -33,7 +33,7 @@ failover-host,volume host failover,Failover a replicating cinder-volume host.
 | 
				
			|||||||
force-delete,volume delete --force,"Attempts force-delete of volume, regardless of state."
 | 
					force-delete,volume delete --force,"Attempts force-delete of volume, regardless of state."
 | 
				
			||||||
freeze-host,volume host set --disable,Freeze and disable the specified cinder-volume host.
 | 
					freeze-host,volume host set --disable,Freeze and disable the specified cinder-volume host.
 | 
				
			||||||
get-capabilities,volume backend capability show,Show capabilities of a volume backend. Admin only.
 | 
					get-capabilities,volume backend capability show,Show capabilities of a volume backend. Admin only.
 | 
				
			||||||
get-pools,,Show pool information for backends. Admin only.
 | 
					get-pools,volume backend pool list,Show pool information for backends. Admin only.
 | 
				
			||||||
image-metadata,volume set --image-property,Sets or deletes volume image metadata.
 | 
					image-metadata,volume set --image-property,Sets or deletes volume image metadata.
 | 
				
			||||||
image-metadata-show,volume show,Shows volume image metadata.
 | 
					image-metadata-show,volume show,Shows volume image metadata.
 | 
				
			||||||
list,volume list,Lists all volumes.
 | 
					list,volume list,Lists all volumes.
 | 
				
			||||||
 
 | 
				
			|||||||
		
		
			
  | 
@@ -252,6 +252,41 @@ class FakeCapability(object):
 | 
				
			|||||||
        return capability
 | 
					        return capability
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FakePool(object):
 | 
				
			||||||
 | 
					    """Fake Pools."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def create_one_pool(attrs=None):
 | 
				
			||||||
 | 
					        """Create a fake pool.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param Dictionary attrs:
 | 
				
			||||||
 | 
					            A dictionary with all attributes of the pool
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					            A FakeResource object with pool name and attrs.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        # Set default attribute
 | 
				
			||||||
 | 
					        pool_info = {
 | 
				
			||||||
 | 
					            'name': 'host@lvmdriver-1#lvmdriver-1',
 | 
				
			||||||
 | 
					            'storage_protocol': 'iSCSI',
 | 
				
			||||||
 | 
					            'thick_provisioning_support': False,
 | 
				
			||||||
 | 
					            'thin_provisioning_support': True,
 | 
				
			||||||
 | 
					            'total_volumes': 99,
 | 
				
			||||||
 | 
					            'total_capacity_gb': 1000.00,
 | 
				
			||||||
 | 
					            'allocated_capacity_gb': 100,
 | 
				
			||||||
 | 
					            'max_over_subscription_ratio': 200.0,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Overwrite default attributes if there are some attributes set
 | 
				
			||||||
 | 
					        pool_info.update(attrs or {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pool = fakes.FakeResource(
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					            pool_info,
 | 
				
			||||||
 | 
					            loaded=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return pool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FakeVolumeClient(object):
 | 
					class FakeVolumeClient(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, **kwargs):
 | 
					    def __init__(self, **kwargs):
 | 
				
			||||||
@@ -294,6 +329,8 @@ class FakeVolumeClient(object):
 | 
				
			|||||||
        self.management_url = kwargs['endpoint']
 | 
					        self.management_url = kwargs['endpoint']
 | 
				
			||||||
        self.capabilities = mock.Mock()
 | 
					        self.capabilities = mock.Mock()
 | 
				
			||||||
        self.capabilities.resource_class = fakes.FakeResource(None, {})
 | 
					        self.capabilities.resource_class = fakes.FakeResource(None, {})
 | 
				
			||||||
 | 
					        self.pools = mock.Mock()
 | 
				
			||||||
 | 
					        self.pools.resource_class = fakes.FakeResource(None, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestVolume(utils.TestCommand):
 | 
					class TestVolume(utils.TestCommand):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,3 +71,98 @@ class TestShowVolumeCapability(volume_fakes.TestVolume):
 | 
				
			|||||||
        self.capability_mock.get.assert_called_with(
 | 
					        self.capability_mock.get.assert_called_with(
 | 
				
			||||||
            'fake',
 | 
					            'fake',
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestListVolumePool(volume_fakes.TestVolume):
 | 
				
			||||||
 | 
					    """Tests for volume backend pool listing."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The pool to be listed
 | 
				
			||||||
 | 
					    pools = volume_fakes.FakePool.create_one_pool()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super(TestListVolumePool, self).setUp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pool_mock = self.app.client_manager.volume.pools
 | 
				
			||||||
 | 
					        self.pool_mock.list.return_value = [self.pools]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get the command object to test
 | 
				
			||||||
 | 
					        self.cmd = volume_backend.ListPool(self.app, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_pool_list(self):
 | 
				
			||||||
 | 
					        arglist = []
 | 
				
			||||||
 | 
					        verifylist = []
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # In base command class Lister in cliff, abstract method take_action()
 | 
				
			||||||
 | 
					        # returns a tuple containing the column names and an iterable
 | 
				
			||||||
 | 
					        # containing the data to be listed.
 | 
				
			||||||
 | 
					        columns, data = self.cmd.take_action(parsed_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expected_columns = [
 | 
				
			||||||
 | 
					            'Name',
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # confirming if all expected columns are present in the result.
 | 
				
			||||||
 | 
					        self.assertEqual(expected_columns, columns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        datalist = ((
 | 
				
			||||||
 | 
					            self.pools.name,
 | 
				
			||||||
 | 
					        ), )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # confirming if all expected values are present in the result.
 | 
				
			||||||
 | 
					        self.assertEqual(datalist, tuple(data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # checking if proper call was made to list pools
 | 
				
			||||||
 | 
					        self.pool_mock.list.assert_called_with(
 | 
				
			||||||
 | 
					            detailed=False,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # checking if long columns are present in output
 | 
				
			||||||
 | 
					        self.assertNotIn("total_volumes", columns)
 | 
				
			||||||
 | 
					        self.assertNotIn("storage_protocol", columns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_service_list_with_long_option(self):
 | 
				
			||||||
 | 
					        arglist = [
 | 
				
			||||||
 | 
					            '--long'
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        verifylist = [
 | 
				
			||||||
 | 
					            ('long', True)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # In base command class Lister in cliff, abstract method take_action()
 | 
				
			||||||
 | 
					        # returns a tuple containing the column names and an iterable
 | 
				
			||||||
 | 
					        # containing the data to be listed.
 | 
				
			||||||
 | 
					        columns, data = self.cmd.take_action(parsed_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expected_columns = [
 | 
				
			||||||
 | 
					            'Name',
 | 
				
			||||||
 | 
					            'Protocol',
 | 
				
			||||||
 | 
					            'Thick',
 | 
				
			||||||
 | 
					            'Thin',
 | 
				
			||||||
 | 
					            'Volumes',
 | 
				
			||||||
 | 
					            'Capacity',
 | 
				
			||||||
 | 
					            'Allocated',
 | 
				
			||||||
 | 
					            'Max Over Ratio',
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # confirming if all expected columns are present in the result.
 | 
				
			||||||
 | 
					        self.assertEqual(expected_columns, columns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        datalist = ((
 | 
				
			||||||
 | 
					            self.pools.name,
 | 
				
			||||||
 | 
					            self.pools.storage_protocol,
 | 
				
			||||||
 | 
					            self.pools.thick_provisioning_support,
 | 
				
			||||||
 | 
					            self.pools.thin_provisioning_support,
 | 
				
			||||||
 | 
					            self.pools.total_volumes,
 | 
				
			||||||
 | 
					            self.pools.total_capacity_gb,
 | 
				
			||||||
 | 
					            self.pools.allocated_capacity_gb,
 | 
				
			||||||
 | 
					            self.pools.max_over_subscription_ratio,
 | 
				
			||||||
 | 
					        ), )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # confirming if all expected values are present in the result.
 | 
				
			||||||
 | 
					        self.assertEqual(datalist, tuple(data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.pool_mock.list.assert_called_with(
 | 
				
			||||||
 | 
					            detailed=True,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@
 | 
				
			|||||||
#   under the License.
 | 
					#   under the License.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""Capability action implementations"""
 | 
					"""Storage backend action implementations"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from osc_lib.command import command
 | 
					from osc_lib.command import command
 | 
				
			||||||
from osc_lib import utils
 | 
					from osc_lib import utils
 | 
				
			||||||
@@ -59,3 +59,55 @@ class ShowCapability(command.Lister):
 | 
				
			|||||||
                (utils.get_dict_properties(
 | 
					                (utils.get_dict_properties(
 | 
				
			||||||
                    s, columns,
 | 
					                    s, columns,
 | 
				
			||||||
                ) for s in print_data))
 | 
					                ) for s in print_data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListPool(command.Lister):
 | 
				
			||||||
 | 
					    _description = _("List pool command")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_parser(self, prog_name):
 | 
				
			||||||
 | 
					        parser = super(ListPool, self).get_parser(prog_name)
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            "--long",
 | 
				
			||||||
 | 
					            action="store_true",
 | 
				
			||||||
 | 
					            default=False,
 | 
				
			||||||
 | 
					            help=_("Show detailed information about pools.")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        # TODO(smcginnis): Starting with Cinder microversion 3.33, user is also
 | 
				
			||||||
 | 
					        # able to pass in --filters with a <key>=<value> pair to filter on.
 | 
				
			||||||
 | 
					        return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def take_action(self, parsed_args):
 | 
				
			||||||
 | 
					        volume_client = self.app.client_manager.volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if parsed_args.long:
 | 
				
			||||||
 | 
					            columns = [
 | 
				
			||||||
 | 
					                'name',
 | 
				
			||||||
 | 
					                'storage_protocol',
 | 
				
			||||||
 | 
					                'thick_provisioning_support',
 | 
				
			||||||
 | 
					                'thin_provisioning_support',
 | 
				
			||||||
 | 
					                'total_volumes',
 | 
				
			||||||
 | 
					                'total_capacity_gb',
 | 
				
			||||||
 | 
					                'allocated_capacity_gb',
 | 
				
			||||||
 | 
					                'max_over_subscription_ratio',
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            headers = [
 | 
				
			||||||
 | 
					                'Name',
 | 
				
			||||||
 | 
					                'Protocol',
 | 
				
			||||||
 | 
					                'Thick',
 | 
				
			||||||
 | 
					                'Thin',
 | 
				
			||||||
 | 
					                'Volumes',
 | 
				
			||||||
 | 
					                'Capacity',
 | 
				
			||||||
 | 
					                'Allocated',
 | 
				
			||||||
 | 
					                'Max Over Ratio'
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            columns = [
 | 
				
			||||||
 | 
					                'Name',
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            headers = columns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = volume_client.pools.list(detailed=parsed_args.long)
 | 
				
			||||||
 | 
					        return (headers,
 | 
				
			||||||
 | 
					                (utils.get_item_properties(
 | 
				
			||||||
 | 
					                    s, columns,
 | 
				
			||||||
 | 
					                ) for s in data))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,3 +5,7 @@ features:
 | 
				
			|||||||
    added which will provide a list of all capabilities that can be configured
 | 
					    added which will provide a list of all capabilities that can be configured
 | 
				
			||||||
    for the requested backend. The required `<host>` parameter takes the form
 | 
					    for the requested backend. The required `<host>` parameter takes the form
 | 
				
			||||||
    `host@backend-name`.
 | 
					    `host@backend-name`.
 | 
				
			||||||
 | 
					  - |
 | 
				
			||||||
 | 
					    A new command, ``openstack volume backend pool list`` was added which will
 | 
				
			||||||
 | 
					    provide a list of all backend storage pools. The optional ``-long``
 | 
				
			||||||
 | 
					    parameter includes some basic configuration and stats for each pool.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -630,6 +630,7 @@ openstack.volume.v2 =
 | 
				
			|||||||
    volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup
 | 
					    volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    volume_backend_capability_show = openstackclient.volume.v2.volume_backend:ShowCapability
 | 
					    volume_backend_capability_show = openstackclient.volume.v2.volume_backend:ShowCapability
 | 
				
			||||||
 | 
					    volume_backend_pool_list = openstackclient.volume.v2.volume_backend:ListPool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    volume_host_failover = openstackclient.volume.v2.volume_host:FailoverVolumeHost
 | 
					    volume_host_failover = openstackclient.volume.v2.volume_host:FailoverVolumeHost
 | 
				
			||||||
    volume_host_set = openstackclient.volume.v2.volume_host:SetVolumeHost
 | 
					    volume_host_set = openstackclient.volume.v2.volume_host:SetVolumeHost
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user