Exemplo n.º 1
0
def list_resource_providers(req):
    """GET a list of resource providers.

    On success return a 200 and an application/json body representing
    a collection of resource providers.
    """
    context = req.environ['placement.context']
    context.can(policies.LIST)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]

    schema = rp_schema.GET_RPS_SCHEMA_1_0
    if want_version.matches((1, 18)):
        schema = rp_schema.GET_RPS_SCHEMA_1_18
    elif want_version.matches((1, 14)):
        schema = rp_schema.GET_RPS_SCHEMA_1_14
    elif want_version.matches((1, 4)):
        schema = rp_schema.GET_RPS_SCHEMA_1_4
    elif want_version.matches((1, 3)):
        schema = rp_schema.GET_RPS_SCHEMA_1_3

    allow_forbidden = want_version.matches((1, 22))

    util.validate_query_params(req, schema)

    filters = {}
    # special handling of member_of qparam since we allow multiple member_of
    # params at microversion 1.24.
    if 'member_of' in req.GET:
        filters['member_of'], filters['forbidden_aggs'] = (
            util.normalize_member_of_qs_params(req))

    qpkeys = ('uuid', 'name', 'in_tree', 'resources', 'required')
    for attr in qpkeys:
        if attr in req.GET:
            value = req.GET[attr]
            if attr == 'resources':
                value = util.normalize_resources_qs_param(value)
            elif attr == 'required':
                value = util.normalize_traits_qs_param(
                    value, allow_forbidden=allow_forbidden)
            filters[attr] = value
    try:
        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' %
            {'error': exc})
    except exception.TraitNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            'Invalid trait(s) in request: %(error)s' % {'error': exc})

    response = req.response
    output, last_modified = _serialize_providers(
        req.environ, resource_providers, want_version)
    response.body = encodeutils.to_utf8(jsonutils.dumps(output))
    response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        response.last_modified = last_modified
        response.cache_control = 'no-cache'
    return response
Exemplo n.º 2
0
 def test_multiple(self):
     traits = (
         'HW_CPU_X86_VMX',
         'HW_GPU_API_DIRECT3D_V12_0',
         'HW_NIC_OFFLOAD_RX',
         'CUSTOM_GOLD',
         'STORAGE_DISK_SSD',
     )
     self.assertEqual(
         set(traits),
         util.normalize_traits_qs_param('%s, %s,%s , %s ,  %s  ' % traits))
Exemplo n.º 3
0
    def from_request(cls, req):
        # TODO(efried): Make it an error to specify limit more than once -
        #  maybe when we make group_policy optional.
        limit = req.GET.getall('limit')
        # JSONschema has already confirmed that limit has the form
        # of an integer.
        if limit:
            limit = int(limit[0])

        # TODO(efried): Make it an error to specify group_policy more than once
        #  - maybe when we make it optional.
        group_policy = req.GET.getall('group_policy') or None
        # Schema ensures we get either "none" or "isolate"
        if group_policy:
            group_policy = group_policy[0]

        anchor_required_traits = None
        anchor_forbidden_traits = None
        root_required = req.GET.getall('root_required')
        if root_required:
            if len(root_required) > 1:
                raise webob.exc.HTTPBadRequest(
                    "Query parameter 'root_required' may be specified only "
                    "once.", comment=errors.ILLEGAL_DUPLICATE_QUERYPARAM)
            anchor_required_traits, anchor_forbidden_traits, conflicts = (
                _fix_one_forbidden(util.normalize_traits_qs_param(
                    root_required[0], allow_forbidden=True)))
            if conflicts:
                raise webob.exc.HTTPBadRequest(
                    'Conflicting required and forbidden traits found in '
                    'root_required: %s' % ', '.join(conflicts),
                    comment=errors.QUERYPARAM_BAD_VALUE)

        same_subtree = req.GET.getall('same_subtree')
        # Construct a list of sets of request group suffixes strings.
        same_subtrees = []
        if same_subtree:
            for val in same_subtree:
                suffixes = set(substr.strip() for substr in val.split(','))
                if '' in suffixes:
                    raise webob.exc.HTTPBadRequest(
                        'Empty string (unsuffixed group) can not be specified '
                        'in `same_subtree` ',
                        comment=errors.QUERYPARAM_BAD_VALUE)
                same_subtrees.append(suffixes)

        return cls(
            limit=limit,
            group_policy=group_policy,
            anchor_required_traits=anchor_required_traits,
            anchor_forbidden_traits=anchor_forbidden_traits,
            same_subtrees=same_subtrees)
