Remove ResourceProviderList class

The get_all_by_filters class method is now module level. Callers
and tests are updated accordingly.

As there is no longer any package using common.py, it is removed.

Looking at this, it now seems obvious that 'get_all_by_filters' is
oxymoronic but changing it now didn't seem appropriate. We may
wish to do that in future work.

Change-Id: Ib9365200ebec58002c2456435f858466c6afea7f
This commit is contained in:
Chris Dent 2019-03-09 00:41:02 +00:00
parent f23137beee
commit a53aef47b2
5 changed files with 222 additions and 268 deletions

@ -321,10 +321,9 @@ def _resource_providers_by_uuid(ctx, rp_uuids):
# TODO(jaypipes): Clearly, this is not efficient to do one query for
# each resource provider UUID in the allocations instead of doing a
# single query for all the UUIDs. However, since
# ResourceProviderList.get_all_by_filters() is way too complicated for
# rp_obj.get_all_by_filters() is way too complicated for
# this purpose and doesn't raise NotFound anyway, we'll do this.
# Perhaps consider adding a ResourceProviderList.get_all_by_uuids()
# later on?
# Perhaps consider adding a rp_obj.get_all_by_uuids() later on?
try:
res[rp_uuid] = rp_obj.ResourceProvider.get_by_uuid(ctx, rp_uuid)
except exception.NotFound:

