Allow specifying a set of fields of the Node resource
This patch add a "--fields" parameter to the "node-list", "node-show" and "node-port-list" commands which the user can specify a subset of fields that will be returned by the server. This is supported by the Ironic API version >= 1.8, so this patch also bumps the default API version to 1.8. Related-Bug: #1466495 Change-Id: I40654ee9fbd92dd91b41f8596adcd26264634147
This commit is contained in:
parent
aea764b451
commit
0d8fa45b4b
ironicclient
@ -36,7 +36,7 @@ from ironicclient import exc
|
||||
# microversion support in the client properly! See
|
||||
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
|
||||
# for full details.
|
||||
DEFAULT_VER = '1.7'
|
||||
DEFAULT_VER = '1.8'
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -167,16 +167,24 @@ def common_params_for_list(args, fields, field_labels):
|
||||
|
||||
params['detail'] = args.detail
|
||||
|
||||
if hasattr(args, 'fields'):
|
||||
requested_fields = args.fields[0] if args.fields else None
|
||||
if requested_fields is not None:
|
||||
params['fields'] = requested_fields
|
||||
|
||||
return params
|
||||
|
||||
|
||||
def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None):
|
||||
def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None,
|
||||
fields=None):
|
||||
"""Generate common filters for any list request.
|
||||
|
||||
:param marker: entity ID from which to start returning entities.
|
||||
:param limit: maximum number of entities to return.
|
||||
:param sort_key: field to use for sorting.
|
||||
:param sort_dir: direction of sorting: 'asc' or 'desc'.
|
||||
:param fields: a list with a specified set of fields of the resource
|
||||
to be returned.
|
||||
:returns: list of string filters.
|
||||
"""
|
||||
filters = []
|
||||
@ -188,6 +196,8 @@ def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None):
|
||||
filters.append('sort_key=%s' % sort_key)
|
||||
if sort_dir is not None:
|
||||
filters.append('sort_dir=%s' % sort_dir)
|
||||
if fields is not None:
|
||||
filters.append('fields=%s' % ','.join(fields))
|
||||
return filters
|
||||
|
||||
|
||||
@ -277,3 +287,19 @@ def bool_argument_value(arg_name, bool_str, strict=True, default=False):
|
||||
raise exc.CommandError(_("argument %(arg)s: %(err)s.")
|
||||
% {'arg': arg_name, 'err': e})
|
||||
return val
|
||||
|
||||
|
||||
def check_for_invalid_fields(fields, valid_fields):
|
||||
"""Check for invalid fields.
|
||||
|
||||
:param fields: A list of fields specified by the user.
|
||||
:param valid_fields: A list of valid fields.
|
||||
raises: CommandError: If invalid fields were specified by the user.
|
||||
"""
|
||||
if not fields:
|
||||
return
|
||||
|
||||
invalid_attr = set(fields) - set(valid_fields)
|
||||
if invalid_attr:
|
||||
raise exc.CommandError(_('Invalid field(s): %s') %
|
||||
', '.join(invalid_attr))
|
||||
|
@ -114,13 +114,19 @@ class UtilsTest(test_utils.BaseTestCase):
|
||||
self.assertEqual('foo', utils.bool_argument_value('arg', 'ee',
|
||||
strict=False, default='foo'))
|
||||
|
||||
def test_check_for_invalid_fields(self):
|
||||
self.assertIsNone(utils.check_for_invalid_fields(
|
||||
['a', 'b'], ['a', 'b', 'c']))
|
||||
# 'd' is not a valid field
|
||||
self.assertRaises(exc.CommandError, utils.check_for_invalid_fields,
|
||||
['a', 'd'], ['a', 'b', 'c'])
|
||||
|
||||
|
||||
class CommonParamsForListTest(test_utils.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(CommonParamsForListTest, self).setUp()
|
||||
self.args = mock.Mock(marker=None, limit=None,
|
||||
sort_key=None, sort_dir=None)
|
||||
self.args.detail = False
|
||||
self.args = mock.Mock(marker=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False, spec=True)
|
||||
self.expected_params = {'detail': False}
|
||||
|
||||
def test_nothing_set(self):
|
||||
@ -179,6 +185,12 @@ class CommonParamsForListTest(test_utils.BaseTestCase):
|
||||
self.assertEqual(self.expected_params,
|
||||
utils.common_params_for_list(self.args, [], []))
|
||||
|
||||
def test_fields(self):
|
||||
self.args.fields = [['a', 'b', 'c']]
|
||||
self.expected_params.update({'fields': ['a', 'b', 'c']})
|
||||
self.assertEqual(self.expected_params,
|
||||
utils.common_params_for_list(self.args, [], []))
|
||||
|
||||
|
||||
class CommonFiltersTest(test_utils.BaseTestCase):
|
||||
def test_limit(self):
|
||||
@ -194,6 +206,10 @@ class CommonFiltersTest(test_utils.BaseTestCase):
|
||||
result = utils.common_filters(**{key: 'test'})
|
||||
self.assertEqual(['%s=test' % key], result)
|
||||
|
||||
def test_fields(self):
|
||||
result = utils.common_filters(fields=['a', 'b', 'c'])
|
||||
self.assertEqual(['fields=a,b,c'], result)
|
||||
|
||||
|
||||
@mock.patch.object(subprocess, 'Popen')
|
||||
class MakeConfigDriveTest(test_utils.BaseTestCase):
|
||||
|
@ -23,7 +23,7 @@ import ironicclient.v1.chassis_shell as c_shell
|
||||
class ChassisShellTest(utils.BaseTestCase):
|
||||
def _get_client_mock_args(self, chassis=None, marker=None, limit=None,
|
||||
sort_dir=None, sort_key=None, detail=False):
|
||||
args = mock.MagicMock()
|
||||
args = mock.MagicMock(spec=True)
|
||||
args.chassis = chassis
|
||||
args.marker = marker
|
||||
args.limit = limit
|
||||
|
@ -103,6 +103,13 @@ fake_responses = {
|
||||
{"nodes": [NODE1, NODE2]}
|
||||
),
|
||||
},
|
||||
'/v1/nodes/?fields=uuid,extra':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"nodes": [NODE1]}
|
||||
),
|
||||
},
|
||||
'/v1/nodes/?associated=False':
|
||||
{
|
||||
'GET': (
|
||||
@ -160,6 +167,13 @@ fake_responses = {
|
||||
UPDATED_NODE,
|
||||
),
|
||||
},
|
||||
'/v1/nodes/%s?fields=uuid,extra' % NODE1['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
NODE1,
|
||||
),
|
||||
},
|
||||
'/v1/nodes/%s' % NODE2['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
@ -188,6 +202,13 @@ fake_responses = {
|
||||
{"ports": [PORT]},
|
||||
),
|
||||
},
|
||||
'/v1/nodes/%s/ports?fields=uuid,address' % NODE1['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"ports": [PORT]},
|
||||
),
|
||||
},
|
||||
'/v1/nodes/%s/maintenance' % NODE1['uuid']:
|
||||
{
|
||||
'PUT': (
|
||||
@ -478,6 +499,18 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertEqual(2, len(nodes))
|
||||
self.assertEqual(nodes[0].extra, {})
|
||||
|
||||
def test_node_list_fields(self):
|
||||
nodes = self.mgr.list(fields=['uuid', 'extra'])
|
||||
expect = [
|
||||
('GET', '/v1/nodes/?fields=uuid,extra', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(nodes))
|
||||
|
||||
def test_node_list_detail_and_fields_fail(self):
|
||||
self.assertRaises(exc.InvalidAttribute, self.mgr.list,
|
||||
detail=True, fields=['uuid', 'extra'])
|
||||
|
||||
def test_node_show(self):
|
||||
node = self.mgr.get(NODE1['uuid'])
|
||||
expect = [
|
||||
@ -503,6 +536,15 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NODE1['uuid'], node.uuid)
|
||||
|
||||
def test_node_show_fields(self):
|
||||
node = self.mgr.get(NODE1['uuid'], fields=['uuid', 'extra'])
|
||||
expect = [
|
||||
('GET', '/v1/nodes/%s?fields=uuid,extra' %
|
||||
NODE1['uuid'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(NODE1['uuid'], node.uuid)
|
||||
|
||||
def test_create(self):
|
||||
node = self.mgr.create(**CREATE_NODE)
|
||||
expect = [
|
||||
@ -605,6 +647,19 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(ports))
|
||||
|
||||
def test_node_port_list_fields(self):
|
||||
ports = self.mgr.list_ports(NODE1['uuid'], fields=['uuid', 'address'])
|
||||
expect = [
|
||||
('GET', '/v1/nodes/%s/ports?fields=uuid,address' %
|
||||
NODE1['uuid'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(ports))
|
||||
|
||||
def test_node_port_list_detail_and_fields_fail(self):
|
||||
self.assertRaises(exc.InvalidAttribute, self.mgr.list_ports,
|
||||
NODE1['uuid'], detail=True, fields=['uuid', 'extra'])
|
||||
|
||||
def test_node_set_maintenance_true(self):
|
||||
maintenance = self.mgr.set_maintenance(NODE1['uuid'], 'true',
|
||||
maint_reason='reason')
|
||||
|
@ -160,9 +160,10 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
args = mock.MagicMock()
|
||||
args.node = 'node_uuid'
|
||||
args.instance_uuid = False
|
||||
args.fields = None
|
||||
|
||||
n_shell.do_node_show(client_mock, args)
|
||||
client_mock.node.get.assert_called_once_with('node_uuid')
|
||||
client_mock.node.get.assert_called_once_with('node_uuid', fields=None)
|
||||
# assert get_by_instance_uuid() wasn't called
|
||||
self.assertFalse(client_mock.node.get_by_instance_uuid.called)
|
||||
|
||||
@ -171,10 +172,11 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
args = mock.MagicMock()
|
||||
args.node = 'instance_uuid'
|
||||
args.instance_uuid = True
|
||||
args.fields = None
|
||||
|
||||
n_shell.do_node_show(client_mock, args)
|
||||
client_mock.node.get_by_instance_uuid.assert_called_once_with(
|
||||
'instance_uuid')
|
||||
'instance_uuid', fields=None)
|
||||
# assert get() wasn't called
|
||||
self.assertFalse(client_mock.node.get.called)
|
||||
|
||||
@ -214,6 +216,25 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
n_shell.do_node_show,
|
||||
client_mock, args)
|
||||
|
||||
def test_do_node_show_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.node = 'node_uuid'
|
||||
args.instance_uuid = False
|
||||
args.fields = [['uuid', 'power_state']]
|
||||
n_shell.do_node_show(client_mock, args)
|
||||
client_mock.node.get.assert_called_once_with(
|
||||
'node_uuid', fields=['uuid', 'power_state'])
|
||||
|
||||
def test_do_node_show_invalid_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.node = 'node_uuid'
|
||||
args.instance_uuid = False
|
||||
args.fields = [['foo', 'bar']]
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
n_shell.do_node_show, client_mock, args)
|
||||
|
||||
def test_do_node_set_maintenance_true(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
@ -464,10 +485,12 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
client_mock.node.get_supported_boot_devices.assert_called_once_with(
|
||||
'node_uuid')
|
||||
|
||||
def _get_client_mock_args(self, associated=None, maintenance=None,
|
||||
marker=None, limit=None, sort_dir=None,
|
||||
sort_key=None, detail=False):
|
||||
def _get_client_mock_args(self, node=None, associated=None,
|
||||
maintenance=None, marker=None, limit=None,
|
||||
sort_dir=None, sort_key=None, detail=False,
|
||||
fields=None):
|
||||
args = mock.MagicMock()
|
||||
args.node = node
|
||||
args.associated = associated
|
||||
args.maintenance = maintenance
|
||||
args.marker = marker
|
||||
@ -475,6 +498,7 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
args.sort_dir = sort_dir
|
||||
args.sort_key = sort_key
|
||||
args.detail = detail
|
||||
args.fields = fields
|
||||
|
||||
return args
|
||||
|
||||
@ -530,6 +554,19 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
client_mock, args)
|
||||
self.assertFalse(client_mock.node.list.called)
|
||||
|
||||
def test_do_node_list_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = self._get_client_mock_args(fields=[['uuid', 'provision_state']])
|
||||
n_shell.do_node_list(client_mock, args)
|
||||
client_mock.node.list.assert_called_once_with(
|
||||
fields=['uuid', 'provision_state'], detail=False)
|
||||
|
||||
def test_do_node_list_invalid_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = self._get_client_mock_args(fields=[['foo', 'bar']])
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
n_shell.do_node_list, client_mock, args)
|
||||
|
||||
def test_do_node_show_states(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
@ -537,3 +574,20 @@ class NodeShellTest(utils.BaseTestCase):
|
||||
|
||||
n_shell.do_node_show_states(client_mock, args)
|
||||
client_mock.node.states.assert_called_once_with('node_uuid')
|
||||
|
||||
def test_do_node_port_list_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
node_mock = mock.MagicMock(spec_set=[])
|
||||
args = self._get_client_mock_args(node=node_mock,
|
||||
fields=[['uuid', 'address']])
|
||||
n_shell.do_node_port_list(client_mock, args)
|
||||
client_mock.node.list_ports.assert_called_once_with(
|
||||
node_mock, fields=['uuid', 'address'], detail=False)
|
||||
|
||||
def test_do_node_port_list_invalid_fields(self):
|
||||
client_mock = mock.MagicMock()
|
||||
node_mock = mock.MagicMock(spec_set=[])
|
||||
args = self._get_client_mock_args(node=node_mock,
|
||||
fields=[['foo', 'bar']])
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
n_shell.do_node_port_list, client_mock, args)
|
||||
|
@ -87,7 +87,7 @@ class PortShellTest(utils.BaseTestCase):
|
||||
|
||||
def _get_client_mock_args(self, address=None, marker=None, limit=None,
|
||||
sort_dir=None, sort_key=None, detail=False):
|
||||
args = mock.MagicMock()
|
||||
args = mock.MagicMock(spec=True)
|
||||
args.address = address
|
||||
args.marker = marker
|
||||
args.limit = limit
|
||||
|
@ -38,7 +38,7 @@ class NodeManager(base.Manager):
|
||||
return '/v1/nodes/%s' % id if id else '/v1/nodes'
|
||||
|
||||
def list(self, associated=None, maintenance=None, marker=None, limit=None,
|
||||
detail=False, sort_key=None, sort_dir=None):
|
||||
detail=False, sort_key=None, sort_dir=None, fields=None):
|
||||
"""Retrieve a list of nodes.
|
||||
|
||||
:param associated: Optional. Either a Boolean or a string
|
||||
@ -70,13 +70,22 @@ class NodeManager(base.Manager):
|
||||
:param sort_dir: Optional, direction of sorting, either 'asc' (the
|
||||
default) or 'desc'.
|
||||
|
||||
:param fields: Optional, a list with a specified set of fields
|
||||
of the resource to be returned. Can not be used
|
||||
when 'detail' is set.
|
||||
|
||||
:returns: A list of nodes.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(marker, limit, sort_key, sort_dir)
|
||||
if detail and fields:
|
||||
raise exc.InvalidAttribute(_("Can't fetch a subset of fields "
|
||||
"with 'detail' set"))
|
||||
|
||||
filters = utils.common_filters(marker, limit, sort_key, sort_dir,
|
||||
fields)
|
||||
if associated is not None:
|
||||
filters.append('associated=%s' % associated)
|
||||
if maintenance is not None:
|
||||
@ -95,7 +104,7 @@ class NodeManager(base.Manager):
|
||||
limit=limit)
|
||||
|
||||
def list_ports(self, node_id, marker=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
sort_dir=None, detail=False, fields=None):
|
||||
"""List all the ports for a given node.
|
||||
|
||||
:param node_id: The UUID of the node.
|
||||
@ -119,13 +128,22 @@ class NodeManager(base.Manager):
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about ports.
|
||||
|
||||
:param fields: Optional, a list with a specified set of fields
|
||||
of the resource to be returned. Can not be used
|
||||
when 'detail' is set.
|
||||
|
||||
:returns: A list of ports.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(marker, limit, sort_key, sort_dir)
|
||||
if detail and fields:
|
||||
raise exc.InvalidAttribute(_("Can't fetch a subset of fields "
|
||||
"with 'detail' set"))
|
||||
|
||||
filters = utils.common_filters(marker, limit, sort_key, sort_dir,
|
||||
fields)
|
||||
|
||||
path = "%s/ports" % node_id
|
||||
if detail:
|
||||
@ -140,14 +158,23 @@ class NodeManager(base.Manager):
|
||||
return self._list_pagination(self._path(path), "ports",
|
||||
limit=limit)
|
||||
|
||||
def get(self, node_id):
|
||||
def get(self, node_id, fields=None):
|
||||
if fields is not None:
|
||||
node_id = '%s?fields=' % node_id
|
||||
node_id += ','.join(fields)
|
||||
|
||||
try:
|
||||
return self._list(self._path(node_id))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def get_by_instance_uuid(self, instance_uuid):
|
||||
path = "detail?instance_uuid=%s" % instance_uuid
|
||||
def get_by_instance_uuid(self, instance_uuid, fields=None):
|
||||
path = '?instance_uuid=%s' % instance_uuid
|
||||
if fields is not None:
|
||||
path += '&fields=' + ','.join(fields)
|
||||
else:
|
||||
path = 'detail' + path
|
||||
|
||||
nodes = self._list(self._path(path), 'nodes')
|
||||
# get all the details of the node assuming that
|
||||
# filtering by instance_uuid returns a collection
|
||||
|
@ -24,10 +24,12 @@ from ironicclient.openstack.common import cliutils
|
||||
from ironicclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_node_show(node):
|
||||
def _print_node_show(node, fields=None):
|
||||
if fields is None:
|
||||
fields = res_fields.NODE_DETAILED_RESOURCE.fields
|
||||
|
||||
data = dict(
|
||||
[(f, getattr(node, f, ''))
|
||||
for f in res_fields.NODE_DETAILED_RESOURCE.fields])
|
||||
[(f, getattr(node, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
|
||||
|
||||
@ -42,14 +44,26 @@ def _print_node_show(node):
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='<id> is an instance UUID.')
|
||||
@cliutils.arg(
|
||||
'--fields',
|
||||
nargs='+',
|
||||
dest='fields',
|
||||
metavar='<field>',
|
||||
action='append',
|
||||
default=[],
|
||||
help="One or more node fields. Only these fields will be fetched from "
|
||||
"the server.")
|
||||
def do_node_show(cc, args):
|
||||
"""Show detailed information about a node."""
|
||||
fields = args.fields[0] if args.fields else None
|
||||
utils.check_empty_arg(args.node, '<id>')
|
||||
utils.check_for_invalid_fields(
|
||||
fields, res_fields.NODE_DETAILED_RESOURCE.fields)
|
||||
if args.instance_uuid:
|
||||
node = cc.node.get_by_instance_uuid(args.node)
|
||||
node = cc.node.get_by_instance_uuid(args.node, fields=fields)
|
||||
else:
|
||||
node = cc.node.get(args.node)
|
||||
_print_node_show(node)
|
||||
node = cc.node.get(args.node, fields=fields)
|
||||
_print_node_show(node, fields=fields)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
@ -87,6 +101,15 @@ def do_node_show(cc, args):
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about the nodes.")
|
||||
@cliutils.arg(
|
||||
'--fields',
|
||||
nargs='+',
|
||||
dest='fields',
|
||||
metavar='<field>',
|
||||
action='append',
|
||||
default=[],
|
||||
help="One or more node fields. Only these fields will be fetched from "
|
||||
"the server. Can not be used when '--detail' is specified.")
|
||||
def do_node_list(cc, args):
|
||||
"""List the nodes which are registered with the Ironic service."""
|
||||
params = {}
|
||||
@ -103,6 +126,14 @@ def do_node_list(cc, args):
|
||||
field_labels = res_fields.NODE_DETAILED_RESOURCE.labels
|
||||
sort_fields = res_fields.NODE_DETAILED_RESOURCE.sort_fields
|
||||
sort_field_labels = res_fields.NODE_DETAILED_RESOURCE.sort_labels
|
||||
elif args.fields:
|
||||
utils.check_for_invalid_fields(
|
||||
args.fields[0], res_fields.NODE_DETAILED_RESOURCE.fields)
|
||||
resource = res_fields.Resource(args.fields[0])
|
||||
fields = resource.fields
|
||||
field_labels = resource.labels
|
||||
sort_fields = res_fields.NODE_DETAILED_RESOURCE.sort_fields
|
||||
sort_field_labels = res_fields.NODE_DETAILED_RESOURCE.sort_labels
|
||||
else:
|
||||
fields = res_fields.NODE_RESOURCE.fields
|
||||
field_labels = res_fields.NODE_RESOURCE.labels
|
||||
@ -276,11 +307,26 @@ def do_node_vendor_passthru(cc, args):
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
@cliutils.arg('node', metavar='<node>', help="UUID of the node.")
|
||||
@cliutils.arg(
|
||||
'--fields',
|
||||
nargs='+',
|
||||
dest='fields',
|
||||
metavar='<field>',
|
||||
action='append',
|
||||
default=[],
|
||||
help="One or more port fields. Only these fields will be fetched from "
|
||||
"the server. Can not be used when '--detail' is specified.")
|
||||
def do_node_port_list(cc, args):
|
||||
"""List the ports associated with a node."""
|
||||
if args.detail:
|
||||
fields = res_fields.PORTS_DETAILED_RESOURCE.fields
|
||||
field_labels = res_fields.PORTS_DETAILED_RESOURCE.labels
|
||||
elif args.fields:
|
||||
utils.check_for_invalid_fields(
|
||||
args.fields[0], res_fields.PORT_DETAILED_RESOURCE.fields)
|
||||
resource = res_fields.Resource(args.fields[0])
|
||||
fields = resource.fields
|
||||
field_labels = resource.labels
|
||||
else:
|
||||
fields = res_fields.PORT_RESOURCE.fields
|
||||
field_labels = res_fields.PORT_RESOURCE.labels
|
||||
|
Loading…
x
Reference in New Issue
Block a user