Merge "Remove ResourceProviderList class"

This commit is contained in:
Zuul 2019-03-15 10:02:20 +00:00 committed by Gerrit Code Review
commit 7a4151e4f0
5 changed files with 222 additions and 268 deletions

View File

@ -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:

View File

@ -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') %

View File

@ -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

View File

@ -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

View File

@ -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))