Add list feature to volume v2
"volume list" is not in the v2. Co-Authored-By: Lin Hua Cheng <os.lcheng@gmail.com> implements bp: volume-v2 Change-Id: I9f4585202f5f9ec5f4c091278fc6c4036efb1290
This commit is contained in:
		| @@ -2,7 +2,7 @@ | ||||
| volume | ||||
| ====== | ||||
|  | ||||
| Volume v1 | ||||
| Volume v1, v2 | ||||
|  | ||||
| volume create | ||||
| ------------- | ||||
|   | ||||
| @@ -15,11 +15,15 @@ | ||||
| import copy | ||||
| import mock | ||||
|  | ||||
| from openstackclient.tests.compute.v2 import fakes as compute_fakes | ||||
| from openstackclient.tests import fakes | ||||
| from openstackclient.tests.identity.v2_0 import fakes as identity_fakes | ||||
| from openstackclient.tests.image.v2 import fakes as image_fakes | ||||
| from openstackclient.tests import utils | ||||
|  | ||||
| volume_attachment_server = copy.deepcopy(compute_fakes.SERVER) | ||||
| volume_attachment_server['device'] = 'device' | ||||
|  | ||||
| volume_id = "ce26708d-a7f8-4b4b-9861-4a80256615a6" | ||||
| volume_name = "fake_volume" | ||||
| volume_description = "fake description" | ||||
| @@ -34,7 +38,7 @@ volume_metadata = { | ||||
| volume_metadata_str = "Alpha='a', Beta='b', Gamma='g'" | ||||
| volume_snapshot_id = 1 | ||||
| volume_availability_zone = "nova" | ||||
| volume_attachments = ["fake_attachments"] | ||||
| volume_attachments = [volume_attachment_server] | ||||
|  | ||||
| VOLUME = { | ||||
|     "id": volume_id, | ||||
|   | ||||
| @@ -495,6 +495,220 @@ class TestVolumeCreate(TestVolume): | ||||
|         self.assertEqual(datalist, data) | ||||
|  | ||||
|  | ||||
| class TestVolumeList(TestVolume): | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(TestVolumeList, self).setUp() | ||||
|  | ||||
|         self.volumes_mock.list.return_value = [ | ||||
|             fakes.FakeResource( | ||||
|                 None, | ||||
|                 copy.deepcopy(volume_fakes.VOLUME), | ||||
|                 loaded=True, | ||||
|             ), | ||||
|         ] | ||||
|  | ||||
|         self.users_mock.get.return_value = [ | ||||
|             fakes.FakeResource( | ||||
|                 None, | ||||
|                 copy.deepcopy(identity_fakes.USER), | ||||
|                 loaded=True, | ||||
|             ), | ||||
|         ] | ||||
|  | ||||
|         self.projects_mock.get.return_value = [ | ||||
|             fakes.FakeResource( | ||||
|                 None, | ||||
|                 copy.deepcopy(identity_fakes.PROJECT), | ||||
|                 loaded=True, | ||||
|             ), | ||||
|         ] | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = volume.ListVolume(self.app, None) | ||||
|  | ||||
|     def test_volume_list_no_options(self): | ||||
|         arglist = [] | ||||
|         verifylist = [ | ||||
|             ('long', False), | ||||
|             ('all_projects', False), | ||||
|             ('name', None), | ||||
|             ('status', None), | ||||
|         ] | ||||
|         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = [ | ||||
|             'ID', | ||||
|             'Display Name', | ||||
|             'Status', | ||||
|             'Size', | ||||
|             'Attached to', | ||||
|         ] | ||||
|         self.assertEqual(collist, columns) | ||||
|  | ||||
|         server = volume_fakes.volume_attachment_server['id'] | ||||
|         device = volume_fakes.volume_attachment_server['device'] | ||||
|         msg = 'Attached to %s on %s ' % (server, device) | ||||
|         datalist = (( | ||||
|             volume_fakes.volume_id, | ||||
|             volume_fakes.volume_name, | ||||
|             volume_fakes.volume_status, | ||||
|             volume_fakes.volume_size, | ||||
|             msg, | ||||
|         ), ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_volume_list_all_projects_option(self): | ||||
|         arglist = [ | ||||
|             '--all-projects', | ||||
|         ] | ||||
|         verifylist = [ | ||||
|             ('long', False), | ||||
|             ('all_projects', True), | ||||
|             ('name', None), | ||||
|             ('status', None), | ||||
|         ] | ||||
|         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = [ | ||||
|             'ID', | ||||
|             'Display Name', | ||||
|             'Status', | ||||
|             'Size', | ||||
|             'Attached to', | ||||
|         ] | ||||
|         self.assertEqual(collist, columns) | ||||
|  | ||||
|         server = volume_fakes.volume_attachment_server['id'] | ||||
|         device = volume_fakes.volume_attachment_server['device'] | ||||
|         msg = 'Attached to %s on %s ' % (server, device) | ||||
|         datalist = (( | ||||
|             volume_fakes.volume_id, | ||||
|             volume_fakes.volume_name, | ||||
|             volume_fakes.volume_status, | ||||
|             volume_fakes.volume_size, | ||||
|             msg, | ||||
|         ), ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_volume_list_name(self): | ||||
|         arglist = [ | ||||
|             '--name', volume_fakes.volume_name, | ||||
|         ] | ||||
|         verifylist = [ | ||||
|             ('long', False), | ||||
|             ('all_projects', False), | ||||
|             ('name', volume_fakes.volume_name), | ||||
|             ('status', None), | ||||
|         ] | ||||
|         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = ( | ||||
|             'ID', | ||||
|             'Display Name', | ||||
|             'Status', | ||||
|             'Size', | ||||
|             'Attached to', | ||||
|         ) | ||||
|         self.assertEqual(collist, tuple(columns)) | ||||
|  | ||||
|         server = volume_fakes.volume_attachment_server['id'] | ||||
|         device = volume_fakes.volume_attachment_server['device'] | ||||
|         msg = 'Attached to %s on %s ' % (server, device) | ||||
|  | ||||
|         datalist = (( | ||||
|             volume_fakes.volume_id, | ||||
|             volume_fakes.volume_name, | ||||
|             volume_fakes.volume_status, | ||||
|             volume_fakes.volume_size, | ||||
|             msg, | ||||
|         ), ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_volume_list_status(self): | ||||
|         arglist = [ | ||||
|             '--status', volume_fakes.volume_status, | ||||
|         ] | ||||
|         verifylist = [ | ||||
|             ('long', False), | ||||
|             ('all_projects', False), | ||||
|             ('name', None), | ||||
|             ('status', volume_fakes.volume_status), | ||||
|         ] | ||||
|         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = ( | ||||
|             'ID', | ||||
|             'Display Name', | ||||
|             'Status', | ||||
|             'Size', | ||||
|             'Attached to', | ||||
|         ) | ||||
|         self.assertEqual(collist, tuple(columns)) | ||||
|  | ||||
|         server = volume_fakes.volume_attachment_server['id'] | ||||
|         device = volume_fakes.volume_attachment_server['device'] | ||||
|         msg = 'Attached to %s on %s ' % (server, device) | ||||
|         datalist = (( | ||||
|             volume_fakes.volume_id, | ||||
|             volume_fakes.volume_name, | ||||
|             volume_fakes.volume_status, | ||||
|             volume_fakes.volume_size, | ||||
|             msg, | ||||
|         ), ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_volume_list_long(self): | ||||
|         arglist = [ | ||||
|             '--long', | ||||
|         ] | ||||
|         verifylist = [ | ||||
|             ('long', True), | ||||
|             ('all_projects', False), | ||||
|             ('name', None), | ||||
|             ('status', None), | ||||
|         ] | ||||
|  | ||||
|         parsed_args = self.check_parser(self.cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = [ | ||||
|             'ID', | ||||
|             'Display Name', | ||||
|             'Status', | ||||
|             'Size', | ||||
|             'Type', | ||||
|             'Bootable', | ||||
|             'Attached to', | ||||
|             'Properties', | ||||
|         ] | ||||
|         self.assertEqual(collist, columns) | ||||
|  | ||||
|         server = volume_fakes.volume_attachment_server['id'] | ||||
|         device = volume_fakes.volume_attachment_server['device'] | ||||
|         msg = 'Attached to %s on %s ' % (server, device) | ||||
|         datalist = (( | ||||
|             volume_fakes.volume_id, | ||||
|             volume_fakes.volume_name, | ||||
|             volume_fakes.volume_status, | ||||
|             volume_fakes.volume_size, | ||||
|             volume_fakes.volume_type, | ||||
|             '', | ||||
|             msg, | ||||
|             "Alpha='a', Beta='b', Gamma='g'", | ||||
|         ), ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|  | ||||
| class TestVolumeShow(TestVolume): | ||||
|     def setUp(self): | ||||
|         super(TestVolumeShow, self).setUp() | ||||
|   | ||||
| @@ -14,9 +14,12 @@ | ||||
|  | ||||
| """Volume V2 Volume action implementations""" | ||||
|  | ||||
| import copy | ||||
| import logging | ||||
| import os | ||||
|  | ||||
| from cliff import command | ||||
| from cliff import lister | ||||
| from cliff import show | ||||
| import six | ||||
|  | ||||
| @@ -189,6 +192,112 @@ class DeleteVolume(command.Command): | ||||
|         return | ||||
|  | ||||
|  | ||||
| class ListVolume(lister.Lister): | ||||
|     """List volumes""" | ||||
|  | ||||
|     log = logging.getLogger(__name__ + '.ListVolume') | ||||
|  | ||||
|     def get_parser(self, prog_name): | ||||
|         parser = super(ListVolume, self).get_parser(prog_name) | ||||
|         parser.add_argument( | ||||
|             '--all-projects', | ||||
|             action='store_true', | ||||
|             default=bool(int(os.environ.get("ALL_PROJECTS", 0))), | ||||
|             help='Include all projects (admin only)', | ||||
|         ) | ||||
|         parser.add_argument( | ||||
|             '--long', | ||||
|             action='store_true', | ||||
|             default=False, | ||||
|             help='List additional fields in output', | ||||
|         ) | ||||
|         parser.add_argument( | ||||
|             '--name', | ||||
|             metavar='<name>', | ||||
|             help='Filter results by name', | ||||
|         ) | ||||
|         parser.add_argument( | ||||
|             '--status', | ||||
|             metavar='<status>', | ||||
|             help='Filter results by status', | ||||
|         ) | ||||
|         return parser | ||||
|  | ||||
|     def take_action(self, parsed_args): | ||||
|         self.log.debug('take_action(%s)', parsed_args) | ||||
|  | ||||
|         volume_client = self.app.client_manager.volume | ||||
|         compute_client = self.app.client_manager.compute | ||||
|  | ||||
|         def _format_attach(attachments): | ||||
|             """Return a formatted string of a volume's attached instances | ||||
|  | ||||
|             :param volume: a volume.attachments field | ||||
|             :rtype: a string of formatted instances | ||||
|             """ | ||||
|  | ||||
|             msg = '' | ||||
|             for attachment in attachments: | ||||
|                 server = attachment['id'] | ||||
|                 if server in server_cache: | ||||
|                     server = server_cache[server].name | ||||
|                 device = attachment['device'] | ||||
|                 msg += 'Attached to %s on %s ' % (server, device) | ||||
|             return msg | ||||
|  | ||||
|         if parsed_args.long: | ||||
|             columns = [ | ||||
|                 'ID', | ||||
|                 'Name', | ||||
|                 'Status', | ||||
|                 'Size', | ||||
|                 'Volume Type', | ||||
|                 'Bootable', | ||||
|                 'Attachments', | ||||
|                 'Metadata', | ||||
|             ] | ||||
|             column_headers = copy.deepcopy(columns) | ||||
|             column_headers[1] = 'Display Name' | ||||
|             column_headers[4] = 'Type' | ||||
|             column_headers[6] = 'Attached to' | ||||
|             column_headers[7] = 'Properties' | ||||
|         else: | ||||
|             columns = [ | ||||
|                 'ID', | ||||
|                 'Name', | ||||
|                 'Status', | ||||
|                 'Size', | ||||
|                 'Attachments', | ||||
|                 ] | ||||
|             column_headers = copy.deepcopy(columns) | ||||
|             column_headers[1] = 'Display Name' | ||||
|             column_headers[4] = 'Attached to' | ||||
|  | ||||
|         # Cache the server list | ||||
|         server_cache = {} | ||||
|         try: | ||||
|             for s in compute_client.servers.list(): | ||||
|                 server_cache[s.id] = s | ||||
|         except Exception: | ||||
|             # Just forget it if there's any trouble | ||||
|             pass | ||||
|  | ||||
|         search_opts = { | ||||
|             'all_projects': parsed_args.all_projects, | ||||
|             'display_name': parsed_args.name, | ||||
|             'status': parsed_args.status, | ||||
|         } | ||||
|  | ||||
|         data = volume_client.volumes.list(search_opts=search_opts) | ||||
|  | ||||
|         return (column_headers, | ||||
|                 (utils.get_item_properties( | ||||
|                     s, columns, | ||||
|                     formatters={'Metadata': utils.format_dict, | ||||
|                                 'Attachments': _format_attach}, | ||||
|                 ) for s in data)) | ||||
|  | ||||
|  | ||||
| class SetVolume(show.ShowOne): | ||||
|     """Set volume properties""" | ||||
|  | ||||
|   | ||||
| @@ -393,6 +393,7 @@ openstack.volume.v2 = | ||||
|     snapshot_show = openstackclient.volume.v2.snapshot:ShowSnapshot | ||||
|     snapshot_unset = openstackclient.volume.v2.snapshot:UnsetSnapshot | ||||
|  | ||||
|     volume_list = openstackclient.volume.v2.volume:ListVolume | ||||
|     volume_create = openstackclient.volume.v2.volume:CreateVolume | ||||
|     volume_delete = openstackclient.volume.v2.volume:DeleteVolume | ||||
|     volume_set = openstackclient.volume.v2.volume:SetVolume | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 heha
					heha