Merge "[placement] Filter resource providers by forbidden traits in db"

This commit is contained in:
Zuul
2018-04-14 00:48:03 +00:00
committed by Gerrit Code Review
2 changed files with 59 additions and 1 deletions

View File

@@ -1433,7 +1433,11 @@ class ResourceProviderList(base.ObjectListBase, base.VersionedObject):
name = filters.pop('name', None)
uuid = filters.pop('uuid', None)
member_of = filters.pop('member_of', [])
required = filters.pop('required', [])
required = set(filters.pop('required', []))
forbidden = set([trait for trait in required
if trait.startswith('!')])
required = required - forbidden
forbidden = set([trait.lstrip('!') for trait in forbidden])
resources = filters.pop('resources', {})
# NOTE(sbauza): We want to key the dict by the resource class IDs
@@ -1514,6 +1518,17 @@ class ResourceProviderList(base.ObjectListBase, base.VersionedObject):
return []
query = query.where(rp.c.id.in_(rp_ids))
# If 'forbidden' has values, filter out those providers that have
# that trait as one their traits.
if forbidden:
trait_map = _trait_ids_from_names(context, forbidden)
if len(trait_map) != len(forbidden):
missing = forbidden - set(trait_map)
raise exception.TraitNotFound(names=', '.join(missing))
rp_ids = _get_provider_ids_having_any_trait(context, trait_map)
if rp_ids:
query = query.where(~rp.c.id.in_(rp_ids))
if not resources:
# Returns quickly the list in case we don't need to check the
# resource usage

View File

@@ -1136,6 +1136,49 @@ class ResourceProviderListTestCase(ResourceProviderBaseCase):
[uuidsentinel.agg_1, uuidsentinel.agg_2]})
self.assertEqual(0, len(resource_providers))
def test_get_all_by_required(self):
# Create some resource providers and give them each 0 or more traits.
# rp_name_0: no traits
# rp_name_1: CUSTOM_TRAIT_A
# rp_name_2: CUSTOM_TRAIT_A, CUSTOM_TRAIT_B
# rp_name_3: CUSTOM_TRAIT_A, CUSTOM_TRAIT_B, CUSTOM_TRAIT_C
trait_names = ['CUSTOM_TRAIT_A', 'CUSTOM_TRAIT_B',
'CUSTOM_TRAIT_C']
trait_objects = []
for trait in trait_names:
trait_object = rp_obj.Trait(self.ctx, name=trait)
trait_object.create()
trait_objects.append(trait_object)
for rp_i in [0, 1, 2, 3]:
uuid = getattr(uuidsentinel, 'rp_uuid_' + str(rp_i))
name = 'rp_name_' + str(rp_i)
rp = rp_obj.ResourceProvider(self.ctx, name=name, uuid=uuid)
rp.create()
if rp_i:
traits = trait_objects[0:rp_i]
rp.set_traits(traits)
# Three rps (1, 2, 3) should have CUSTOM_TRAIT_A
custom_a_rps = rp_obj.ResourceProviderList.get_all_by_filters(
self.ctx, filters={'required': ['CUSTOM_TRAIT_A']})
self.assertEqual(3, len(custom_a_rps))
rp_names = [a_rp.name for a_rp in custom_a_rps]
expected_names = ['rp_name_%s' % i for i in [1, 2, 3]]
self.assertEqual(expected_names, sorted(rp_names))
# One rp (rp 1) if we forbid CUSTOM_TRAIT_B, with a single trait of
# CUSTOM_TRAIT_A
custom_a_rps = rp_obj.ResourceProviderList.get_all_by_filters(
self.ctx,
filters={'required': ['CUSTOM_TRAIT_A', '!CUSTOM_TRAIT_B']})
self.assertEqual(1, len(custom_a_rps))
self.assertEqual(uuidsentinel.rp_uuid_1, custom_a_rps[0].uuid)
self.assertEqual('rp_name_1', custom_a_rps[0].name)
traits = rp_obj.TraitList.get_all_by_resource_provider(
self.ctx, custom_a_rps[0])
self.assertEqual(1, len(traits))
self.assertEqual('CUSTOM_TRAIT_A', traits[0].name)
class TestResourceProviderAggregates(test.NoDBTestCase):