Merge "Add list feature to volume v2"
This commit is contained in:
commit
8affa0d1c3
@ -2,7 +2,7 @@
|
|||||||
volume
|
volume
|
||||||
======
|
======
|
||||||
|
|
||||||
Volume v1
|
Volume v1, v2
|
||||||
|
|
||||||
volume create
|
volume create
|
||||||
-------------
|
-------------
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
import copy
|
import copy
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
from openstackclient.tests.compute.v2 import fakes as compute_fakes
|
||||||
from openstackclient.tests import fakes
|
from openstackclient.tests import fakes
|
||||||
from openstackclient.tests.identity.v2_0 import fakes as identity_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.image.v2 import fakes as image_fakes
|
||||||
from openstackclient.tests import utils
|
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_id = "ce26708d-a7f8-4b4b-9861-4a80256615a6"
|
||||||
volume_name = "fake_volume"
|
volume_name = "fake_volume"
|
||||||
volume_description = "fake description"
|
volume_description = "fake description"
|
||||||
@ -34,7 +38,7 @@ volume_metadata = {
|
|||||||
volume_metadata_str = "Alpha='a', Beta='b', Gamma='g'"
|
volume_metadata_str = "Alpha='a', Beta='b', Gamma='g'"
|
||||||
volume_snapshot_id = 1
|
volume_snapshot_id = 1
|
||||||
volume_availability_zone = "nova"
|
volume_availability_zone = "nova"
|
||||||
volume_attachments = ["fake_attachments"]
|
volume_attachments = [volume_attachment_server]
|
||||||
|
|
||||||
VOLUME = {
|
VOLUME = {
|
||||||
"id": volume_id,
|
"id": volume_id,
|
||||||
|
@ -495,6 +495,220 @@ class TestVolumeCreate(TestVolume):
|
|||||||
self.assertEqual(datalist, data)
|
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):
|
class TestVolumeShow(TestVolume):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestVolumeShow, self).setUp()
|
super(TestVolumeShow, self).setUp()
|
||||||
|
@ -14,9 +14,12 @@
|
|||||||
|
|
||||||
"""Volume V2 Volume action implementations"""
|
"""Volume V2 Volume action implementations"""
|
||||||
|
|
||||||
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from cliff import command
|
from cliff import command
|
||||||
|
from cliff import lister
|
||||||
from cliff import show
|
from cliff import show
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@ -189,6 +192,112 @@ class DeleteVolume(command.Command):
|
|||||||
return
|
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):
|
class SetVolume(show.ShowOne):
|
||||||
"""Set volume properties"""
|
"""Set volume properties"""
|
||||||
|
|
||||||
|
@ -393,6 +393,7 @@ openstack.volume.v2 =
|
|||||||
snapshot_show = openstackclient.volume.v2.snapshot:ShowSnapshot
|
snapshot_show = openstackclient.volume.v2.snapshot:ShowSnapshot
|
||||||
snapshot_unset = openstackclient.volume.v2.snapshot:UnsetSnapshot
|
snapshot_unset = openstackclient.volume.v2.snapshot:UnsetSnapshot
|
||||||
|
|
||||||
|
volume_list = openstackclient.volume.v2.volume:ListVolume
|
||||||
volume_create = openstackclient.volume.v2.volume:CreateVolume
|
volume_create = openstackclient.volume.v2.volume:CreateVolume
|
||||||
volume_delete = openstackclient.volume.v2.volume:DeleteVolume
|
volume_delete = openstackclient.volume.v2.volume:DeleteVolume
|
||||||
volume_set = openstackclient.volume.v2.volume:SetVolume
|
volume_set = openstackclient.volume.v2.volume:SetVolume
|
||||||
|
Loading…
Reference in New Issue
Block a user