Add '--fields' to show more columns for bay-list
This patch does: - move '_get_list_table_columns_and_formatters' function to cliutils. - add '--fields' to 'bay-list' command to show more specific fields. - add test case for bay-list with '--fields'. Change-Id: I2fdd66f0c6648bb2c6ae65325cbba3656b9854f6 Closes-Bug: #1535687
This commit is contained in:
parent
f1d97b652a
commit
d6a697cabb
magnumclient
@ -24,6 +24,7 @@ import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from magnumclient.common.apiclient import exceptions
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import strutils
|
||||
import prettytable
|
||||
@ -324,3 +325,60 @@ def make_field_formatter(attr, filters=None):
|
||||
name = _format_field_name(attr)
|
||||
formatter = get_field
|
||||
return name, formatter
|
||||
|
||||
|
||||
def _get_list_table_columns_and_formatters(fields, objs, exclude_fields=(),
|
||||
filters=None):
|
||||
"""Check and add fields to output columns.
|
||||
|
||||
If there is any value in fields that not an attribute of obj,
|
||||
CommandError will be raised.
|
||||
If fields has duplicate values (case sensitive), we will make them unique
|
||||
and ignore duplicate ones.
|
||||
:param fields: A list of string contains the fields to be printed.
|
||||
:param objs: An list of object which will be used to check if field is
|
||||
valid or not. Note, we don't check fields if obj is None or
|
||||
empty.
|
||||
:param exclude_fields: A tuple of string which contains the fields to be
|
||||
excluded.
|
||||
:param filters: A dictionary defines how to get value from fields, this
|
||||
is useful when field's value is a complex object such as
|
||||
dictionary.
|
||||
:return: columns, formatters.
|
||||
columns is a list of string which will be used as table header.
|
||||
formatters is a dictionary specifies how to display the value
|
||||
of the field.
|
||||
They can be [], {}.
|
||||
:raise: magnumclient.common.apiclient.exceptions.CommandError.
|
||||
"""
|
||||
|
||||
if objs and isinstance(objs, list):
|
||||
obj = objs[0]
|
||||
else:
|
||||
obj = None
|
||||
fields = None
|
||||
|
||||
columns = []
|
||||
formatters = {}
|
||||
|
||||
if fields:
|
||||
non_existent_fields = []
|
||||
exclude_fields = set(exclude_fields)
|
||||
|
||||
for field in fields.split(','):
|
||||
if not hasattr(obj, field):
|
||||
non_existent_fields.append(field)
|
||||
continue
|
||||
if field in exclude_fields:
|
||||
continue
|
||||
field_title, formatter = make_field_formatter(field, filters)
|
||||
columns.append(field_title)
|
||||
formatters[field_title] = formatter
|
||||
exclude_fields.add(field)
|
||||
|
||||
if non_existent_fields:
|
||||
raise exceptions.CommandError(
|
||||
_("Non-existent fields are specified: %s") %
|
||||
non_existent_fields
|
||||
)
|
||||
return columns, formatters
|
||||
|
@ -16,6 +16,21 @@ import mock
|
||||
|
||||
from magnumclient import exceptions
|
||||
from magnumclient.tests.v1 import shell_test_base
|
||||
from magnumclient.v1.bays import Bay
|
||||
|
||||
|
||||
class FakeBay(Bay):
|
||||
def __init__(self, manager=None, info={}, **kwargs):
|
||||
Bay.__init__(self, manager=manager, info=info)
|
||||
self.uuid = kwargs.get('uuid', 'x')
|
||||
self.name = kwargs.get('name', 'x')
|
||||
self.baymodel_id = kwargs.get('baymodel_id', 'x')
|
||||
self.stack_id = kwargs.get('stack_id', 'x')
|
||||
self.status = kwargs.get('status', 'x')
|
||||
self.master_count = kwargs.get('master_count', 1)
|
||||
self.node_count = kwargs.get('node_count', 1)
|
||||
self.links = kwargs.get('links', [])
|
||||
self.bay_create_timeout = kwargs.get('bay_create_timeout', 0)
|
||||
|
||||
|
||||
class ShellTest(shell_test_base.TestCommandLineArgument):
|
||||
@ -34,6 +49,29 @@ class ShellTest(shell_test_base.TestCommandLineArgument):
|
||||
'--sort-key uuid')
|
||||
self.assertTrue(mock_list.called)
|
||||
|
||||
@mock.patch('magnumclient.v1.bays.BayManager.list')
|
||||
def test_bay_list_ignored_duplicated_field(self, mock_list):
|
||||
mock_list.return_value = [FakeBay()]
|
||||
self._test_arg_success('bay-list --fields status,status,status,name',
|
||||
keyword='\n| uuid | name | Status |\n')
|
||||
# Output should be
|
||||
# +------+------+--------+
|
||||
# | uuid | name | Status |
|
||||
# +------+------+--------+
|
||||
# | x | x | x |
|
||||
# +------+------+--------+
|
||||
self.assertTrue(mock_list.called)
|
||||
|
||||
@mock.patch('magnumclient.v1.bays.BayManager.list')
|
||||
def test_bay_list_failure_with_invalid_field(self, mock_list):
|
||||
mock_list.return_value = [FakeBay()]
|
||||
_error_msg = [".*?^Non-existent fields are specified: ['xxx','zzz']"]
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self._test_arg_failure,
|
||||
'bay-list --fields xxx,stack_id,zzz,status',
|
||||
_error_msg)
|
||||
self.assertTrue(mock_list.called)
|
||||
|
||||
@mock.patch('magnumclient.v1.bays.BayManager.list')
|
||||
def test_bay_list_failure_invalid_arg(self, mock_list):
|
||||
_error_msg = [
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
import os.path
|
||||
|
||||
from magnumclient.common.apiclient import exceptions
|
||||
from magnumclient.common import cliutils as utils
|
||||
from magnumclient.common import utils as magnum_utils
|
||||
from magnumclient.i18n import _
|
||||
@ -175,7 +174,7 @@ def do_baymodel_list(cs, args):
|
||||
sort_key=args.sort_key,
|
||||
sort_dir=args.sort_dir)
|
||||
columns = ['uuid', 'name']
|
||||
columns += _get_list_table_columns_and_formatters(
|
||||
columns += utils._get_list_table_columns_and_formatters(
|
||||
args.fields, nodes,
|
||||
exclude_fields=(c.lower() for c in columns))[0]
|
||||
utils.print_list(nodes, columns,
|
||||
@ -207,60 +206,3 @@ def do_baymodel_update(cs, args):
|
||||
|
||||
baymodel = cs.baymodels.update(args.baymodel, patch)
|
||||
_show_baymodel(baymodel)
|
||||
|
||||
|
||||
def _get_list_table_columns_and_formatters(fields, objs, exclude_fields=(),
|
||||
filters=None):
|
||||
"""Check and add fields to output columns.
|
||||
|
||||
If there is any value in fields that not an attribute of obj,
|
||||
CommandError will be raised.
|
||||
If fields has duplicate values (case sensitive), we will make them unique
|
||||
and ignore duplicate ones.
|
||||
:param fields: A list of string contains the fields to be printed.
|
||||
:param objs: An list of object which will be used to check if field is
|
||||
valid or not. Note, we don't check fields if obj is None or
|
||||
empty.
|
||||
:param exclude_fields: A tuple of string which contains the fields to be
|
||||
excluded.
|
||||
:param filters: A dictionary defines how to get value from fields, this
|
||||
is useful when field's value is a complex object such as
|
||||
dictionary.
|
||||
:return: columns, formatters.
|
||||
columns is a list of string which will be used as table header.
|
||||
formatters is a dictionary specifies how to display the value
|
||||
of the field.
|
||||
They can be [], {}.
|
||||
:raise: magnumclient.common.apiclient.exceptions.CommandError.
|
||||
"""
|
||||
|
||||
if objs and isinstance(objs, list):
|
||||
obj = objs[0]
|
||||
else:
|
||||
obj = None
|
||||
fields = None
|
||||
|
||||
columns = []
|
||||
formatters = {}
|
||||
|
||||
if fields:
|
||||
non_existent_fields = []
|
||||
exclude_fields = set(exclude_fields)
|
||||
|
||||
for field in fields.split(','):
|
||||
if not hasattr(obj, field):
|
||||
non_existent_fields.append(field)
|
||||
continue
|
||||
if field in exclude_fields:
|
||||
continue
|
||||
field_title, formatter = utils.make_field_formatter(field, filters)
|
||||
columns.append(field_title)
|
||||
formatters[field_title] = formatter
|
||||
exclude_fields.add(field)
|
||||
|
||||
if non_existent_fields:
|
||||
raise exceptions.CommandError(
|
||||
_("Non-existent fields are specified: %s") %
|
||||
non_existent_fields
|
||||
)
|
||||
return columns, formatters
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
from magnumclient.common import cliutils as utils
|
||||
from magnumclient.common import utils as magnum_utils
|
||||
from magnumclient.i18n import _
|
||||
|
||||
|
||||
def _show_bay(bay):
|
||||
@ -37,12 +38,23 @@ def _show_bay(bay):
|
||||
metavar='<sort-dir>',
|
||||
choices=['desc', 'asc'],
|
||||
help='Direction to sort. "asc" or "desc".')
|
||||
@utils.arg('--fields',
|
||||
default=None,
|
||||
metavar='<fields>',
|
||||
help=_('Comma-separated list of fields to display. '
|
||||
'Available fields: uuid, name, baymodel_id, stack_id, '
|
||||
'status, master_count, node_count, links, bay_create_timeout'
|
||||
)
|
||||
)
|
||||
def do_bay_list(cs, args):
|
||||
"""Print a list of available bays."""
|
||||
bays = cs.bays.list(marker=args.marker, limit=args.limit,
|
||||
sort_key=args.sort_key,
|
||||
sort_dir=args.sort_dir)
|
||||
columns = ('uuid', 'name', 'node_count', 'master_count', 'status')
|
||||
columns = ['uuid', 'name']
|
||||
columns += utils._get_list_table_columns_and_formatters(
|
||||
args.fields, bays,
|
||||
exclude_fields=(c.lower() for c in columns))[0]
|
||||
utils.print_list(bays, columns,
|
||||
{'versions': magnum_utils.print_list_field('versions')},
|
||||
sortby_index=None)
|
||||
|
Loading…
x
Reference in New Issue
Block a user