@ -236,8 +236,7 @@ def list_resource_providers(req):
value, allow_forbidden=allow_forbidden)
filters[attr] = value
try:
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
context, filters)
resource_providers = rp_obj.get_all_by_filters(context, filters)
except exception.ResourceClassNotFound as exc:
raise webob.exc.HTTPBadRequest(
_('Invalid resource class in resources parameter: %(error)s') %

@ -1,38 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
class ObjectList(object):
# For FooList, ITEM_CLS = Foo
ITEM_CLS = None
"""Provide listiness for objects which are a list of other objects."""
def __init__(self, objects=None):
self.objects = objects or []
def __len__(self):
"""List length is a proxy for truthiness."""
return len(self.objects)
def __getitem__(self, index):
return self.objects[index]
def __repr__(self):
strings = [repr(x) for x in self.objects]
return "%s[%s]" % (self.__class__.__name__, ", ".join(strings))
@classmethod
def _set_objects(cls, context, db_list):
list_obj = cls()
for db_item in db_list:
list_obj.objects.append(cls.ITEM_CLS(context, **db_item))
return list_obj

@ -34,7 +34,6 @@ from placement.db.sqlalchemy import models
from placement import db_api
from placement import exception
from placement.i18n import _
from placement.objects import common as common_obj
from placement.objects import inventory as inv_obj
from placement.objects import rp_candidates
from placement.objects import trait as trait_obj
@ -1089,9 +1088,8 @@ class ResourceProvider(object):
# However as the RP's current parent is None the above
# condition is the same as "the new parent cannot be any RP
# from the current RP tree".
same_tree = ResourceProviderList.get_all_by_filters(
context,
filters={'in_tree': self.uuid})
same_tree = get_all_by_filters(
context, filters={'in_tree': self.uuid})
rp_uuids_in_the_same_tree = [rp.uuid for rp in same_tree]
if parent_uuid in rp_uuids_in_the_same_tree:
raise exception.ObjectActionError(
@ -1282,206 +1280,202 @@ def get_providers_with_shared_capacity(ctx, rc_id, amount, member_of=None):
return [r[0] for r in ctx.session.execute(sel)]
class ResourceProviderList(common_obj.ObjectList):
ITEM_CLS = ResourceProvider
@db_api.placement_context_manager.reader
def _get_all_by_filters_from_db(context, filters):
# Eg. filters can be:
# filters = {
# 'name': <name>,
# 'uuid': <uuid>,
# 'member_of': [[<aggregate_uuid>, <aggregate_uuid>],
# [<aggregate_uuid>]]
# 'resources': {
# 'VCPU': 1,
# 'MEMORY_MB': 1024
# },
# 'in_tree': <uuid>,
# 'required': [<trait_name>, ...]
# }
if not filters:
filters = {}
else:
# Since we modify the filters, copy them so that we don't modify
# them in the calling program.
filters = copy.deepcopy(filters)
name = filters.pop('name', None)
uuid = filters.pop('uuid', None)
member_of = filters.pop('member_of', [])
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])
@staticmethod
@db_api.placement_context_manager.reader
def _get_all_by_filters_from_db(context, filters):
# Eg. filters can be:
# filters = {
# 'name': <name>,
# 'uuid': <uuid>,
# 'member_of': [[<aggregate_uuid>, <aggregate_uuid>],
# [<aggregate_uuid>]]
# 'resources': {
# 'VCPU': 1,
# 'MEMORY_MB': 1024
# },
# 'in_tree': <uuid>,
# 'required': [<trait_name>, ...]
# }
if not filters:
filters = {}
else:
# Since we modify the filters, copy them so that we don't modify
# them in the calling program.
filters = copy.deepcopy(filters)
name = filters.pop('name', None)
uuid = filters.pop('uuid', None)
member_of = filters.pop('member_of', [])
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
# and we want to make sure those class names aren't incorrect.
resources = {rc_cache.RC_CACHE.id_from_string(r_name): amount
for r_name, amount in resources.items()}
rp = sa.alias(_RP_TBL, name="rp")
root_rp = sa.alias(_RP_TBL, name="root_rp")
parent_rp = sa.alias(_RP_TBL, name="parent_rp")
resources = filters.pop('resources', {})
# NOTE(sbauza): We want to key the dict by the resource class IDs
# and we want to make sure those class names aren't incorrect.
resources = {rc_cache.RC_CACHE.id_from_string(r_name): amount
for r_name, amount in resources.items()}
rp = sa.alias(_RP_TBL, name="rp")
root_rp = sa.alias(_RP_TBL, name="root_rp")
parent_rp = sa.alias(_RP_TBL, name="parent_rp")
cols = [
rp.c.id,
rp.c.uuid,
rp.c.name,
rp.c.generation,
rp.c.updated_at,
rp.c.created_at,
root_rp.c.uuid.label("root_provider_uuid"),
parent_rp.c.uuid.label("parent_provider_uuid"),
]
cols = [
rp.c.id,
rp.c.uuid,
rp.c.name,
rp.c.generation,
rp.c.updated_at,
rp.c.created_at,
root_rp.c.uuid.label("root_provider_uuid"),
parent_rp.c.uuid.label("parent_provider_uuid"),
]
# TODO(jaypipes): Convert this to an inner join once all
# root_provider_id values are NOT NULL
rp_to_root = sa.outerjoin(
rp, root_rp,
rp.c.root_provider_id == root_rp.c.id)
rp_to_parent = sa.outerjoin(
rp_to_root, parent_rp,
rp.c.parent_provider_id == parent_rp.c.id)
# TODO(jaypipes): Convert this to an inner join once all
# root_provider_id values are NOT NULL
rp_to_root = sa.outerjoin(
rp, root_rp,
rp.c.root_provider_id == root_rp.c.id)
rp_to_parent = sa.outerjoin(
rp_to_root, parent_rp,
rp.c.parent_provider_id == parent_rp.c.id)
query = sa.select(cols).select_from(rp_to_parent)
query = sa.select(cols).select_from(rp_to_parent)
if name:
query = query.where(rp.c.name == name)
if uuid:
query = query.where(rp.c.uuid == uuid)
if 'in_tree' in filters:
# The 'in_tree' parameter is the UUID of a resource provider that
# the caller wants to limit the returned providers to only those
# within its "provider tree". So, we look up the resource provider
# having the UUID specified by the 'in_tree' parameter and grab the
# root_provider_id value of that record. We can then ask for only
# those resource providers having a root_provider_id of that value.
tree_uuid = filters.pop('in_tree')
tree_ids = provider_ids_from_uuid(context, tree_uuid)
if tree_ids is None:
# List operations should simply return an empty list when a
# non-existing resource provider UUID is given.
return []
root_id = tree_ids.root_id
# TODO(jaypipes): Remove this OR condition when root_provider_id
# is not nullable in the database and all resource provider records
# have populated the root provider ID.
where_cond = sa.or_(
rp.c.id == root_id,
rp.c.root_provider_id == root_id)
query = query.where(where_cond)
# Get the provider IDs matching any specified traits and/or aggregates
rp_ids, forbidden_rp_ids = get_provider_ids_for_traits_and_aggs(
context, required, forbidden, member_of)
if rp_ids is None:
# If no providers match the traits/aggs, we can short out
if name:
query = query.where(rp.c.name == name)
if uuid:
query = query.where(rp.c.uuid == uuid)
if 'in_tree' in filters:
# The 'in_tree' parameter is the UUID of a resource provider that
# the caller wants to limit the returned providers to only those
# within its "provider tree". So, we look up the resource provider
# having the UUID specified by the 'in_tree' parameter and grab the
# root_provider_id value of that record. We can then ask for only
# those resource providers having a root_provider_id of that value.
tree_uuid = filters.pop('in_tree')
tree_ids = provider_ids_from_uuid(context, tree_uuid)
if tree_ids is None:
# List operations should simply return an empty list when a
# non-existing resource provider UUID is given.
return []
if rp_ids:
query = query.where(rp.c.id.in_(rp_ids))
# forbidden providers, if found, are mutually exclusive with matching
# providers above, so we only need to include this clause if we didn't
# use the positive filter above.
elif forbidden_rp_ids:
query = query.where(~rp.c.id.in_(forbidden_rp_ids))
root_id = tree_ids.root_id
# TODO(jaypipes): Remove this OR condition when root_provider_id
# is not nullable in the database and all resource provider records
# have populated the root provider ID.
where_cond = sa.or_(
rp.c.id == root_id,
rp.c.root_provider_id == root_id)
query = query.where(where_cond)
if not resources:
# Returns quickly the list in case we don't need to check the
# resource usage
res = context.session.execute(query).fetchall()
return [dict(r) for r in res]
# NOTE(sbauza): In case we want to look at the resource criteria, then
# the SQL generated from this case looks something like:
# SELECT
# rp.*
# FROM resource_providers AS rp
# JOIN inventories AS inv
# ON rp.id = inv.resource_provider_id
# LEFT JOIN (
# SELECT resource_provider_id, resource_class_id, SUM(used) AS used
# FROM allocations
# WHERE resource_class_id IN ($RESOURCE_CLASSES)
# GROUP BY resource_provider_id, resource_class_id
# ) AS usage
# ON inv.resource_provider_id = usage.resource_provider_id
# AND inv.resource_class_id = usage.resource_class_id
# AND (inv.resource_class_id = $X AND (used + $AMOUNT_X <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_X AND inv.max_unit >= $AMOUNT_X AND
# $AMOUNT_X % inv.step_size == 0)
# OR (inv.resource_class_id = $Y AND (used + $AMOUNT_Y <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_Y AND inv.max_unit >= $AMOUNT_Y AND
# $AMOUNT_Y % inv.step_size == 0)
# OR (inv.resource_class_id = $Z AND (used + $AMOUNT_Z <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_Z AND inv.max_unit >= $AMOUNT_Z AND
# $AMOUNT_Z % inv.step_size == 0))
# GROUP BY rp.id
# HAVING
# COUNT(DISTINCT(inv.resource_class_id)) == len($RESOURCE_CLASSES)
#
# with a possible additional WHERE clause for the name and uuid that
# comes from the above filters
# First JOIN between inventories and RPs is here
inv_join = sa.join(
rp_to_parent,
_INV_TBL,
rp.c.id == _INV_TBL.c.resource_provider_id)
# Now, below is the LEFT JOIN for getting the allocations usage
usage = _usage_select(list(resources))
usage_join = sa.outerjoin(
inv_join, usage, sa.and_(
usage.c.resource_provider_id == (
_INV_TBL.c.resource_provider_id),
usage.c.resource_class_id == _INV_TBL.c.resource_class_id))
# And finally, we verify for each resource class if the requested
# amount isn't more than the left space (considering the allocation
# ratio, the reserved space and the min and max amount possible sizes)
where_clauses = [
sa.and_(
_INV_TBL.c.resource_class_id == r_idx,
_capacity_check_clause(amount, usage)
)
for (r_idx, amount) in resources.items()]
query = query.select_from(usage_join)
query = query.where(sa.or_(*where_clauses))
query = query.group_by(rp.c.id, root_rp.c.uuid, parent_rp.c.uuid)
# NOTE(sbauza): Only RPs having all the asked resources can be provided
query = query.having(sql.func.count(
sa.distinct(_INV_TBL.c.resource_class_id)) == len(resources))
# Get the provider IDs matching any specified traits and/or aggregates
rp_ids, forbidden_rp_ids = get_provider_ids_for_traits_and_aggs(
context, required, forbidden, member_of)
if rp_ids is None:
# If no providers match the traits/aggs, we can short out
return []
if rp_ids:
query = query.where(rp.c.id.in_(rp_ids))
# forbidden providers, if found, are mutually exclusive with matching
# providers above, so we only need to include this clause if we didn't
# use the positive filter above.
elif forbidden_rp_ids:
query = query.where(~rp.c.id.in_(forbidden_rp_ids))
if not resources:
# Returns quickly the list in case we don't need to check the
# resource usage
res = context.session.execute(query).fetchall()
return [dict(r) for r in res]
@classmethod
def get_all_by_filters(cls, context, filters=None):
"""Returns a list of `ResourceProvider` objects that have sufficient
resources in their inventories to satisfy the amounts specified in the
`filters` parameter.
# NOTE(sbauza): In case we want to look at the resource criteria, then
# the SQL generated from this case looks something like:
# SELECT
# rp.*
# FROM resource_providers AS rp
# JOIN inventories AS inv
# ON rp.id = inv.resource_provider_id
# LEFT JOIN (
# SELECT resource_provider_id, resource_class_id, SUM(used) AS used
# FROM allocations
# WHERE resource_class_id IN ($RESOURCE_CLASSES)
# GROUP BY resource_provider_id, resource_class_id
# ) AS usage
# ON inv.resource_provider_id = usage.resource_provider_id
# AND inv.resource_class_id = usage.resource_class_id
# AND (inv.resource_class_id = $X AND (used + $AMOUNT_X <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_X AND inv.max_unit >= $AMOUNT_X AND
# $AMOUNT_X % inv.step_size == 0)
# OR (inv.resource_class_id = $Y AND (used + $AMOUNT_Y <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_Y AND inv.max_unit >= $AMOUNT_Y AND
# $AMOUNT_Y % inv.step_size == 0)
# OR (inv.resource_class_id = $Z AND (used + $AMOUNT_Z <= (
# total - reserved) * inv.allocation_ratio) AND
# inv.min_unit <= $AMOUNT_Z AND inv.max_unit >= $AMOUNT_Z AND
# $AMOUNT_Z % inv.step_size == 0))
# GROUP BY rp.id
# HAVING
# COUNT(DISTINCT(inv.resource_class_id)) == len($RESOURCE_CLASSES)
#
# with a possible additional WHERE clause for the name and uuid that
# comes from the above filters
If no resource providers can be found, the function will return an
empty list.
# First JOIN between inventories and RPs is here
inv_join = sa.join(
rp_to_parent,
_INV_TBL,
rp.c.id == _INV_TBL.c.resource_provider_id)
:param context: `placement.context.RequestContext` that may be used to
grab a DB connection.
:param filters: Can be `name`, `uuid`, `member_of`, `in_tree` or
`resources` where `member_of` is a list of list of
aggregate UUIDs, `in_tree` is a UUID of a resource
provider that we can use to find the root provider ID
of the tree of providers to filter results by and
`resources` is a dict of amounts keyed by resource
classes.
:type filters: dict
"""
resource_providers = cls._get_all_by_filters_from_db(context, filters)
return cls._set_objects(context, resource_providers)
# Now, below is the LEFT JOIN for getting the allocations usage
usage = _usage_select(list(resources))
usage_join = sa.outerjoin(
inv_join, usage, sa.and_(
usage.c.resource_provider_id == (
_INV_TBL.c.resource_provider_id),
usage.c.resource_class_id == _INV_TBL.c.resource_class_id))
# And finally, we verify for each resource class if the requested
# amount isn't more than the left space (considering the allocation
# ratio, the reserved space and the min and max amount possible sizes)
where_clauses = [
sa.and_(
_INV_TBL.c.resource_class_id == r_idx,
_capacity_check_clause(amount, usage)
)
for (r_idx, amount) in resources.items()]
query = query.select_from(usage_join)
query = query.where(sa.or_(*where_clauses))
query = query.group_by(rp.c.id, root_rp.c.uuid, parent_rp.c.uuid)
# NOTE(sbauza): Only RPs having all the asked resources can be provided
query = query.having(sql.func.count(
sa.distinct(_INV_TBL.c.resource_class_id)) == len(resources))
res = context.session.execute(query).fetchall()
return [dict(r) for r in res]
def get_all_by_filters(context, filters=None):
"""Returns a list of `ResourceProvider` objects that have sufficient
resources in their inventories to satisfy the amounts specified in the
`filters` parameter.
If no resource providers can be found, the function will return an
empty list.
:param context: `placement.context.RequestContext` that may be used to
grab a DB connection.
:param filters: Can be `name`, `uuid`, `member_of`, `in_tree` or
`resources` where `member_of` is a list of list of
aggregate UUIDs, `in_tree` is a UUID of a resource
provider that we can use to find the root provider ID
of the tree of providers to filter results by and
`resources` is a dict of amounts keyed by resource
classes.
:type filters: dict
"""
resource_providers = _get_all_by_filters_from_db(context, filters)
return [ResourceProvider(context, **rp) for rp in resource_providers]
@db_api.placement_context_manager.reader