Exemplo n.º 4
0
 def _parse_request_items(req, allow_forbidden, verbose_suffix):
     ret = {}
     pattern = _QS_KEY_PATTERN_1_33 if verbose_suffix else _QS_KEY_PATTERN
     for key, val in req.GET.items():
         match = pattern.match(key)
         if not match:
             continue
         # `prefix` is 'resources', 'required', 'member_of', or 'in_tree'
         # `suffix` is a number in microversion < 1.33, a string 1-64
         # characters long of [a-zA-Z0-9_-] in microversion >= 1.33, or None
         prefix, suffix = match.groups()
         suffix = suffix or ''
         if suffix not in ret:
             ret[suffix] = RequestGroup(use_same_provider=bool(suffix))
         request_group = ret[suffix]
         if prefix == _QS_RESOURCES:
             request_group.resources = util.normalize_resources_qs_param(
                 val)
         elif prefix == _QS_REQUIRED:
             request_group.required_traits = util.normalize_traits_qs_param(
                 val, allow_forbidden=allow_forbidden)
         elif prefix == _QS_MEMBER_OF:
             # special handling of member_of qparam since we allow multiple
             # member_of params at microversion 1.24.
             # NOTE(jaypipes): Yes, this is inefficient to do this when
             # there are multiple member_of query parameters, but we do this
             # so we can error out if someone passes an "orphaned" member_of
             # request group.
             # TODO(jaypipes): Do validation of query parameters using
             # JSONSchema
             request_group.member_of, request_group.forbidden_aggs = (
                 util.normalize_member_of_qs_params(req, suffix))
         elif prefix == _QS_IN_TREE:
             request_group.in_tree = util.normalize_in_tree_qs_params(
                 val)
     return ret
Exemplo n.º 5
0
 def test_one(self):
     trait = 'HW_CPU_X86_VMX'
     # Various whitespace permutations
     for fmt in ('%s', ' %s', '%s ', ' %s ', '  %s  '):
         self.assertEqual(set([trait]),
                          util.normalize_traits_qs_param(fmt % trait))
Exemplo n.º 6
0
def list_resource_providers(req):
    """GET a list of resource providers.

    On success return a 200 and an application/json body representing
    a collection of resource providers.
    """
    context = req.environ['placement.context']
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]

    schema = rp_schema.GET_RPS_SCHEMA_1_0
    if want_version.matches((1, 18)):
        schema = rp_schema.GET_RPS_SCHEMA_1_18
    elif want_version.matches((1, 14)):
        schema = rp_schema.GET_RPS_SCHEMA_1_14
    elif want_version.matches((1, 4)):
        schema = rp_schema.GET_RPS_SCHEMA_1_4
    elif want_version.matches((1, 3)):
        schema = rp_schema.GET_RPS_SCHEMA_1_3

    util.validate_query_params(req, schema)

    filters = {}
    qpkeys = ('uuid', 'name', 'member_of', 'in_tree', 'resources', 'required')
    for attr in qpkeys:
        if attr in req.GET:
            value = req.GET[attr]
            # special case member_of to always make its value a
            # list, either by accepting the single value, or if it
            # starts with 'in:' splitting on ','.
            # NOTE(cdent): This will all change when we start using
            # JSONSchema validation of query params.
            if attr == 'member_of':
                if value.startswith('in:'):
                    value = value[3:].split(',')
                else:
                    value = [value]
                # Make sure the values are actually UUIDs.
                for aggr_uuid in value:
                    if not uuidutils.is_uuid_like(aggr_uuid):
                        raise webob.exc.HTTPBadRequest(
                            _('Invalid uuid value: %(uuid)s') %
                            {'uuid': aggr_uuid})
            elif attr == 'resources':
                value = util.normalize_resources_qs_param(value)
            elif attr == 'required':
                value = util.normalize_traits_qs_param(value)
            filters[attr] = value
    try:
        resource_providers = rp_obj.ResourceProviderList.get_all_by_filters(
            context, filters)
    except exception.ResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('Invalid resource class in resources parameter: %(error)s') %
            {'error': exc})
    except exception.TraitNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('Invalid trait(s) in "required" parameter: %(error)s') %
            {'error': exc})

    response = req.response
    output, last_modified = _serialize_providers(
        req.environ, resource_providers, want_version)
    response.body = encodeutils.to_utf8(jsonutils.dumps(output))
    response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        response.last_modified = last_modified
        response.cache_control = 'no-cache'
    return response