Support list-volume for group show
V3.25 support query groups with volumes, this patch add the client support. Partial-Implements: blueprint improvement-to-query-consistency-group-detail Partial-Bug: #1663474 Change-Id: Ic0d86b9265f295877eebca97ff450f5efd73b184
This commit is contained in:
@@ -403,9 +403,14 @@ class ManagerWithFind(six.with_metaclass(abc.ABCMeta, Manager)):
|
|||||||
search_opts['display_name'] = kwargs['display_name']
|
search_opts['display_name'] = kwargs['display_name']
|
||||||
|
|
||||||
found = common_base.ListWithMeta([], None)
|
found = common_base.ListWithMeta([], None)
|
||||||
|
# list_volume is used for group query, it's not resource's property.
|
||||||
|
list_volume = kwargs.pop('list_volume', False)
|
||||||
searches = kwargs.items()
|
searches = kwargs.items()
|
||||||
|
if list_volume:
|
||||||
listing = self.list(search_opts=search_opts)
|
listing = self.list(search_opts=search_opts,
|
||||||
|
list_volume=list_volume)
|
||||||
|
else:
|
||||||
|
listing = self.list(search_opts=search_opts)
|
||||||
found.append_request_ids(listing.request_ids)
|
found.append_request_ids(listing.request_ids)
|
||||||
# Not all resources attributes support filters on server side
|
# Not all resources attributes support filters on server side
|
||||||
# (e.g. 'human_id' doesn't), so when doing findall some client
|
# (e.g. 'human_id' doesn't), so when doing findall some client
|
||||||
|
@@ -85,9 +85,10 @@ def find_consistencygroup(cs, consistencygroup):
|
|||||||
return utils.find_resource(cs.consistencygroups, consistencygroup)
|
return utils.find_resource(cs.consistencygroups, consistencygroup)
|
||||||
|
|
||||||
|
|
||||||
def find_group(cs, group):
|
def find_group(cs, group, **kwargs):
|
||||||
"""Gets a group by name or ID."""
|
"""Gets a group by name or ID."""
|
||||||
return utils.find_resource(cs.groups, group)
|
kwargs['is_group'] = True
|
||||||
|
return utils.find_resource(cs.groups, group, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def find_cgsnapshot(cs, cgsnapshot):
|
def find_cgsnapshot(cs, cgsnapshot):
|
||||||
|
@@ -53,13 +53,13 @@ class FakeManager(base.ManagerWithFind):
|
|||||||
FakeResource('5678', {'name': '9876'})
|
FakeResource('5678', {'name': '9876'})
|
||||||
]
|
]
|
||||||
|
|
||||||
def get(self, resource_id):
|
def get(self, resource_id, **kwargs):
|
||||||
for resource in self.resources:
|
for resource in self.resources:
|
||||||
if resource.id == str(resource_id):
|
if resource.id == str(resource_id):
|
||||||
return resource
|
return resource
|
||||||
raise exceptions.NotFound(resource_id)
|
raise exceptions.NotFound(resource_id)
|
||||||
|
|
||||||
def list(self, search_opts):
|
def list(self, search_opts, **kwargs):
|
||||||
return common_base.ListWithMeta(self.resources, fakes.REQUEST_ID)
|
return common_base.ListWithMeta(self.resources, fakes.REQUEST_ID)
|
||||||
|
|
||||||
|
|
||||||
@@ -132,6 +132,18 @@ class FindResourceTestCase(test_utils.TestCase):
|
|||||||
output = utils.find_resource(display_manager, 'entity_three')
|
output = utils.find_resource(display_manager, 'entity_three')
|
||||||
self.assertEqual(display_manager.get('4242'), output)
|
self.assertEqual(display_manager.get('4242'), output)
|
||||||
|
|
||||||
|
def test_find_by_group_id(self):
|
||||||
|
output = utils.find_resource(self.manager, 1234, is_group=True,
|
||||||
|
list_volume=True)
|
||||||
|
self.assertEqual(self.manager.get('1234', list_volume=True), output)
|
||||||
|
|
||||||
|
def test_find_by_group_name(self):
|
||||||
|
display_manager = FakeDisplayManager(None)
|
||||||
|
output = utils.find_resource(display_manager, 'entity_three',
|
||||||
|
is_group=True, list_volume=True)
|
||||||
|
self.assertEqual(display_manager.get('4242', list_volume=True),
|
||||||
|
output)
|
||||||
|
|
||||||
|
|
||||||
class CaptureStdout(object):
|
class CaptureStdout(object):
|
||||||
"""Context manager for capturing stdout from statements in its block."""
|
"""Context manager for capturing stdout from statements in its block."""
|
||||||
|
@@ -101,6 +101,11 @@ class GroupsTest(utils.TestCase):
|
|||||||
cs.assert_called('GET', '/groups/detail?foo=bar')
|
cs.assert_called('GET', '/groups/detail?foo=bar')
|
||||||
self._assert_request_id(lst)
|
self._assert_request_id(lst)
|
||||||
|
|
||||||
|
def test_list_group_with_volume(self):
|
||||||
|
lst = cs.groups.list(list_volume=True)
|
||||||
|
cs.assert_called('GET', '/groups/detail?list_volume=True')
|
||||||
|
self._assert_request_id(lst)
|
||||||
|
|
||||||
def test_list_group_with_empty_search_opt(self):
|
def test_list_group_with_empty_search_opt(self):
|
||||||
lst = cs.groups.list(
|
lst = cs.groups.list(
|
||||||
search_opts={'foo': 'bar', 'abc': None}
|
search_opts={'foo': 'bar', 'abc': None}
|
||||||
@@ -114,6 +119,12 @@ class GroupsTest(utils.TestCase):
|
|||||||
cs.assert_called('GET', '/groups/%s' % group_id)
|
cs.assert_called('GET', '/groups/%s' % group_id)
|
||||||
self._assert_request_id(grp)
|
self._assert_request_id(grp)
|
||||||
|
|
||||||
|
def test_get_group_with_list_volume(self):
|
||||||
|
group_id = '1234'
|
||||||
|
grp = cs.groups.get(group_id, list_volume=True)
|
||||||
|
cs.assert_called('GET', '/groups/%s?list_volume=True' % group_id)
|
||||||
|
self._assert_request_id(grp)
|
||||||
|
|
||||||
def test_create_group_from_src_snap(self):
|
def test_create_group_from_src_snap(self):
|
||||||
grp = cs.groups.create_from_src('5678', None, name='group')
|
grp = cs.groups.create_from_src('5678', None, name='group')
|
||||||
expected = {
|
expected = {
|
||||||
|
@@ -329,6 +329,11 @@ class ShellTest(utils.TestCase):
|
|||||||
'group-show 1234')
|
'group-show 1234')
|
||||||
self.assert_called('GET', '/groups/1234')
|
self.assert_called('GET', '/groups/1234')
|
||||||
|
|
||||||
|
def test_group_show_with_list_volume(self):
|
||||||
|
self.run_command('--os-volume-api-version 3.25 '
|
||||||
|
'group-show 1234 --list-volume')
|
||||||
|
self.assert_called('GET', '/groups/1234?list_volume=True')
|
||||||
|
|
||||||
@ddt.data(True, False)
|
@ddt.data(True, False)
|
||||||
def test_group_delete(self, delete_vol):
|
def test_group_delete(self, delete_vol):
|
||||||
cmd = '--os-volume-api-version 3.13 group-delete 1234'
|
cmd = '--os-volume-api-version 3.13 group-delete 1234'
|
||||||
|
@@ -220,11 +220,14 @@ def print_dict(d, property="Property", formatters=None):
|
|||||||
_print(pt, property)
|
_print(pt, property)
|
||||||
|
|
||||||
|
|
||||||
def find_resource(manager, name_or_id):
|
def find_resource(manager, name_or_id, **kwargs):
|
||||||
"""Helper for the _find_* methods."""
|
"""Helper for the _find_* methods."""
|
||||||
|
is_group = kwargs.pop('is_group', False)
|
||||||
# first try to get entity as integer id
|
# first try to get entity as integer id
|
||||||
try:
|
try:
|
||||||
if isinstance(name_or_id, int) or name_or_id.isdigit():
|
if isinstance(name_or_id, int) or name_or_id.isdigit():
|
||||||
|
if is_group:
|
||||||
|
return manager.get(int(name_or_id), **kwargs)
|
||||||
return manager.get(int(name_or_id))
|
return manager.get(int(name_or_id))
|
||||||
except exceptions.NotFound:
|
except exceptions.NotFound:
|
||||||
pass
|
pass
|
||||||
@@ -232,6 +235,8 @@ def find_resource(manager, name_or_id):
|
|||||||
# now try to get entity as uuid
|
# now try to get entity as uuid
|
||||||
try:
|
try:
|
||||||
uuid.UUID(name_or_id)
|
uuid.UUID(name_or_id)
|
||||||
|
if is_group:
|
||||||
|
return manager.get(name_or_id, **kwargs)
|
||||||
return manager.get(name_or_id)
|
return manager.get(name_or_id)
|
||||||
except (ValueError, exceptions.NotFound):
|
except (ValueError, exceptions.NotFound):
|
||||||
pass
|
pass
|
||||||
@@ -243,12 +248,18 @@ def find_resource(manager, name_or_id):
|
|||||||
try:
|
try:
|
||||||
resource = getattr(manager, 'resource_class', None)
|
resource = getattr(manager, 'resource_class', None)
|
||||||
name_attr = resource.NAME_ATTR if resource else 'name'
|
name_attr = resource.NAME_ATTR if resource else 'name'
|
||||||
|
if is_group:
|
||||||
|
kwargs[name_attr] = name_or_id
|
||||||
|
return manager.find(**kwargs)
|
||||||
return manager.find(**{name_attr: name_or_id})
|
return manager.find(**{name_attr: name_or_id})
|
||||||
except exceptions.NotFound:
|
except exceptions.NotFound:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# finally try to find entity by human_id
|
# finally try to find entity by human_id
|
||||||
try:
|
try:
|
||||||
|
if is_group:
|
||||||
|
kwargs['human_id'] = name_or_id
|
||||||
|
return manager.find(**kwargs)
|
||||||
return manager.find(human_id=name_or_id)
|
return manager.find(human_id=name_or_id)
|
||||||
except exceptions.NotFound:
|
except exceptions.NotFound:
|
||||||
msg = "No %s with a name or ID of '%s' exists." % \
|
msg = "No %s with a name or ID of '%s' exists." % \
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
"""Group interface (v3 extension)."""
|
"""Group interface (v3 extension)."""
|
||||||
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
from cinderclient import api_versions
|
from cinderclient import api_versions
|
||||||
from cinderclient import base
|
from cinderclient import base
|
||||||
@@ -106,20 +107,31 @@ class GroupManager(base.ManagerWithFind):
|
|||||||
"/groups/action", body=body)
|
"/groups/action", body=body)
|
||||||
return common_base.DictWithMeta(body['group'], resp)
|
return common_base.DictWithMeta(body['group'], resp)
|
||||||
|
|
||||||
def get(self, group_id):
|
def get(self, group_id, **kwargs):
|
||||||
"""Get a group.
|
"""Get a group.
|
||||||
|
|
||||||
:param group_id: The ID of the group to get.
|
:param group_id: The ID of the group to get.
|
||||||
:rtype: :class:`Group`
|
:rtype: :class:`Group`
|
||||||
"""
|
"""
|
||||||
return self._get("/groups/%s" % group_id,
|
query_params = utils.unicode_key_value_to_string(kwargs)
|
||||||
|
|
||||||
|
query_string = ""
|
||||||
|
if query_params:
|
||||||
|
params = sorted(query_params.items(), key=lambda x: x[0])
|
||||||
|
query_string = "?%s" % parse.urlencode(params)
|
||||||
|
|
||||||
|
return self._get("/groups/%s" % group_id + query_string,
|
||||||
"group")
|
"group")
|
||||||
|
|
||||||
def list(self, detailed=True, search_opts=None):
|
def list(self, detailed=True, search_opts=None, list_volume=False):
|
||||||
"""Lists all groups.
|
"""Lists all groups.
|
||||||
|
|
||||||
:rtype: list of :class:`Group`
|
:rtype: list of :class:`Group`
|
||||||
"""
|
"""
|
||||||
|
if list_volume:
|
||||||
|
if not search_opts:
|
||||||
|
search_opts = {}
|
||||||
|
search_opts['list_volume'] = True
|
||||||
query_string = utils.build_query_param(search_opts)
|
query_string = utils.build_query_param(search_opts)
|
||||||
|
|
||||||
detail = ""
|
detail = ""
|
||||||
|
@@ -831,13 +831,26 @@ def do_group_list(cs, args):
|
|||||||
|
|
||||||
|
|
||||||
@api_versions.wraps('3.13')
|
@api_versions.wraps('3.13')
|
||||||
|
@utils.arg('--list-volume',
|
||||||
|
dest='list_volume',
|
||||||
|
metavar='<False|True>',
|
||||||
|
nargs='?',
|
||||||
|
type=bool,
|
||||||
|
const=True,
|
||||||
|
default=False,
|
||||||
|
help='Shows volumes included in the group.',
|
||||||
|
start_version='3.25')
|
||||||
@utils.arg('group',
|
@utils.arg('group',
|
||||||
metavar='<group>',
|
metavar='<group>',
|
||||||
help='Name or ID of a group.')
|
help='Name or ID of a group.')
|
||||||
def do_group_show(cs, args):
|
def do_group_show(cs, args):
|
||||||
"""Shows details of a group."""
|
"""Shows details of a group."""
|
||||||
info = dict()
|
info = dict()
|
||||||
group = shell_utils.find_group(cs, args.group)
|
if getattr(args, 'list_volume', None):
|
||||||
|
group = shell_utils.find_group(cs, args.group,
|
||||||
|
list_volume=args.list_volume)
|
||||||
|
else:
|
||||||
|
group = shell_utils.find_group(cs, args.group)
|
||||||
info.update(group._info)
|
info.update(group._info)
|
||||||
|
|
||||||
info.pop('links', None)
|
info.pop('links', None)
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Support show group with ``list-volume`` argument.
|
||||||
|
The command is : cinder group-show {group_id} --list-volume
|
Reference in New Issue
Block a user