Merge "Add support for fields in drivers CLI"
This commit is contained in:
commit
6f1be0651b
@ -37,7 +37,7 @@ from ironicclient import exc
|
||||
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
|
||||
# for full details.
|
||||
DEFAULT_VER = '1.9'
|
||||
LAST_KNOWN_API_VERSION = 76
|
||||
LAST_KNOWN_API_VERSION = 77
|
||||
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -12,8 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
|
||||
from osc_lib.command import command
|
||||
@ -39,11 +38,23 @@ class ListBaremetalDriver(command.Lister):
|
||||
help='Type of driver ("classic" or "dynamic"). '
|
||||
'The default is to list all of them.'
|
||||
)
|
||||
parser.add_argument(
|
||||
display_group = parser.add_mutually_exclusive_group()
|
||||
display_group.add_argument(
|
||||
'--long',
|
||||
action='store_true',
|
||||
default=None,
|
||||
help="Show detailed information about the drivers.")
|
||||
display_group.add_argument(
|
||||
'--fields',
|
||||
nargs='+',
|
||||
dest='fields',
|
||||
metavar='<field>',
|
||||
action='append',
|
||||
default=[],
|
||||
choices=res_fields.DRIVER_DETAILED_RESOURCE.fields,
|
||||
help=_("One or more node fields. Only these fields will be "
|
||||
"fetched from the server. Can not be used when '--long' "
|
||||
"is specified."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@ -55,6 +66,12 @@ class ListBaremetalDriver(command.Lister):
|
||||
if parsed_args.long:
|
||||
labels = res_fields.DRIVER_DETAILED_RESOURCE.labels
|
||||
columns = res_fields.DRIVER_DETAILED_RESOURCE.fields
|
||||
elif parsed_args.fields:
|
||||
fields = itertools.chain.from_iterable(parsed_args.fields)
|
||||
resource = res_fields.Resource(list(fields))
|
||||
columns = resource.fields
|
||||
labels = resource.labels
|
||||
params['fields'] = columns
|
||||
else:
|
||||
labels = res_fields.DRIVER_RESOURCE.labels
|
||||
columns = res_fields.DRIVER_RESOURCE.fields
|
||||
@ -213,13 +230,26 @@ class ShowBaremetalDriver(command.ShowOne):
|
||||
'driver',
|
||||
metavar='<driver>',
|
||||
help=_('Name of the driver.'))
|
||||
parser.add_argument(
|
||||
'--fields',
|
||||
nargs='+',
|
||||
dest='fields',
|
||||
metavar='<field>',
|
||||
action='append',
|
||||
default=[],
|
||||
choices=res_fields.DRIVER_DETAILED_RESOURCE.fields,
|
||||
help=_("One or more node fields. Only these fields will be "
|
||||
"fetched from the server."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
|
||||
driver = baremetal_client.driver.get(parsed_args.driver)._info
|
||||
fields = list(itertools.chain.from_iterable(parsed_args.fields))
|
||||
fields = fields if fields else None
|
||||
driver = baremetal_client.driver.get(parsed_args.driver,
|
||||
fields=fields)._info
|
||||
driver.pop("links", None)
|
||||
driver.pop("properties", None)
|
||||
# For list-type properties, show the values as comma separated
|
||||
|
@ -146,6 +146,69 @@ class TestListBaremetalDriver(TestBaremetalDriver):
|
||||
),)
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
def test_baremetal_driver_list_fields(self):
|
||||
arglist = [
|
||||
'--fields', 'name', 'hosts'
|
||||
]
|
||||
verifylist = [
|
||||
('fields', [['name', 'hosts']])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
kwargs = {
|
||||
'driver_type': None,
|
||||
'detail': None,
|
||||
'fields': ('name', 'hosts')
|
||||
}
|
||||
|
||||
self.baremetal_mock.driver.list.assert_called_with(**kwargs)
|
||||
|
||||
def test_baremetal_driver_list_fields_multiple(self):
|
||||
arglist = [
|
||||
'--fields', 'name',
|
||||
'--fields', 'hosts', 'type'
|
||||
]
|
||||
verifylist = [
|
||||
('fields', [['name'], ['hosts', 'type']])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
kwargs = {
|
||||
'driver_type': None,
|
||||
'detail': None,
|
||||
'fields': ('name', 'hosts', 'type')
|
||||
}
|
||||
|
||||
self.baremetal_mock.driver.list.assert_called_with(**kwargs)
|
||||
|
||||
def test_baremetal_driver_list_invalid_fields(self):
|
||||
arglist = [
|
||||
'--fields', 'name', 'invalid'
|
||||
]
|
||||
verifylist = [
|
||||
('fields', [['name', 'invalid']])
|
||||
]
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_driver_list_fields_with_long(self):
|
||||
arglist = [
|
||||
'--fields', 'name', 'hosts',
|
||||
'--long'
|
||||
]
|
||||
verifylist = [
|
||||
('fields', [['name', 'invalid']]),
|
||||
('long', True)
|
||||
]
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
|
||||
class TestListBaremetalDriverProperty(TestBaremetalDriver):
|
||||
|
||||
@ -362,7 +425,7 @@ class TestShowBaremetalDriver(TestBaremetalDriver):
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
args = ['fakedrivername']
|
||||
self.baremetal_mock.driver.get.assert_called_with(*args)
|
||||
self.baremetal_mock.driver.get.assert_called_with(*args, fields=None)
|
||||
self.assertFalse(self.baremetal_mock.driver.properties.called)
|
||||
|
||||
collist = ('default_bios_interface', 'default_boot_interface',
|
||||
@ -420,3 +483,54 @@ class TestShowBaremetalDriver(TestBaremetalDriver):
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_driver_show_fields(self):
|
||||
arglist = [
|
||||
'fakedrivername',
|
||||
'--fields', 'name', 'hosts'
|
||||
]
|
||||
verifylist = [
|
||||
('driver', 'fakedrivername'),
|
||||
('fields', [['name', 'hosts']])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
args = ['fakedrivername']
|
||||
fields = ['name', 'hosts']
|
||||
self.baremetal_mock.driver.get.assert_called_with(*args, fields=fields)
|
||||
self.assertFalse(self.baremetal_mock.driver.properties.called)
|
||||
|
||||
def test_baremetal_driver_show_fields_multiple(self):
|
||||
arglist = [
|
||||
'fakedrivername',
|
||||
'--fields', 'name',
|
||||
'--fields', 'hosts', 'type'
|
||||
]
|
||||
verifylist = [
|
||||
('driver', 'fakedrivername'),
|
||||
('fields', [['name'], ['hosts', 'type']])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
args = ['fakedrivername']
|
||||
fields = ['name', 'hosts', 'type']
|
||||
self.baremetal_mock.driver.get.assert_called_with(*args, fields=fields)
|
||||
self.assertFalse(self.baremetal_mock.driver.properties.called)
|
||||
|
||||
def test_baremetal_driver_show_invalid_fields(self):
|
||||
arglist = [
|
||||
'fakedrivername',
|
||||
'--fields', 'name', 'invalid'
|
||||
]
|
||||
verifylist = [
|
||||
('driver', 'fakedrivername'),
|
||||
('fields', [['name', 'invalid']])
|
||||
]
|
||||
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
@ -77,6 +77,13 @@ fake_responses = {
|
||||
{'drivers': [DRIVER1]},
|
||||
),
|
||||
},
|
||||
'/v1/drivers/?fields=name,hosts':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{'drivers': [DRIVER1]}
|
||||
)
|
||||
},
|
||||
'/v1/drivers/%s' % DRIVER1['name']:
|
||||
{
|
||||
'GET': (
|
||||
@ -84,6 +91,13 @@ fake_responses = {
|
||||
DRIVER1
|
||||
),
|
||||
},
|
||||
'/v1/drivers/%s?fields=name,hosts' % DRIVER1['name']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
DRIVER1,
|
||||
),
|
||||
},
|
||||
'/v1/drivers/%s/properties' % DRIVER2['name']:
|
||||
{
|
||||
'GET': (
|
||||
@ -136,6 +150,24 @@ class DriverManagerTest(testtools.TestCase):
|
||||
|
||||
self.assertEqual(DRIVER1, driver_attr)
|
||||
|
||||
def test_driver_list_fields(self):
|
||||
drivers = self.mgr.list(fields=['name', 'hosts'])
|
||||
expect = [
|
||||
('GET', '/v1/drivers/?fields=name,hosts', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(drivers, matchers.HasLength(1))
|
||||
|
||||
def test_driver_show_fields(self):
|
||||
driver_ = self.mgr.get(DRIVER1['name'], fields=['name', 'hosts'])
|
||||
expect = [
|
||||
('GET', '/v1/drivers/%s?fields=name,hosts' %
|
||||
DRIVER1['name'], {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(DRIVER1['name'], driver_.name)
|
||||
self.assertEqual(DRIVER1['hosts'], driver_.hosts)
|
||||
|
||||
def test_driver_properties(self):
|
||||
properties = self.mgr.properties(DRIVER2['name'])
|
||||
expect = [
|
||||
|
@ -28,7 +28,7 @@ class DriverManager(base.Manager):
|
||||
_resource_name = 'drivers'
|
||||
|
||||
def list(self, driver_type=None, detail=None, os_ironic_api_version=None,
|
||||
global_request_id=None):
|
||||
global_request_id=None, fields=None):
|
||||
"""Retrieve a list of drivers.
|
||||
|
||||
:param driver_type: Optional, string to filter the drivers by type.
|
||||
@ -41,13 +41,22 @@ class DriverManager(base.Manager):
|
||||
the request. If not specified, the client's default is used.
|
||||
:param global_request_id: String containing global request ID header
|
||||
value (in form "req-<UUID>") to use for the request.
|
||||
: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 drivers.
|
||||
"""
|
||||
|
||||
filters = []
|
||||
if detail and fields:
|
||||
raise exc.InvalidAttribute(_("Can't fetch a subset of fields "
|
||||
"with 'detail' set"))
|
||||
if driver_type is not None:
|
||||
filters.append('type=%s' % driver_type)
|
||||
if detail is not None:
|
||||
filters.append('detail=%s' % detail)
|
||||
if fields is not None:
|
||||
filters.append('fields=%s' % ','.join(fields))
|
||||
|
||||
path = ''
|
||||
if filters:
|
||||
@ -57,8 +66,8 @@ class DriverManager(base.Manager):
|
||||
global_request_id=global_request_id)
|
||||
|
||||
def get(self, driver_name, os_ironic_api_version=None,
|
||||
global_request_id=None):
|
||||
return self._get(resource_id=driver_name,
|
||||
global_request_id=None, fields=None):
|
||||
return self._get(resource_id=driver_name, fields=fields,
|
||||
os_ironic_api_version=os_ironic_api_version,
|
||||
global_request_id=global_request_id)
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for fields selector in driver cli.
|
||||
See `story 1674775
|
||||
<https://storyboard.openstack.org/#!/story/1674775>`_.
|
||||
|
||||
* ``openstack baremetal driver list --fields <field> [<field> ...]``
|
||||
* ``openstack baremetal driver show <driver_name> --fields <field> [<field> ...]``
|
Loading…
Reference in New Issue
Block a user