Support filtering resource providers by aggregate membership

This provides the backend for allowing an HTTP query of
'/resource_providers?member_of=in:$uuid_1,$uuid_2,$uuid_3'
which will return those resource providers which are members of any
of the listed aggregates.

This is done by extending the ResourceProvider.get_all_by_filters
methods to accept an additional 'member_of' filter with a value
of a list of aggregate uuids.

Change-Id: I1a69f7426b23f7b118bac7877b64700e688e8c6d
This commit is contained in:
Chris Dent 2016-12-06 17:55:51 +00:00 committed by Jay Pipes
parent aa77e0bd17
commit a29b1ee419
2 changed files with 58 additions and 1 deletions

View File

@ -540,7 +540,7 @@ class ResourceProviderList(base.ObjectListBase, base.NovaObject):
}
allowed_filters = (
'name', 'uuid'
'name', 'uuid', 'member_of'
)
@staticmethod
@ -550,6 +550,7 @@ class ResourceProviderList(base.ObjectListBase, base.NovaObject):
# filters = {
# 'name': <name>,
# 'uuid': <uuid>,
# 'member_of': [<aggregate_uuid>, <aggregate_uuid>]
# 'resources': {
# 'VCPU': 1,
# 'MEMORY_MB': 1024
@ -564,6 +565,7 @@ class ResourceProviderList(base.ObjectListBase, base.NovaObject):
name = filters.pop('name', None)
uuid = filters.pop('uuid', None)
can_host = filters.pop('can_host', 0)
member_of = filters.pop('member_of', [])
resources = filters.pop('resources', {})
# NOTE(sbauza): We want to key the dict by the resource class IDs
@ -577,6 +579,19 @@ class ResourceProviderList(base.ObjectListBase, base.NovaObject):
query = query.filter(models.ResourceProvider.uuid == uuid)
query = query.filter(models.ResourceProvider.can_host == can_host)
# If 'member_of' has values join with the PlacementAggregates to
# get those resource providers that are associated with any of the
# list of aggregate uuids provided with 'member_of'.
if member_of:
join_statement = sa.join(_AGG_TBL, _RP_AGG_TBL, sa.and_(
_AGG_TBL.c.id == _RP_AGG_TBL.c.aggregate_id,
_AGG_TBL.c.uuid.in_(member_of)))
resource_provider_id = _RP_AGG_TBL.c.resource_provider_id
rps_in_aggregates = sa.select(
[resource_provider_id]).select_from(join_statement)
query = query.filter(models.ResourceProvider.id.in_(
rps_in_aggregates))
if not resources:
# Returns quickly the list in case we don't need to check the
# resource usage

View File

@ -637,6 +637,48 @@ class ResourceProviderListTestCase(ResourceProviderBaseCase):
objects.ResourceProviderList.get_all_by_filters,
self.context, {'resources': {'FOOBAR': 3}})
def test_get_all_by_filters_aggregate(self):
for rp_i in [1, 2, 3, 4]:
uuid = getattr(uuidsentinel, 'rp_uuid_' + str(rp_i))
name = 'rp_name_' + str(rp_i)
rp = objects.ResourceProvider(self.context, name=name, uuid=uuid)
rp.create()
if rp_i % 2:
aggregate_uuids = [uuidsentinel.agg_a, uuidsentinel.agg_b]
rp.set_aggregates(aggregate_uuids)
resource_providers = objects.ResourceProviderList.get_all_by_filters(
self.context, filters={'member_of': [uuidsentinel.agg_a]})
self.assertEqual(2, len(resource_providers))
names = [_rp.name for _rp in resource_providers]
self.assertIn('rp_name_1', names)
self.assertIn('rp_name_3', names)
self.assertNotIn('rp_name_2', names)
self.assertNotIn('rp_name_4', names)
resource_providers = objects.ResourceProviderList.get_all_by_filters(
self.context, filters={'member_of':
[uuidsentinel.agg_a, uuidsentinel.agg_b]})
self.assertEqual(2, len(resource_providers))
resource_providers = objects.ResourceProviderList.get_all_by_filters(
self.context, filters={'member_of':
[uuidsentinel.agg_a, uuidsentinel.agg_b],
'name': u'rp_name_1'})
self.assertEqual(1, len(resource_providers))
resource_providers = objects.ResourceProviderList.get_all_by_filters(
self.context, filters={'member_of':
[uuidsentinel.agg_a, uuidsentinel.agg_b],
'name': u'barnabas'})
self.assertEqual(0, len(resource_providers))
resource_providers = objects.ResourceProviderList.get_all_by_filters(
self.context, filters={'member_of':
[uuidsentinel.agg_1, uuidsentinel.agg_2]})
self.assertEqual(0, len(resource_providers))
class TestResourceProviderAggregates(test.NoDBTestCase):