Пример #1
0
    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)
Пример #2
0
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()