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
This commit is contained in:
parent
28167f18f8
commit
a0c1fd8888
@ -286,7 +286,7 @@ provision state, and maintenance setting for each Node.
|
|||||||
Introduced the ``lessee`` field.
|
Introduced the ``lessee`` field.
|
||||||
|
|
||||||
.. versionadded:: 1.82
|
.. versionadded:: 1.82
|
||||||
Introduced the ``shard`` field.
|
Introduced the ``shard`` field. Introduced the ``sharded`` request parameter.
|
||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
@ -309,6 +309,7 @@ Request
|
|||||||
- owner: owner
|
- owner: owner
|
||||||
- lessee: lessee
|
- lessee: lessee
|
||||||
- shard: req_shard
|
- shard: req_shard
|
||||||
|
- sharded: req_sharded
|
||||||
- description_contains: r_description_contains
|
- description_contains: r_description_contains
|
||||||
- fields: fields
|
- fields: fields
|
||||||
- limit: limit
|
- limit: limit
|
||||||
@ -381,7 +382,7 @@ Nova instance, eg. with a request to ``v1/nodes/detail?instance_uuid={NOVA INSTA
|
|||||||
Introduced the ``lessee`` field.
|
Introduced the ``lessee`` field.
|
||||||
|
|
||||||
.. versionadded:: 1.82
|
.. versionadded:: 1.82
|
||||||
Introduced the ``shard`` field.
|
Introduced the ``shard`` field. Introduced the ``sharded`` request parameter.
|
||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
@ -404,6 +405,7 @@ Request
|
|||||||
- owner: owner
|
- owner: owner
|
||||||
- lessee: lessee
|
- lessee: lessee
|
||||||
- shard: req_shard
|
- shard: req_shard
|
||||||
|
- sharded: req_sharded
|
||||||
- description_contains: r_description_contains
|
- description_contains: r_description_contains
|
||||||
- limit: limit
|
- limit: limit
|
||||||
- marker: marker
|
- marker: marker
|
||||||
|
@ -1827,6 +1827,13 @@ req_shard:
|
|||||||
in: body
|
in: body
|
||||||
required: false
|
required: false
|
||||||
type: array
|
type: array
|
||||||
|
req_sharded:
|
||||||
|
description: |
|
||||||
|
When true, filter the list of returned Nodes, and only return the ones with
|
||||||
|
a non-null ``shard`` value. When false, the inverse filter is performed.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
req_standalone_ports_supported:
|
req_standalone_ports_supported:
|
||||||
description: |
|
description: |
|
||||||
Indicates whether ports that are members of this portgroup can be
|
Indicates whether ports that are members of this portgroup can be
|
||||||
|
@ -2071,7 +2071,8 @@ class NodesController(rest.RestController):
|
|||||||
fields=None, fault=None, conductor_group=None,
|
fields=None, fault=None, conductor_group=None,
|
||||||
detail=None, conductor=None, owner=None,
|
detail=None, conductor=None, owner=None,
|
||||||
lessee=None, project=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:
|
if self.from_chassis and not chassis_uuid:
|
||||||
raise exception.MissingParameterValue(
|
raise exception.MissingParameterValue(
|
||||||
_("Chassis id not specified."))
|
_("Chassis id not specified."))
|
||||||
@ -2112,7 +2113,8 @@ class NodesController(rest.RestController):
|
|||||||
'project': project,
|
'project': project,
|
||||||
'description_contains': description_contains,
|
'description_contains': description_contains,
|
||||||
'retired': retired,
|
'retired': retired,
|
||||||
'instance_uuid': instance_uuid
|
'instance_uuid': instance_uuid,
|
||||||
|
'sharded': sharded
|
||||||
}
|
}
|
||||||
filters = {}
|
filters = {}
|
||||||
for key, value in possible_filters.items():
|
for key, value in possible_filters.items():
|
||||||
@ -2257,14 +2259,14 @@ class NodesController(rest.RestController):
|
|||||||
detail=args.boolean, conductor=args.string,
|
detail=args.boolean, conductor=args.string,
|
||||||
owner=args.string, description_contains=args.string,
|
owner=args.string, description_contains=args.string,
|
||||||
lessee=args.string, project=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,
|
def get_all(self, chassis_uuid=None, instance_uuid=None, associated=None,
|
||||||
maintenance=None, retired=None, provision_state=None,
|
maintenance=None, retired=None, provision_state=None,
|
||||||
marker=None, limit=None, sort_key='id', sort_dir='asc',
|
marker=None, limit=None, sort_key='id', sort_dir='asc',
|
||||||
driver=None, fields=None, resource_class=None, fault=None,
|
driver=None, fields=None, resource_class=None, fault=None,
|
||||||
conductor_group=None, detail=None, conductor=None,
|
conductor_group=None, detail=None, conductor=None,
|
||||||
owner=None, description_contains=None, lessee=None,
|
owner=None, description_contains=None, lessee=None,
|
||||||
project=None, shard=None):
|
project=None, shard=None, sharded=None):
|
||||||
"""Retrieve a list of nodes.
|
"""Retrieve a list of nodes.
|
||||||
|
|
||||||
:param chassis_uuid: Optional UUID of a chassis, to get only nodes for
|
: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
|
:param description_contains: Optional string value to get only nodes
|
||||||
with description field contains matching
|
with description field contains matching
|
||||||
value.
|
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)
|
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_owner(owner)
|
||||||
api_utils.check_allow_filter_by_lessee(lessee)
|
api_utils.check_allow_filter_by_lessee(lessee)
|
||||||
api_utils.check_allow_filter_by_shard(shard)
|
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,
|
fields = api_utils.get_request_return_fields(fields, detail,
|
||||||
_DEFAULT_RETURN_FIELDS)
|
_DEFAULT_RETURN_FIELDS)
|
||||||
@ -2341,8 +2348,8 @@ class NodesController(rest.RestController):
|
|||||||
detail=detail,
|
detail=detail,
|
||||||
conductor=conductor,
|
conductor=conductor,
|
||||||
owner=owner, lessee=lessee,
|
owner=owner, lessee=lessee,
|
||||||
shard=shard, project=project,
|
shard=shard, sharded=sharded,
|
||||||
**extra_args)
|
project=project, **extra_args)
|
||||||
|
|
||||||
@METRICS.timer('NodesController.detail')
|
@METRICS.timer('NodesController.detail')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
@ -2355,14 +2362,14 @@ class NodesController(rest.RestController):
|
|||||||
conductor_group=args.string, conductor=args.string,
|
conductor_group=args.string, conductor=args.string,
|
||||||
owner=args.string, description_contains=args.string,
|
owner=args.string, description_contains=args.string,
|
||||||
lessee=args.string, project=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,
|
def detail(self, chassis_uuid=None, instance_uuid=None, associated=None,
|
||||||
maintenance=None, retired=None, provision_state=None,
|
maintenance=None, retired=None, provision_state=None,
|
||||||
marker=None, limit=None, sort_key='id', sort_dir='asc',
|
marker=None, limit=None, sort_key='id', sort_dir='asc',
|
||||||
driver=None, resource_class=None, fault=None,
|
driver=None, resource_class=None, fault=None,
|
||||||
conductor_group=None, conductor=None, owner=None,
|
conductor_group=None, conductor=None, owner=None,
|
||||||
description_contains=None, lessee=None, project=None,
|
description_contains=None, lessee=None, project=None,
|
||||||
shard=None):
|
shard=None, sharded=None):
|
||||||
"""Retrieve a list of nodes with detail.
|
"""Retrieve a list of nodes with detail.
|
||||||
|
|
||||||
:param chassis_uuid: Optional UUID of a chassis, to get only nodes for
|
: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
|
:param description_contains: Optional string value to get only nodes
|
||||||
with description field contains matching
|
with description field contains matching
|
||||||
value.
|
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)
|
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_conductor(conductor)
|
||||||
api_utils.check_allow_filter_by_shard(shard)
|
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}
|
extra_args = {'description_contains': description_contains}
|
||||||
return self._get_nodes_collection(chassis_uuid, instance_uuid,
|
return self._get_nodes_collection(chassis_uuid, instance_uuid,
|
||||||
@ -2435,7 +2447,7 @@ class NodesController(rest.RestController):
|
|||||||
conductor=conductor,
|
conductor=conductor,
|
||||||
owner=owner, lessee=lessee,
|
owner=owner, lessee=lessee,
|
||||||
project=project, shard=shard,
|
project=project, shard=shard,
|
||||||
**extra_args)
|
sharded=sharded, **extra_args)
|
||||||
|
|
||||||
@METRICS.timer('NodesController.validate')
|
@METRICS.timer('NodesController.validate')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
|
@ -401,7 +401,8 @@ class Connection(api.Connection):
|
|||||||
for field in ('uuid', 'provision_state', 'shard')}
|
for field in ('uuid', 'provision_state', 'shard')}
|
||||||
_NODE_NON_NULL_FILTERS = {'associated': 'instance_uuid',
|
_NODE_NON_NULL_FILTERS = {'associated': 'instance_uuid',
|
||||||
'reserved': 'reservation',
|
'reserved': 'reservation',
|
||||||
'with_power_state': 'power_state'}
|
'with_power_state': 'power_state',
|
||||||
|
'sharded': 'shard'}
|
||||||
_NODE_FILTERS = ({'chassis_uuid', 'reserved_by_any_of',
|
_NODE_FILTERS = ({'chassis_uuid', 'reserved_by_any_of',
|
||||||
'provisioned_before', 'inspection_started_before',
|
'provisioned_before', 'inspection_started_before',
|
||||||
'description_contains', 'project'}
|
'description_contains', 'project'}
|
||||||
|
@ -8028,6 +8028,17 @@ class TestNodeShardGets(test_api_base.BaseApiTest):
|
|||||||
expect_errors=True, headers=headers)
|
expect_errors=True, headers=headers)
|
||||||
self.assertEqual(http_client.NOT_ACCEPTABLE, result.status_code)
|
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',
|
@mock.patch.object(rpcapi.ConductorAPI, 'create_node',
|
||||||
lambda _api, _ctx, node, _topic: _create_node_locally(node))
|
lambda _api, _ctx, node, _topic: _create_node_locally(node))
|
||||||
|
Loading…
Reference in New Issue
Block a user