diff options
author | Jay Faulkner <jay@jvf.cc> | 2023-02-01 14:54:03 -0800 |
---|---|---|
committer | Jay Faulkner <jay@jvf.cc> | 2023-02-13 11:46:21 -0800 |
commit | a0c1fd8888f283d741faf76774aac3373161be80 (patch) | |
tree | 5901424e2f3ce42daf8f78b487c3de69e1ef8628 /ironic | |
parent | 28167f18f85823d97a12460b6ba4a724b5e27486 (diff) | |
download | ironic-a0c1fd8888f283d741faf76774aac3373161be80.tar.gz |
Add support for filtering for sharded nodes
This request parameter will allow an operator to ask the question
"Do I need to assign shards to any of my nodes?".
Change-Id: I26b745e5ef2b320a8d8a0667ac61c080fcdcd576
Diffstat (limited to 'ironic')
-rw-r--r-- | ironic/api/controllers/v1/node.py | 30 | ||||
-rw-r--r-- | ironic/db/sqlalchemy/api.py | 3 | ||||
-rw-r--r-- | ironic/tests/unit/api/controllers/v1/test_node.py | 11 |
3 files changed, 34 insertions, 10 deletions
diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index 9a117a95f..1aa9cf9ca 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -2071,7 +2071,8 @@ class NodesController(rest.RestController): fields=None, fault=None, conductor_group=None, detail=None, conductor=None, owner=None, lessee=None, project=None, - description_contains=None, shard=None): + description_contains=None, shard=None, + sharded=None): if self.from_chassis and not chassis_uuid: raise exception.MissingParameterValue( _("Chassis id not specified.")) @@ -2112,7 +2113,8 @@ class NodesController(rest.RestController): 'project': project, 'description_contains': description_contains, 'retired': retired, - 'instance_uuid': instance_uuid + 'instance_uuid': instance_uuid, + 'sharded': sharded } filters = {} for key, value in possible_filters.items(): @@ -2257,14 +2259,14 @@ class NodesController(rest.RestController): detail=args.boolean, conductor=args.string, owner=args.string, description_contains=args.string, lessee=args.string, project=args.string, - shard=args.string_list) + shard=args.string_list, sharded=args.boolean) def get_all(self, chassis_uuid=None, instance_uuid=None, associated=None, maintenance=None, retired=None, provision_state=None, marker=None, limit=None, sort_key='id', sort_dir='asc', driver=None, fields=None, resource_class=None, fault=None, conductor_group=None, detail=None, conductor=None, owner=None, description_contains=None, lessee=None, - project=None, shard=None): + project=None, shard=None, sharded=None): """Retrieve a list of nodes. :param chassis_uuid: Optional UUID of a chassis, to get only nodes for @@ -2310,6 +2312,9 @@ class NodesController(rest.RestController): :param description_contains: Optional string value to get only nodes with description field contains matching value. + :param sharded: Optional boolean whether to return a list of + nodes with or without a shard set. May be combined + with other parameters. """ project = api_utils.check_list_policy('node', project) @@ -2325,6 +2330,8 @@ class NodesController(rest.RestController): api_utils.check_allow_filter_by_owner(owner) api_utils.check_allow_filter_by_lessee(lessee) api_utils.check_allow_filter_by_shard(shard) + # Sharded is guarded by the same API version as shard + api_utils.check_allow_filter_by_shard(sharded) fields = api_utils.get_request_return_fields(fields, detail, _DEFAULT_RETURN_FIELDS) @@ -2341,8 +2348,8 @@ class NodesController(rest.RestController): detail=detail, conductor=conductor, owner=owner, lessee=lessee, - shard=shard, project=project, - **extra_args) + shard=shard, sharded=sharded, + project=project, **extra_args) @METRICS.timer('NodesController.detail') @method.expose() @@ -2355,14 +2362,14 @@ class NodesController(rest.RestController): conductor_group=args.string, conductor=args.string, owner=args.string, description_contains=args.string, lessee=args.string, project=args.string, - shard=args.string_list) + shard=args.string_list, sharded=args.boolean) def detail(self, chassis_uuid=None, instance_uuid=None, associated=None, maintenance=None, retired=None, provision_state=None, marker=None, limit=None, sort_key='id', sort_dir='asc', driver=None, resource_class=None, fault=None, conductor_group=None, conductor=None, owner=None, description_contains=None, lessee=None, project=None, - shard=None): + shard=None, sharded=None): """Retrieve a list of nodes with detail. :param chassis_uuid: Optional UUID of a chassis, to get only nodes for @@ -2403,6 +2410,9 @@ class NodesController(rest.RestController): :param description_contains: Optional string value to get only nodes with description field contains matching value. + :param sharded: Optional boolean whether to return a list of + nodes with or without a shard set. May be combined + with other parameters. """ project = api_utils.check_list_policy('node', project) @@ -2421,6 +2431,8 @@ class NodesController(rest.RestController): api_utils.check_allow_filter_by_conductor(conductor) api_utils.check_allow_filter_by_shard(shard) + # Sharded is guarded by the same API version as shard + api_utils.check_allow_filter_by_shard(sharded) extra_args = {'description_contains': description_contains} return self._get_nodes_collection(chassis_uuid, instance_uuid, @@ -2435,7 +2447,7 @@ class NodesController(rest.RestController): conductor=conductor, owner=owner, lessee=lessee, project=project, shard=shard, - **extra_args) + sharded=sharded, **extra_args) @METRICS.timer('NodesController.validate') @method.expose() diff --git a/ironic/db/sqlalchemy/api.py b/ironic/db/sqlalchemy/api.py index 474a49ec5..de3934318 100644 --- a/ironic/db/sqlalchemy/api.py +++ b/ironic/db/sqlalchemy/api.py @@ -401,7 +401,8 @@ class Connection(api.Connection): for field in ('uuid', 'provision_state', 'shard')} _NODE_NON_NULL_FILTERS = {'associated': 'instance_uuid', 'reserved': 'reservation', - 'with_power_state': 'power_state'} + 'with_power_state': 'power_state', + 'sharded': 'shard'} _NODE_FILTERS = ({'chassis_uuid', 'reserved_by_any_of', 'provisioned_before', 'inspection_started_before', 'description_contains', 'project'} diff --git a/ironic/tests/unit/api/controllers/v1/test_node.py b/ironic/tests/unit/api/controllers/v1/test_node.py index e1ef916b9..1c4bf82d3 100644 --- a/ironic/tests/unit/api/controllers/v1/test_node.py +++ b/ironic/tests/unit/api/controllers/v1/test_node.py @@ -8028,6 +8028,17 @@ class TestNodeShardGets(test_api_base.BaseApiTest): expect_errors=True, headers=headers) self.assertEqual(http_client.NOT_ACCEPTABLE, result.status_code) + def test_filtering_by_sharded(self): + obj_utils.create_test_node(self.context, uuid=uuid.uuid4()) + obj_utils.create_test_node(self.context, uuid=uuid.uuid4()) + # We now have one node in shard foo (setUp) and two unsharded. + result_true = self.get_json( + '/nodes?sharded=true', headers=self.headers) + result_false = self.get_json( + '/nodes?sharded=false', headers=self.headers) + self.assertEqual(1, len(result_true['nodes'])) + self.assertEqual(2, len(result_false['nodes'])) + @mock.patch.object(rpcapi.ConductorAPI, 'create_node', lambda _api, _ctx, node, _topic: _create_node_locally(node)) |