def _get_by_one_request(rg_ctx): """Get allocation candidates for one RequestGroup. Must be called from within an placement_context_manager.reader (or writer) context. :param rg_ctx: RequestGroupSearchContext. """ if not rg_ctx.use_same_provider and (rg_ctx.exists_sharing or rg_ctx.exists_nested): # TODO(jaypipes): The check/callout to handle trees goes here. # Build a dict, keyed by resource class internal ID, of lists of # internal IDs of resource providers that share some inventory for # each resource class requested. # If there aren't any providers that have any of the # required traits, just exit early... if rg_ctx.required_trait_map: # TODO(cdent): Now that there is also a forbidden_trait_map # it should be possible to further optimize this attempt at # a quick return, but we leave that to future patches for # now. trait_rps = res_ctx.get_provider_ids_having_any_trait( rg_ctx.context, rg_ctx.required_trait_map) if not trait_rps: return [], [] rp_candidates = res_ctx.get_trees_matching_all(rg_ctx) return _alloc_candidates_multiple_providers(rg_ctx, rp_candidates) # Either we are processing a single-RP request group, or there are no # sharing providers that (help) satisfy the request. Get a list of # tuples of (internal provider ID, root provider ID) that have ALL # the requested resources and more efficiently construct the # allocation requests. rp_tuples = res_ctx.get_provider_ids_matching(rg_ctx) return _alloc_candidates_single_provider(rg_ctx, rp_tuples)
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>]] # 'forbidden_aggs': [<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', []) forbidden_aggs = filters.pop('forbidden_aggs', []) 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', {}) in_tree = filters.pop('in_tree', None) 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"), ] rp_to_root = sa.join( 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) if name: query = query.where(rp.c.name == name) if uuid: query = query.where(rp.c.uuid == uuid) if in_tree: # 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_ids = res_ctx.provider_ids_from_uuid(context, in_tree) 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 query = query.where(rp.c.root_provider_id == root_id) if required: trait_map = trait_obj.ids_from_names(context, required) trait_rps = res_ctx._get_provider_ids_having_all_traits( context, trait_map) if not trait_rps: return [] query = query.where(rp.c.id.in_(trait_rps)) if forbidden: trait_map = trait_obj.ids_from_names(context, forbidden) trait_rps = res_ctx.get_provider_ids_having_any_trait( context, trait_map) if trait_rps: query = query.where(~rp.c.id.in_(trait_rps)) if member_of: rps_in_aggs = res_ctx.provider_ids_matching_aggregates( context, member_of) if not rps_in_aggs: return [] query = query.where(rp.c.id.in_(rps_in_aggs)) if forbidden_aggs: rps_bad_aggs = res_ctx.provider_ids_matching_aggregates( context, [forbidden_aggs]) if rps_bad_aggs: query = query.where(~rp.c.id.in_(rps_bad_aggs)) for rc_name, amount in resources.items(): rc_id = context.rc_cache.id_from_string(rc_name) rps_with_resource = res_ctx.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)) return context.session.execute(query).fetchall()