diff --git a/nova/objects/resource_provider.py b/nova/objects/resource_provider.py index 9fd19cc6e120..07ad215edbfb 100644 --- a/nova/objects/resource_provider.py +++ b/nova/objects/resource_provider.py @@ -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': , # 'uuid': , + # 'member_of': [, ] # '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 diff --git a/nova/tests/functional/db/test_resource_provider.py b/nova/tests/functional/db/test_resource_provider.py index 5aed9fe26d18..3a7f09336f1e 100644 --- a/nova/tests/functional/db/test_resource_provider.py +++ b/nova/tests/functional/db/test_resource_provider.py @@ -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):