@ -186,7 +186,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Check the new-style providers remains in a tree,
# which means the root provider ids are not changed
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.root_rp,
@ -282,7 +282,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
tb.add_inventory(grandchild_rp, orc.VCPU, 1)
# Check all providers returned when getting by root UUID
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.root_rp,
@ -291,7 +291,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(3, len(rps))
# Check all providers returned when getting by child UUID
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.child_rp,
@ -300,7 +300,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(3, len(rps))
# Check all providers returned when getting by grandchild UUID
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.grandchild_rp,
@ -313,7 +313,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# No aggregate associations yet, so expect no records when adding a
# member_of filter
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'member_of': [[uuidsentinel.agg]],
@ -326,7 +326,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# the grandchild is returned when asking for the grandchild's tree
# along with the aggregate as member_of
grandchild_rp.set_aggregates([uuidsentinel.agg])
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'member_of': [[uuidsentinel.agg]],
@ -337,7 +337,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(uuidsentinel.grandchild_rp, rps[0].uuid)
# Try filtering on an unknown UUID and verify no results
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'uuid': uuidsentinel.unknown_rp,
@ -348,7 +348,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# And now check that filtering for just the child's UUID along with the
# tree produces just a single provider (the child)
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'uuid': uuidsentinel.child_rp,
@ -361,7 +361,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Ensure that the resources filter also continues to work properly with
# the in_tree filter. Request resources that none of the providers
# currently have and ensure no providers are returned
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.grandchild_rp,
@ -373,7 +373,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
self.assertEqual(0, len(rps))
# And now ask for one VCPU, which should only return us the grandchild
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.grandchild_rp,
@ -387,7 +387,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# Finally, verify we still get the grandchild if filtering on the
# parent's UUID as in_tree
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.child_rp,
@ -426,13 +426,13 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
"""
# Passing a non-existing resource provider UUID should return an empty
# list
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.rp1,
}
)
self.assertEqual([], rps.objects)
self.assertEqual([], rps)
rp_tbl = rp_obj._RP_TBL
conn = self.placement_db.get_engine().connect()
@ -454,7 +454,7 @@ class ResourceProviderTestCase(tb.PlacementDbBaseTestCase):
# don't have any migrations messing with the end result.
with mock.patch('placement.objects.resource_provider.'
'_set_root_provider_id'):
rps = rp_obj.ResourceProviderList.get_all_by_filters(
rps = rp_obj.get_all_by_filters(
self.ctx,
filters={
'in_tree': uuidsentinel.rp1,
@ -796,13 +796,13 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
'rp_name_' + rp_i,
uuid=getattr(uuidsentinel, 'rp_uuid_' + rp_i))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx)
self.assertEqual(2, len(resource_providers))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, filters={'name': u'rp_name_1'})
self.assertEqual(1, len(resource_providers))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, filters={'uuid': uuidsentinel.rp_uuid_2})
self.assertEqual(1, len(resource_providers))
self.assertEqual('rp_name_2', resource_providers[0].name)
@ -824,55 +824,55 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
# Both RPs should accept that request given the only current allocation
# for the first RP is leaving one VCPU
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.VCPU: 1}})
self.assertEqual(2, len(resource_providers))
# Now, when asking for 2 VCPUs, only the second RP should accept that
# given the current allocation for the first RP
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.VCPU: 2}})
self.assertEqual(1, len(resource_providers))
# Adding a second resource request should be okay for the 2nd RP
# given it has enough disk but we also need to make sure that the
# first RP is not acceptable because of the VCPU request
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.VCPU: 2, orc.DISK_GB: 1022}})
self.assertEqual(1, len(resource_providers))
# Now, we are asking for both disk and VCPU resources that all the RPs
# can't accept (as the 2nd RP is having a reserved size)
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.VCPU: 2, orc.DISK_GB: 1024}})
self.assertEqual(0, len(resource_providers))
# We also want to verify that asking for a specific RP can also be
# checking the resource usage.
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'name': u'rp_name_1',
'resources': {orc.VCPU: 1}})
self.assertEqual(1, len(resource_providers))
# Let's verify that the min and max units are checked too
# Case 1: amount is in between min and max and modulo step_size
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.MEMORY_MB: 2}})
self.assertEqual(2, len(resource_providers))
# Case 2: amount is less than min_unit
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.MEMORY_MB: 1}})
self.assertEqual(0, len(resource_providers))
# Case 3: amount is more than min_unit
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.MEMORY_MB: 5}})
self.assertEqual(0, len(resource_providers))
# Case 4: amount is not modulo step_size
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, {'resources': {orc.MEMORY_MB: 3}})
self.assertEqual(0, len(resource_providers))
def test_get_all_by_filters_with_resources_not_existing(self):
self.assertRaises(
exception.ResourceClassNotFound,
rp_obj.ResourceProviderList.get_all_by_filters,
rp_obj.get_all_by_filters,
self.ctx, {'resources': {'FOOBAR': 3}})
def test_get_all_by_filters_aggregate(self):
@ -882,7 +882,7 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
'rp_name_' + str(rp_i), *aggs,
uuid=getattr(uuidsentinel, 'rp_uuid_' + str(rp_i)))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx, filters={'member_of': [[uuidsentinel.agg_a]]})
self.assertEqual(2, len(resource_providers))
@ -892,24 +892,24 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
self.assertNotIn('rp_name_2', names)
self.assertNotIn('rp_name_4', names)
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx,
filters={'member_of': [[uuidsentinel.agg_a, uuidsentinel.agg_b]]})
self.assertEqual(2, len(resource_providers))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx,
filters={'member_of': [[uuidsentinel.agg_a, uuidsentinel.agg_b]],
'name': u'rp_name_1'})
self.assertEqual(1, len(resource_providers))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx,
filters={'member_of': [[uuidsentinel.agg_a, uuidsentinel.agg_b]],
'name': u'barnabas'})
self.assertEqual(0, len(resource_providers))
resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
resource_providers = rp_obj.get_all_by_filters(
self.ctx,
filters={'member_of': [[uuidsentinel.agg_1, uuidsentinel.agg_2]]})
self.assertEqual(0, len(resource_providers))
@ -931,7 +931,7 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
tb.set_traits(rp, *traits)
# Three rps (1, 2, 3) should have CUSTOM_TRAIT_A
custom_a_rps = rp_obj.ResourceProviderList.get_all_by_filters(
custom_a_rps = rp_obj.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]
@ -940,7 +940,7 @@ class ResourceProviderListTestCase(tb.PlacementDbBaseTestCase):
# 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(
custom_a_rps = rp_obj.get_all_by_filters(
self.ctx,
filters={'required': ['CUSTOM_TRAIT_A', '!CUSTOM_TRAIT_B']})
self.assertEqual(1, len(custom_a_rps))