Merge "Add list feature to volume v2"
This commit is contained in:
commit
8affa0d1c3
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user