diff --git a/ironicclient/tests/unit/v1/test_chassis.py b/ironicclient/tests/unit/v1/test_chassis.py index eed9f154f..edec1390a 100644 --- a/ironicclient/tests/unit/v1/test_chassis.py +++ b/ironicclient/tests/unit/v1/test_chassis.py @@ -36,6 +36,7 @@ CHASSIS2 = {'id': 43, NODE = {'id': 123, 'uuid': '66666666-7777-8888-9999-000000000000', 'chassis_id': 42, + 'provision_state': 'available', 'driver': 'fake', 'driver_info': {'user': 'foo', 'password': 'bar'}, 'properties': {'num_cpu': 4}, @@ -118,6 +119,27 @@ fake_responses = { {"nodes": [NODE]}, ), }, + '/v1/chassis/%s/nodes?associated=True' % CHASSIS['uuid']: + { + 'GET': ( + {}, + {"nodes": [NODE]}, + ) + }, + '/v1/chassis/%s/nodes?maintenance=False' % CHASSIS['uuid']: + { + 'GET': ( + {}, + {"nodes": [NODE]}, + ) + }, + '/v1/chassis/%s/nodes?provision_state=available' % CHASSIS['uuid']: + { + 'GET': ( + {}, + {"nodes": [NODE]}, + ) + }, } fake_responses_pagination = { @@ -350,6 +372,34 @@ class ChassisManagerTest(testtools.TestCase): self.assertEqual(expect, self.api.calls) self.assertEqual(1, len(nodes)) + def test_chassis_node_list_maintenance(self): + nodes = self.mgr.list_nodes(CHASSIS['uuid'], maintenance=False) + expect = [ + ('GET', '/v1/chassis/%s/nodes?maintenance=False' % + CHASSIS['uuid'], {}, None), + ] + self.assertEqual(expect, self.api.calls) + self.assertEqual(1, len(nodes)) + + def test_chassis_node_list_associated(self): + nodes = self.mgr.list_nodes(CHASSIS['uuid'], associated=True) + expect = [ + ('GET', '/v1/chassis/%s/nodes?associated=True' % + CHASSIS['uuid'], {}, None), + ] + self.assertEqual(expect, self.api.calls) + self.assertEqual(1, len(nodes)) + + def test_chassis_node_list_provision_state(self): + nodes = self.mgr.list_nodes(CHASSIS['uuid'], + provision_state="available") + expect = [ + ('GET', '/v1/chassis/%s/nodes?provision_state=available' % + CHASSIS['uuid'], {}, None), + ] + self.assertEqual(expect, self.api.calls) + self.assertEqual(1, len(nodes)) + def test_chassis_node_list_detail_and_fields_fail(self): self.assertRaises(exc.InvalidAttribute, self.mgr.list_nodes, CHASSIS['uuid'], detail=True, diff --git a/ironicclient/tests/unit/v1/test_chassis_shell.py b/ironicclient/tests/unit/v1/test_chassis_shell.py index bf9ec5541..ed1239514 100644 --- a/ironicclient/tests/unit/v1/test_chassis_shell.py +++ b/ironicclient/tests/unit/v1/test_chassis_shell.py @@ -24,7 +24,8 @@ 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, - fields=None): + fields=None, associated=None, maintenance=None, + provision_state=None): args = mock.MagicMock(spec=True) args.chassis = chassis args.marker = marker @@ -33,6 +34,9 @@ class ChassisShellTest(utils.BaseTestCase): args.sort_key = sort_key args.detail = detail args.fields = fields + args.associated = associated + args.maintenance = maintenance + args.provision_state = provision_state return args @@ -259,6 +263,33 @@ class ChassisShellTest(utils.BaseTestCase): client_mock.chassis.list_nodes.assert_called_once_with( chassis_mock, fields=['uuid', 'power_state'], detail=False) + def test_do_chassis_node_list_associated(self): + client_mock = mock.MagicMock() + chassis_mock = mock.MagicMock(spec_set=[]) + args = self._get_client_mock_args(chassis=chassis_mock, + associated=True) + c_shell.do_chassis_node_list(client_mock, args) + client_mock.chassis.list_nodes.assert_called_once_with( + chassis_mock, associated=True, detail=False) + + def test_do_chassis_node_list_maintenance(self): + client_mock = mock.MagicMock() + chassis_mock = mock.MagicMock(spec_set=[]) + args = self._get_client_mock_args(chassis=chassis_mock, + maintenance=True) + c_shell.do_chassis_node_list(client_mock, args) + client_mock.chassis.list_nodes.assert_called_once_with( + chassis_mock, maintenance=True, detail=False) + + def test_do_chassis_node_list_provision_state(self): + client_mock = mock.MagicMock() + chassis_mock = mock.MagicMock(spec_set=[]) + args = self._get_client_mock_args(chassis=chassis_mock, + provision_state='wait call-back') + c_shell.do_chassis_node_list(client_mock, args) + client_mock.chassis.list_nodes.assert_called_once_with( + chassis_mock, provision_state='wait call-back', detail=False) + def test_do_chassis_node_list_invalid_fields(self): client_mock = mock.MagicMock() chassis_mock = mock.MagicMock(spec_set=[]) diff --git a/ironicclient/v1/chassis.py b/ironicclient/v1/chassis.py index 666d0518f..27b87ec9c 100644 --- a/ironicclient/v1/chassis.py +++ b/ironicclient/v1/chassis.py @@ -89,7 +89,8 @@ class ChassisManager(base.Manager): limit=limit) def list_nodes(self, chassis_id, marker=None, limit=None, - sort_key=None, sort_dir=None, detail=False, fields=None): + sort_key=None, sort_dir=None, detail=False, fields=None, + associated=None, maintenance=None, provision_state=None): """List all the nodes for a given chassis. :param chassis_id: The UUID of the chassis. @@ -117,6 +118,20 @@ class ChassisManager(base.Manager): of the resource to be returned. Can not be used when 'detail' is set. + :param associated: Optional. Either a Boolean or a string + representation of a Boolean that indicates whether + to return a list of associated (True or "True") or + unassociated (False or "False") nodes. + + :param maintenance: Optional. Either a Boolean or a string + representation of a Boolean that indicates whether + to return nodes in maintenance mode (True or + "True"), or not in maintenance mode (False or + "False"). + + :param provision_state: Optional. String value to get only nodes in + that provision state. + :returns: A list of nodes. """ @@ -130,6 +145,13 @@ class ChassisManager(base.Manager): 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: + filters.append('maintenance=%s' % maintenance) + if provision_state is not None: + filters.append('provision_state=%s' % provision_state) + path = "%s/nodes" % chassis_id if detail: path += '/detail' diff --git a/ironicclient/v1/chassis_shell.py b/ironicclient/v1/chassis_shell.py index 8d6ee3596..053e0f0ee 100644 --- a/ironicclient/v1/chassis_shell.py +++ b/ironicclient/v1/chassis_shell.py @@ -206,8 +206,30 @@ def do_chassis_update(cc, args): default=[], help="One or more node fields. Only these fields will be fetched from " "the server. Can not be used when '--detail' is specified.") +@cliutils.arg( + '--maintenance', + metavar='', + help="List nodes in maintenance mode: 'true' or 'false'.") +@cliutils.arg( + '--associated', + metavar='', + help="List nodes by instance association: 'true' or 'false'.") +@cliutils.arg( + '--provision-state', + metavar='', + help="List nodes in specified provision state.") def do_chassis_node_list(cc, args): """List the nodes contained in a chassis.""" + params = {} + if args.associated is not None: + params['associated'] = utils.bool_argument_value("--associated", + args.associated) + if args.maintenance is not None: + params['maintenance'] = utils.bool_argument_value("--maintenance", + args.maintenance) + if args.provision_state is not None: + params['provision_state'] = args.provision_state + if args.detail: fields = res_fields.NODE_DETAILED_RESOURCE.fields field_labels = res_fields.NODE_DETAILED_RESOURCE.labels @@ -221,7 +243,9 @@ def do_chassis_node_list(cc, args): fields = res_fields.NODE_RESOURCE.fields field_labels = res_fields.NODE_RESOURCE.labels - params = utils.common_params_for_list(args, fields, field_labels) + params.update(utils.common_params_for_list(args, + fields, + field_labels)) nodes = cc.chassis.list_nodes(args.chassis, **params) cliutils.print_list(nodes, fields,