Reuse common get_providers_with_resource()
This patch refactors _get_all_by_filters_from_db() function used in `GET /resource_providers` to use more common function, get_providers_with_resource(). SQL queries will increase slightly by this patch, but it is done for the readability and the debuggability. Change-Id: Iff0cec9445e6ddafa37c852438ce0c54fef77082
This commit is contained in:
parent
56e25635ff
commit
3a46b4463b
@ -1309,12 +1309,8 @@ def _get_all_by_filters_from_db(context, filters):
|
||||
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")
|
||||
@ -1381,75 +1377,11 @@ def _get_all_by_filters_from_db(context, filters):
|
||||
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]
|
||||
|
||||
# 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))
|
||||
for rc_name, amount in resources.items():
|
||||
rc_id = rc_cache.RC_CACHE.id_from_string(rc_name)
|
||||
rps_with_resource = get_providers_with_resource(context, rc_id, amount)
|
||||
rps_with_resource = (rp[0] for rp in rps_with_resource)
|
||||
query = query.where(rp.c.id.in_(rps_with_resource))
|
||||
|
||||
res = context.session.execute(query).fetchall()
|
||||
return [dict(r) for r in res]
|
||||
|
Loading…
x
Reference in New Issue
Block a user