Beispiel #1
0
def delete_inventory(req):
    """DELETE to destroy a single inventory.

    If the inventory is in use or resource provider generation is out
    of sync return a 409.

    On success return a 204 and an empty body.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)
    try:
        resource_provider.delete_inventory(resource_class)
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse) as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory of class %(class)s: %(error)s') %
            {'class': resource_class, 'error': exc},
            json_formatter=util.json_error_formatter)

    response = req.response
    response.status = 204
    response.content_type = None
    return response
Beispiel #2
0
def get_inventory(req):
    """GET one inventory.

    On success return a 200 an application/json body representing one
    inventory.
    """
    context = req.environ['placement.context']
    context.can(policies.SHOW)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')
    try:
        rp = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %(uuid)s found : %(error)s") %
             {'uuid': uuid, 'error': exc})

    inv_list = rp_obj.InventoryList.get_all_by_resource_provider(context, rp)
    inventory = inv_list.find(resource_class)

    if not inventory:
        raise webob.exc.HTTPNotFound(
            _('No inventory of class %(class)s for %(rp_uuid)s') %
            {'class': resource_class, 'rp_uuid': uuid})

    return _send_inventory(req, rp, inventory)
Beispiel #3
0
def delete_inventory(req):
    """DELETE to destroy a single inventory.

    If the inventory is in use or resource provider generation is out
    of sync return a 409.

    On success return a 204 and an empty body.
    """
    context = req.environ['placement.context']
    context.can(policies.DELETE)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)
    try:
        resource_provider.delete_inventory(resource_class)
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse) as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory of class %(class)s: %(error)s') %
            {'class': resource_class, 'error': exc},
            comment=errors.CONCURRENT_UPDATE)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _('No inventory of class %(class)s found for delete: %(error)s') %
             {'class': resource_class, 'error': exc})

    response = req.response
    response.status = 204
    response.content_type = None
    return response
Beispiel #4
0
def get_inventory(req):
    """GET one inventory.

    On success return a 200 an application/json body representing one
    inventory.
    """
    context = req.environ['placement.context']
    context.can(policies.SHOW)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')
    try:
        rp = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %(uuid)s found : %(error)s") %
             {'uuid': uuid, 'error': exc})

    inv_list = rp_obj.InventoryList.get_all_by_resource_provider(context, rp)
    inventory = inv_list.find(resource_class)

    if not inventory:
        raise webob.exc.HTTPNotFound(
            _('No inventory of class %(class)s for %(rp_uuid)s') %
            {'class': resource_class, 'rp_uuid': uuid})

    return _send_inventory(req, rp, inventory)
Beispiel #5
0
def delete_inventory(req):
    """DELETE to destroy a single inventory.

    If the inventory is in use or resource provider generation is out
    of sync return a 409.

    On success return a 204 and an empty body.
    """
    context = req.environ['placement.context']
    context.can(policies.DELETE)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)
    try:
        resource_provider.delete_inventory(resource_class)
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse) as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory of class %(class)s: %(error)s') %
            {'class': resource_class, 'error': exc},
            comment=errors.CONCURRENT_UPDATE)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _('No inventory of class %(class)s found for delete: %(error)s') %
             {'class': resource_class, 'error': exc})

    response = req.response
    response.status = 204
    response.content_type = None
    return response
Beispiel #6
0
def update_inventory(req):
    """PUT to update one inventory.

    If the resource generation is out of sync, return a 409.
    If the inventory has settings which are invalid (for example
    reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventory.
    """
    context = req.environ['placement.context']
    context.can(policies.UPDATE)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)

    data = _extract_inventory(req.body, schema.BASE_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'),
            comment=errors.CONCURRENT_UPDATE)

    inventory = _make_inventory_object(resource_provider, resource_class,
                                       **data)

    try:
        _validate_inventory_capacity(
            req.environ[microversion.MICROVERSION_ENVIRON], inventory)
        resource_provider.update_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(_('update conflict: %(error)s') %
                                     {'error': exc},
                                     comment=errors.CONCURRENT_UPDATE)
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('No inventory record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })

    return _send_inventory(req, resource_provider, inventory)
Beispiel #7
0
def update_inventory(req):
    """PUT to update one inventory.

    If the resource generation is out of sync, return a 409.
    If the inventory has settings which are invalid (for example
    reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)

    data = _extract_inventory(req.body, BASE_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'),
            json_formatter=util.json_error_formatter)

    inventory = _make_inventory_object(resource_provider, resource_class,
                                       **data)

    try:
        resource_provider.update_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(_('update conflict: %(error)s') %
                                     {'error': exc},
                                     json_formatter=util.json_error_formatter)
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('No inventory record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              },
            json_formatter=util.json_error_formatter)
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              },
            json_formatter=util.json_error_formatter)

    return _send_inventory(req.response, resource_provider, inventory)
Beispiel #8
0
def update_inventory(req):
    """PUT to update one inventory.

    If the resource generation is out of sync, return a 409.
    If the inventory has settings which are invalid (for example
    reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventory.
    """
    context = req.environ['placement.context']
    context.can(policies.UPDATE)
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)

    data = _extract_inventory(req.body, schema.BASE_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'),
            comment=errors.CONCURRENT_UPDATE)

    inventory = make_inventory_object(resource_provider,
                                      resource_class,
                                      **data)

    try:
        _validate_inventory_capacity(
            req.environ[microversion.MICROVERSION_ENVIRON], inventory)
        resource_provider.update_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc},
            comment=errors.CONCURRENT_UPDATE)
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('No inventory record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                           'error': exc})
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                          'error': exc})

    return _send_inventory(req, resource_provider, inventory)
Beispiel #9
0
def update_inventory(req):
    """PUT to update one inventory.

    If the resource generation is out of sync, return a 409.
    If the inventory has settings which are invalid (for example
    reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    data = _extract_inventory(req.body, BASE_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'),
            json_formatter=util.json_error_formatter)

    inventory = _make_inventory_object(resource_provider,
                                       resource_class,
                                       **data)

    try:
        resource_provider.update_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc},
            json_formatter=util.json_error_formatter)
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('No inventory record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                           'error': exc},
            json_formatter=util.json_error_formatter)
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                          'error': exc},
            json_formatter=util.json_error_formatter)

    return _send_inventory(req.response, resource_provider, inventory)
Beispiel #10
0
def update_resource_provider(req):
    """PUT to update a single resource provider.

    On success return a 200 response with a representation of the updated
    resource provider.
    """
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    context = req.environ['placement.context']

    # The containing application will catch a not found here.
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    data = _extract_resource_provider(req.body,
                                      PUT_RESOURCE_PROVIDER_SCHEMA)

    resource_provider.name = data['name']

    try:
        resource_provider.save()
    except db_exc.DBDuplicateEntry as exc:
        raise webob.exc.HTTPConflict(
            'Conflicting resource provider already exists: %s' % exc,
            json_formatter=util.json_error_formatter)
    except exception.ObjectActionError as exc:
        raise webob.exc.HTTPBadRequest(
            'Unable to save resource provider %s: %s' % (uuid, exc),
            json_formatter=util.json_error_formatter)

    req.response.body = jsonutils.dumps(
        _serialize_provider(req.environ, resource_provider))
    req.response.status = 200
    req.response.content_type = 'application/json'
    return req.response
Beispiel #11
0
def list_for_resource_provider(req):
    """List allocations associated with a resource provider."""
    # TODO(cdent): On a shared resource provider (for example a
    # giant disk farm) this list could get very long. At the moment
    # we have no facility for limiting the output. Given that we are
    # using a dict of dicts for the output we are potentially limiting
    # ourselves in terms of sorting and filtering.
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # confirm existence of resource provider so we get a reasonable
    # 404 instead of empty list
    try:
        resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("Resource provider '%(rp_uuid)s' not found: %(error)s") % {
                'rp_uuid': uuid,
                'error': exc
            })

    allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
        context, uuid)

    allocations_json = jsonutils.dumps(
        _serialize_allocations_for_resource_provider(allocations,
                                                     resource_provider))

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(allocations_json)
    req.response.content_type = 'application/json'
    return req.response
Beispiel #12
0
def update_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    data = util.extract_json(req.body, SET_TRAITS_FOR_RP_SCHEMA)
    rp_gen = data['resource_provider_generation']
    traits = data['traits']
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    if resource_provider.generation != rp_gen:
        raise webob.exc.HTTPConflict(
            _("Resource provider's generation already changed. Please update "
              "the generation and try again."),
            json_formatter=util.json_error_formatter)

    trait_objs = objects.TraitList.get_all(
        context, filters={'name_in': traits})
    traits_name = set([obj.name for obj in trait_objs])
    non_existed_trait = set(traits) - set(traits_name)
    if non_existed_trait:
        raise webob.exc.HTTPBadRequest(
            _("No such trait %s") % ', '.join(non_existed_trait))

    resource_provider.set_traits(trait_objs)

    response_body = _serialize_traits(trait_objs)
    response_body[
        'resource_provider_generation'] = resource_provider.generation
    req.response.status = 200
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(response_body))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #13
0
def get_resource_class(req):
    """Get a single resource class.

    On success return a 200 with an application/json body representing
    the resource class.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']
    context.can(policies.SHOW)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    # The containing application will catch a not found here.
    rc = rp_obj.ResourceClass.get_by_name(context, name)

    req.response.body = encodeutils.to_utf8(jsonutils.dumps(
        _serialize_resource_class(req.environ, rc))
    )
    req.response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        req.response.cache_control = 'no-cache'
        # Non-custom resource classes will return None from pick_last_modified,
        # so the 'or' causes utcnow to be used.
        last_modified = util.pick_last_modified(None, rc) or timeutils.utcnow(
            with_timezone=True)
        req.response.last_modified = last_modified
    return req.response
Beispiel #14
0
def update_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    data = util.extract_json(req.body, SET_TRAITS_FOR_RP_SCHEMA)
    rp_gen = data['resource_provider_generation']
    traits = data['traits']
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)

    if resource_provider.generation != rp_gen:
        raise webob.exc.HTTPConflict(
            _("Resource provider's generation already changed. Please update "
              "the generation and try again."),
            json_formatter=util.json_error_formatter)

    trait_objs = rp_obj.TraitList.get_all(
        context, filters={'name_in': traits})
    traits_name = set([obj.name for obj in trait_objs])
    non_existed_trait = set(traits) - set(traits_name)
    if non_existed_trait:
        raise webob.exc.HTTPBadRequest(
            _("No such trait %s") % ', '.join(non_existed_trait))

    resource_provider.set_traits(trait_objs)

    response_body = _serialize_traits(trait_objs)
    response_body[
        'resource_provider_generation'] = resource_provider.generation
    req.response.status = 200
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(response_body))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #15
0
def delete_inventories(req):
    """DELETE all inventory for a resource provider.

    Delete inventory as required to reset all the inventory.
    If an inventory to be deleted is in use, return a 409 Conflict.
    On success return a 204 No content.
    Return 405 Method Not Allowed if the wanted microversion does not match.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)

    inventories = rp_obj.InventoryList(objects=[])

    try:
        resource_provider.set_inventory(inventories)
    except exception.ConcurrentUpdateDetected:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory for resource provider '
              '%(rp_uuid)s because the inventory was updated by '
              'another process. Please retry your request.') %
            {'rp_uuid': resource_provider.uuid})
    except exception.InventoryInUse as ex:
        # NOTE(mriedem): This message cannot change without impacting the
        # nova.scheduler.client.report._RE_INV_IN_USE regex.
        raise webob.exc.HTTPConflict(explanation=ex.format_message())

    response = req.response
    response.status = 204
    response.content_type = None

    return response
Beispiel #16
0
def delete_resource_provider(req):
    """DELETE to destroy a single resource provider.

    On success return a 204 and an empty body.
    """
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    context = req.environ['placement.context']
    context.can(policies.DELETE)
    # The containing application will catch a not found here.
    try:
        resource_provider = rp_obj.ResourceProvider.get_by_uuid(
            context, uuid)
        resource_provider.destroy()
    except exception.ResourceProviderInUse as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to delete resource provider %(rp_uuid)s: %(error)s') %
            {'rp_uuid': uuid, 'error': exc},
            comment=errors.PROVIDER_IN_USE)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %s found for delete") % uuid)
    except exception.CannotDeleteParentResourceProvider as exc:
        raise webob.exc.HTTPConflict(
            _("Unable to delete parent resource provider %(rp_uuid)s: "
              "It has child resource providers.") % {'rp_uuid': uuid},
            comment=errors.PROVIDER_CANNOT_DELETE_PARENT)
    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #17
0
def delete_inventories(req):
    """DELETE all inventory for a resource provider.

    Delete inventory as required to reset all the inventory.
    If an inventory to be deleted is in use, return a 409 Conflict.
    On success return a 204 No content.
    Return 405 Method Not Allowed if the wanted microversion does not match.
    """
    microversion.raise_http_status_code_if_not_version(req, 405, (1, 5))
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    inventories = objects.InventoryList(objects=[])

    try:
        resource_provider.set_inventory(inventories)
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc})

    response = req.response
    response.status = 204
    response.content_type = None

    return response
Beispiel #18
0
def list_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    context.can(policies.RP_TRAIT_LIST)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # Resource provider object is needed for two things: If it is
    # NotFound we'll get a 404 here, which needs to happen because
    # get_all_by_resource_provider can return an empty list.
    # It is also needed for the generation, used in the outgoing
    # representation.
    try:
        rp = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %(uuid)s found: %(error)s") %
             {'uuid': uuid, 'error': exc})

    traits = rp_obj.TraitList.get_all_by_resource_provider(context, rp)
    response_body, last_modified = _serialize_traits(traits, want_version)
    response_body["resource_provider_generation"] = rp.generation

    if want_version.matches((1, 15)):
        req.response.last_modified = last_modified
        req.response.cache_control = 'no-cache'

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(response_body))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #19
0
def set_aggregates(req):
    context = req.environ['placement.context']
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    consider_generation = want_version.matches(
        min_version=_INCLUDE_GENERATION_VERSION)
    put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_1
    if consider_generation:
        put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_19
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)
    data = util.extract_json(req.body, put_schema)
    if consider_generation:
        # Check for generation conflict
        rp_gen = data['resource_provider_generation']
        if resource_provider.generation != rp_gen:
            raise webob.exc.HTTPConflict(
                _("Resource provider's generation already changed. Please "
                  "update the generation and try again."))
        aggregate_uuids = data['aggregates']
    else:
        aggregate_uuids = data
    try:
        resource_provider.set_aggregates(
            aggregate_uuids, increment_generation=consider_generation)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('Update conflict: %(error)s') % {'error': exc})

    return _send_aggregates(req, resource_provider, aggregate_uuids)
Beispiel #20
0
def list_for_consumer(req):
    """List allocations associated with a consumer."""
    context = req.environ['placement.context']
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    consumer_id = util.wsgi_path_item(req.environ, 'consumer_uuid')
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]

    # NOTE(cdent): There is no way for a 404 to be returned here,
    # only an empty result. We do not have a way to validate a
    # consumer id.
    allocations = rp_obj.AllocationList.get_all_by_consumer_id(
        context, consumer_id)

    output, last_modified = _serialize_allocations_for_consumer(
        allocations, want_version)
    allocations_json = jsonutils.dumps(output)

    response = req.response
    response.status = 200
    response.body = encodeutils.to_utf8(allocations_json)
    response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        response.last_modified = last_modified
        response.cache_control = 'no-cache'
    return response
Beispiel #21
0
def update_resource_class(req):
    """PUT to create or validate the existence of single resource class.

    On a successful create return 201. Return 204 if the class already
    exists. If the resource class is not a custom resource class, return
    a 400. 409 might be a better choice, but 400 aligns with previous code.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']

    # Use JSON validation to validation resource class name.
    util.extract_json('{"name": "%s"}' % name, PUT_RC_SCHEMA_V1_2)

    status = 204
    try:
        rc = objects.ResourceClass.get_by_name(context, name)
    except exception.NotFound:
        try:
            rc = objects.ResourceClass(context, name=name)
            rc.create()
            status = 201
        # We will not see ResourceClassCannotUpdateStandard because
        # that was already caught when validating the {name}.
        except exception.ResourceClassExists:
            # Someone just now created the class, so stick with 204
            pass

    req.response.status = status
    req.response.content_type = None
    req.response.location = util.resource_class_url(req.environ, rc)
    return req.response
Beispiel #22
0
def set_aggregates(req):
    context = req.environ['placement.context']
    context.can(policies.UPDATE)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    consider_generation = want_version.matches(
        min_version=_INCLUDE_GENERATION_VERSION)
    put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_1
    if consider_generation:
        put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_19
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
        context, uuid)
    data = util.extract_json(req.body, put_schema)
    if consider_generation:
        # Check for generation conflict
        rp_gen = data['resource_provider_generation']
        if resource_provider.generation != rp_gen:
            raise webob.exc.HTTPConflict(
                _("Resource provider's generation already changed. Please "
                  "update the generation and try again."),
                comment=errors.CONCURRENT_UPDATE)
        aggregate_uuids = data['aggregates']
    else:
        aggregate_uuids = data
    _set_aggregates(resource_provider, aggregate_uuids,
                    increment_generation=consider_generation)

    return _send_aggregates(req, resource_provider, aggregate_uuids)
Beispiel #23
0
def put_trait(req):
    context = req.environ['placement.context']
    context.can(policies.TRAITS_UPDATE)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    name = util.wsgi_path_item(req.environ, 'name')

    try:
        jsonschema.validate(name, schema.CUSTOM_TRAIT)
    except jsonschema.ValidationError:
        raise webob.exc.HTTPBadRequest(
            _('The trait is invalid. A valid trait must be no longer than '
              '255 characters, start with the prefix "CUSTOM_" and use '
              'following characters: "A"-"Z", "0"-"9" and "_"'))

    trait = rp_obj.Trait(context)
    trait.name = name

    try:
        trait.create()
        req.response.status = 201
    except exception.TraitExists:
        # Get the trait that already exists to get last-modified time.
        if want_version.matches((1, 15)):
            trait = rp_obj.Trait.get_by_name(context, name)
        req.response.status = 204

    req.response.content_type = None
    req.response.location = util.trait_url(req.environ, trait)
    if want_version.matches((1, 15)):
        req.response.last_modified = trait.created_at
        req.response.cache_control = 'no-cache'
    return req.response
Beispiel #24
0
def set_aggregates(req):
    context = req.environ['placement.context']
    context.can(policies.UPDATE)
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    consider_generation = want_version.matches(
        min_version=_INCLUDE_GENERATION_VERSION)
    put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_1
    if consider_generation:
        put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_19
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    data = util.extract_json(req.body, put_schema)
    if consider_generation:
        # Check for generation conflict
        rp_gen = data['resource_provider_generation']
        if resource_provider.generation != rp_gen:
            raise webob.exc.HTTPConflict(_(
                "Resource provider's generation already changed. Please "
                "update the generation and try again."),
                                         comment=errors.CONCURRENT_UPDATE)
        aggregate_uuids = data['aggregates']
    else:
        aggregate_uuids = data
    _set_aggregates(resource_provider,
                    aggregate_uuids,
                    increment_generation=consider_generation)

    return _send_aggregates(req, resource_provider, aggregate_uuids)
Beispiel #25
0
def delete_allocations(req):
    context = req.environ['placement.context']
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')

    allocations = objects.AllocationList.get_all_by_consumer_id(
        context, consumer_uuid)
    if allocations:
        try:
            allocations.delete_all()
        # NOTE(pumaranikar): Following NotFound exception added in the case
        # when allocation is deleted from allocations list by some other
        # activity. In that case, delete_all() will throw a NotFound exception.
        except exception.NotFound as exc:
            raise webob.exc.HTPPNotFound(
                  _("Allocation for consumer with id %(id)s not found."
                    "error: %(error)s") %
                  {'id': consumer_uuid, 'error': exc})
    else:
        raise webob.exc.HTTPNotFound(
            _("No allocations for consumer '%(consumer_uuid)s'") %
            {'consumer_uuid': consumer_uuid})
    LOG.debug("Successfully deleted allocations %s", allocations)

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #26
0
def update_resource_provider(req):
    """PUT to update a single resource provider.

    On success return a 200 response with a representation of the updated
    resource provider.
    """
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    context = req.environ['placement.context']

    # The containing application will catch a not found here.
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    data = util.extract_json(req.body, PUT_RESOURCE_PROVIDER_SCHEMA)

    resource_provider.name = data['name']

    try:
        resource_provider.save()
    except db_exc.DBDuplicateEntry as exc:
        raise webob.exc.HTTPConflict(
            _('Conflicting resource provider already exists: %(error)s') %
            {'error': exc},
            json_formatter=util.json_error_formatter)
    except exception.ObjectActionError as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to save resource provider %(rp_uuid)s: %(error)s') %
            {'rp_uuid': uuid, 'error': exc},
            json_formatter=util.json_error_formatter)

    req.response.body = jsonutils.dumps(
        _serialize_provider(req.environ, resource_provider))
    req.response.status = 200
    req.response.content_type = 'application/json'
    return req.response
Beispiel #27
0
def list_for_consumer(req):
    """List allocations associated with a consumer."""
    context = req.environ['placement.context']
    context.can(policies.ALLOC_LIST)
    consumer_id = util.wsgi_path_item(req.environ, 'consumer_uuid')
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]

    # NOTE(cdent): There is no way for a 404 to be returned here,
    # only an empty result. We do not have a way to validate a
    # consumer id.
    allocations = rp_obj.AllocationList.get_all_by_consumer_id(
        context, consumer_id)

    output = _serialize_allocations_for_consumer(allocations, want_version)
    last_modified = _last_modified_from_allocations(allocations, want_version)
    allocations_json = jsonutils.dumps(output)

    response = req.response
    response.status = 200
    response.body = encodeutils.to_utf8(allocations_json)
    response.content_type = 'application/json'
    if want_version.matches((1, 15)):
        response.last_modified = last_modified
        response.cache_control = 'no-cache'
    return response
Beispiel #28
0
def set_inventories(req):
    """PUT to set all inventory for a resource provider.

    Create, update and delete inventory as required to reset all
    the inventory.

    If the resource generation is out of sync, return a 409.
    If an inventory to be deleted is in use, return a 409.
    If any inventory to be created or updated has settings which are
    invalid (for example reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventories.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)

    data = _extract_inventories(req.body, PUT_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'))

    inv_list = []
    for res_class, inventory_data in data['inventories'].items():
        inventory = _make_inventory_object(resource_provider, res_class,
                                           **inventory_data)
        inv_list.append(inventory)
    inventories = rp_obj.InventoryList(objects=inv_list)

    try:
        resource_provider.set_inventory(inventories)
    except exception.ResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unknown resource class in inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPConflict(
            _('Race condition detected when setting inventory. No inventory '
              'record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })
    except (exception.ConcurrentUpdateDetected, exception.InventoryInUse,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc})
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })

    return _send_inventories(req, resource_provider, inventories)
Beispiel #29
0
def list_usages(req):
    """GET a dictionary of resource provider usage by resource class.

    If the resource provider does not exist return a 404.

    On success return a 200 with an application/json representation of
    the usage dictionary.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # Resource provider object needed for two things: If it is
    # NotFound we'll get a 404 here, which needs to happen because
    # get_all_by_resource_provider_uuid can return an empty list.
    # It is also needed for the generation, used in the outgoing
    # representation.
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)
    usage = objects.UsageList.get_all_by_resource_provider_uuid(
        context, uuid)

    response = req.response
    response.body = jsonutils.dumps(
        _serialize_usages(resource_provider, usage))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #30
0
def update_resource_provider(req):
    """PUT to update a single resource provider.

    On success return a 200 response with a representation of the updated
    resource provider.
    """
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    context = req.environ['placement.context']

    # The containing application will catch a not found here.
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)

    data = util.extract_json(req.body, PUT_RESOURCE_PROVIDER_SCHEMA)

    resource_provider.name = data['name']

    try:
        resource_provider.save()
    except db_exc.DBDuplicateEntry as exc:
        raise webob.exc.HTTPConflict(
            _('Conflicting resource provider %(name)s already exists.') %
            {'name': data['name']})
    except exception.ObjectActionError as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to save resource provider %(rp_uuid)s: %(error)s') % {
                'rp_uuid': uuid,
                'error': exc
            })

    req.response.body = encodeutils.to_utf8(
        jsonutils.dumps(_serialize_provider(req.environ, resource_provider)))
    req.response.status = 200
    req.response.content_type = 'application/json'
    return req.response
Beispiel #31
0
def list_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # Resource provider object is needed for two things: If it is
    # NotFound we'll get a 404 here, which needs to happen because
    # get_all_by_resource_provider can return an empty list.
    # It is also needed for the generation, used in the outgoing
    # representation.
    try:
        rp = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %(uuid)s found: %(error)s") %
             {'uuid': uuid, 'error': exc})

    traits = rp_obj.TraitList.get_all_by_resource_provider(context, rp)
    response_body, last_modified = _serialize_traits(traits, want_version)
    response_body["resource_provider_generation"] = rp.generation

    if want_version.matches((1, 15)):
        req.response.last_modified = last_modified
        req.response.cache_control = 'no-cache'

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(response_body))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #32
0
def delete_allocations(req):
    context = req.environ['placement.context']
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')

    allocations = objects.AllocationList.get_all_by_consumer_id(
        context, consumer_uuid)
    if allocations:
        try:
            allocations.delete_all()
        # NOTE(pumaranikar): Following NotFound exception added in the case
        # when allocation is deleted from allocations list by some other
        # activity. In that case, delete_all() will throw a NotFound exception.
        except exception.NotFound as exc:
            raise webob.exc.HTPPNotFound(
                _("Allocation for consumer with id %(id)s not found."
                  "error: %(error)s") % {
                      'id': consumer_uuid,
                      'error': exc
                  })
    else:
        raise webob.exc.HTTPNotFound(
            _("No allocations for consumer '%(consumer_uuid)s'") %
            {'consumer_uuid': consumer_uuid})
    LOG.debug("Successfully deleted allocations %s", allocations)

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #33
0
def put_trait(req):
    context = req.environ['placement.context']
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    name = util.wsgi_path_item(req.environ, 'name')

    try:
        jsonschema.validate(name, schema.CUSTOM_TRAIT)
    except jsonschema.ValidationError:
        raise webob.exc.HTTPBadRequest(
            _('The trait is invalid. A valid trait must be no longer than '
              '255 characters, start with the prefix "CUSTOM_" and use '
              'following characters: "A"-"Z", "0"-"9" and "_"'))

    trait = rp_obj.Trait(context)
    trait.name = name

    try:
        trait.create()
        req.response.status = 201
    except exception.TraitExists:
        # Get the trait that already exists to get last-modified time.
        if want_version.matches((1, 15)):
            trait = rp_obj.Trait.get_by_name(context, name)
        req.response.status = 204

    req.response.content_type = None
    req.response.location = util.trait_url(req.environ, trait)
    if want_version.matches((1, 15)):
        req.response.last_modified = trait.created_at
        req.response.cache_control = 'no-cache'
    return req.response
Beispiel #34
0
def list_for_resource_provider(req):
    """List allocations associated with a resource provider."""
    # TODO(cdent): On a shared resource provider (for example a
    # giant disk farm) this list could get very long. At the moment
    # we have no facility for limiting the output. Given that we are
    # using a dict of dicts for the output we are potentially limiting
    # ourselves in terms of sorting and filtering.
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # confirm existence of resource provider so we get a reasonable
    # 404 instead of empty list
    try:
        resource_provider = objects.ResourceProvider.get_by_uuid(
            context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("Resource provider '%(rp_uuid)s' not found: %(error)s") %
            {'rp_uuid': uuid, 'error': exc})

    allocations = objects.AllocationList.get_all_by_resource_provider_uuid(
        context, uuid)

    allocations_json = jsonutils.dumps(
        _serialize_allocations_for_resource_provider(
            allocations, resource_provider))

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(allocations_json)
    req.response.content_type = 'application/json'
    return req.response
Beispiel #35
0
def create_inventory(req):
    """POST to create one inventory.

    On success return a 201 response, a location header pointing
    to the newly created inventory and an application/json representation
    of the inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)
    data = _extract_inventory(req.body, POST_INVENTORY_SCHEMA)

    inventory = _make_inventory_object(resource_provider, **data)

    try:
        resource_provider.add_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict('Update conflict: %s' % exc,
                                     json_formatter=util.json_error_formatter)
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            'Unable to create inventory for resource provider %s: %s' %
            (resource_provider.uuid, exc),
            json_formatter=util.json_error_formatter)

    response = req.response
    response.location = util.inventory_url(req.environ, resource_provider,
                                           data['resource_class'])
    return _send_inventory(response, resource_provider, inventory, status=201)
Beispiel #36
0
def delete_inventories(req):
    """DELETE all inventory for a resource provider.

    Delete inventory as required to reset all the inventory.
    If an inventory to be deleted is in use, return a 409 Conflict.
    On success return a 204 No content.
    Return 405 Method Not Allowed if the wanted microversion does not match.
    """
    microversion.raise_http_status_code_if_not_version(req, 405, (1, 5))
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)

    inventories = objects.InventoryList(objects=[])

    try:
        resource_provider.set_inventory(inventories)
    except exception.ConcurrentUpdateDetected:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory for resource provider '
              '%(rp_uuid)s because the inventory was updated by '
              'another process. Please retry your request.') %
            {'rp_uuid': resource_provider.uuid})
    except exception.InventoryInUse:
        raise webob.exc.HTTPConflict(
            _('Unable to delete inventory for resource provider '
              '%(rp_uuid)s because the inventory is in use.') %
            {'rp_uuid': resource_provider.uuid})

    response = req.response
    response.status = 204
    response.content_type = None

    return response
Beispiel #37
0
def update_resource_class(req):
    """PUT to create or validate the existence of single resource class.

    On a successful create return 201. Return 204 if the class already
    exists. If the resource class is not a custom resource class, return
    a 400. 409 might be a better choice, but 400 aligns with previous code.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']
    context.can(policies.UPDATE)

    # Use JSON validation to validation resource class name.
    util.extract_json('{"name": "%s"}' % name, schema.PUT_RC_SCHEMA_V1_2)

    status = 204
    try:
        rc = rp_obj.ResourceClass.get_by_name(context, name)
    except exception.NotFound:
        try:
            rc = rp_obj.ResourceClass(context, name=name)
            rc.create()
            status = 201
        # We will not see ResourceClassCannotUpdateStandard because
        # that was already caught when validating the {name}.
        except exception.ResourceClassExists:
            # Someone just now created the class, so stick with 204
            pass

    req.response.status = status
    req.response.content_type = None
    req.response.location = util.resource_class_url(req.environ, rc)
    return req.response
Beispiel #38
0
def delete_resource_class(req):
    """DELETE to destroy a single resource class.

    On success return a 204 and an empty body.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']
    # The containing application will catch a not found here.
    rc = objects.ResourceClass.get_by_name(context, name)
    try:
        rc.destroy()
    except exception.ResourceClassCannotDeleteStandard as exc:
        raise webob.exc.HTTPBadRequest(
            _('Cannot delete standard resource class %(rp_name)s: %(error)s') %
            {
                'rp_name': name,
                'error': exc
            },
            json_formatter=util.json_error_formatter)
    except exception.ResourceClassInUse as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to delete resource class %(rp_name)s: %(error)s') % {
                'rp_name': name,
                'error': exc
            },
            json_formatter=util.json_error_formatter)
    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #39
0
def _set_allocations(req, schema):
    context = req.environ['placement.context']
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')
    data = util.extract_json(req.body, schema)
    allocation_data = data['allocations']

    # If the body includes an allocation for a resource provider
    # that does not exist, raise a 400.
    allocation_objects = []
    for allocation in allocation_data:
        resource_provider_uuid = allocation['resource_provider']['uuid']

        try:
            resource_provider = rp_obj.ResourceProvider.get_by_uuid(
                context, resource_provider_uuid)
        except exception.NotFound:
            raise webob.exc.HTTPBadRequest(
                _("Allocation for resource provider '%(rp_uuid)s' "
                  "that does not exist.") %
                {'rp_uuid': resource_provider_uuid})

        resources = allocation['resources']
        for resource_class in resources:
            allocation = rp_obj.Allocation(resource_provider=resource_provider,
                                           consumer_id=consumer_uuid,
                                           resource_class=resource_class,
                                           used=resources[resource_class])
            allocation_objects.append(allocation)

    allocations = rp_obj.AllocationList(
        context,
        objects=allocation_objects,
        project_id=data.get('project_id'),
        user_id=data.get('user_id'),
    )

    try:
        allocations.create_all()
        LOG.debug("Successfully wrote allocations %s", allocations)
    # InvalidInventory is a parent for several exceptions that
    # indicate either that Inventory is not present, or that
    # capacity limits have been exceeded.
    except exception.NotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _("Unable to allocate inventory for resource provider "
              "%(rp_uuid)s: %(error)s") % {
                  'rp_uuid': resource_provider_uuid,
                  'error': exc
              })
    except exception.InvalidInventory as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to allocate inventory: %(error)s') % {'error': exc})
    except exception.ConcurrentUpdateDetected as exc:
        raise webob.exc.HTTPConflict(
            _('Inventory changed while attempting to allocate: %(error)s') %
            {'error': exc})

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #40
0
def list_usages(req):
    """GET a dictionary of resource provider usage by resource class.

    If the resource provider does not exist return a 404.

    On success return a 200 with an application/json representation of
    the usage dictionary.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    # Resource provider object needed for two things: If it is
    # NotFound we'll get a 404 here, which needs to happen because
    # get_all_by_resource_provider_uuid can return an empty list.
    # It is also needed for the generation, used in the outgoing
    # representation.
    try:
        resource_provider = objects.ResourceProvider.get_by_uuid(
            context, uuid)
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %(uuid)s found: %(error)s") %
             {'uuid': uuid, 'error': exc})

    usage = objects.UsageList.get_all_by_resource_provider_uuid(
        context, uuid)

    response = req.response
    response.body = encodeutils.to_utf8(jsonutils.dumps(
        _serialize_usages(resource_provider, usage)))
    req.response.content_type = 'application/json'
    return req.response
Beispiel #41
0
def update_resource_class(req):
    """PUT to update a single resource class.

    On success return a 200 response with a representation of the updated
    resource class.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']

    data = util.extract_json(req.body, PUT_RC_SCHEMA_V1_2)

    # The containing application will catch a not found here.
    rc = objects.ResourceClass.get_by_name(context, name)

    rc.name = data['name']

    try:
        rc.save()
    except exception.ResourceClassExists:
        raise webob.exc.HTTPConflict(
            _('Resource class already exists: %(name)s') % {'name': rc.name},
            json_formatter=util.json_error_formatter)
    except exception.ResourceClassCannotUpdateStandard:
        raise webob.exc.HTTPBadRequest(
            _('Cannot update standard resource class %(rp_name)s') %
            {'rp_name': name},
            json_formatter=util.json_error_formatter)

    req.response.body = encodeutils.to_utf8(
        jsonutils.dumps(_serialize_resource_class(req.environ, rc)))
    req.response.status = 200
    req.response.content_type = 'application/json'
    return req.response
Beispiel #42
0
def update_resource_class(req):
    """PUT to update a single resource class.

    On success return a 200 response with a representation of the updated
    resource class.
    """
    name = util.wsgi_path_item(req.environ, 'name')
    context = req.environ['placement.context']

    data = util.extract_json(req.body, PUT_RC_SCHEMA_V1_2)

    # The containing application will catch a not found here.
    rc = objects.ResourceClass.get_by_name(context, name)

    rc.name = data['name']

    try:
        rc.save()
    except exception.ResourceClassExists:
        raise webob.exc.HTTPConflict(
            _('Resource class already exists: %(name)s') %
            {'name': name},
            json_formatter=util.json_error_formatter)
    except exception.ResourceClassCannotUpdateStandard:
        raise webob.exc.HTTPBadRequest(
            _('Cannot update standard resource class %(rp_name)s') %
            {'rp_name': name},
            json_formatter=util.json_error_formatter)

    req.response.body = jsonutils.dumps(
        _serialize_resource_class(req.environ, rc)
    )
    req.response.status = 200
    req.response.content_type = 'application/json'
    return req.response
Beispiel #43
0
def create_inventory(req):
    """POST to create one inventory.

    On success return a 201 response, a location header pointing
    to the newly created inventory and an application/json representation
    of the inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    data = _extract_inventory(req.body, POST_INVENTORY_SCHEMA)
    resource_class = data.pop('resource_class')

    inventory = _make_inventory_object(resource_provider, resource_class,
                                       **data)

    try:
        resource_provider.add_inventory(inventory)
    except (exception.ConcurrentUpdateDetected,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('Update conflict: %(error)s') % {'error': exc})
    except (exception.InvalidInventoryCapacity, exception.NotFound) as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to create inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {
                  'rp_uuid': resource_provider.uuid,
                  'error': exc
              })

    response = req.response
    response.location = util.inventory_url(req.environ, resource_provider,
                                           resource_class)
    return _send_inventory(req, resource_provider, inventory, status=201)
Beispiel #44
0
def _set_allocations(req, schema):
    context = req.environ['placement.context']
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')
    data = util.extract_json(req.body, schema)
    allocation_data = data['allocations']

    # If the body includes an allocation for a resource provider
    # that does not exist, raise a 400.
    allocation_objects = []
    for allocation in allocation_data:
        resource_provider_uuid = allocation['resource_provider']['uuid']

        try:
            resource_provider = objects.ResourceProvider.get_by_uuid(
                context, resource_provider_uuid)
        except exception.NotFound:
            raise webob.exc.HTTPBadRequest(
                _("Allocation for resource provider '%(rp_uuid)s' "
                  "that does not exist.") %
                {'rp_uuid': resource_provider_uuid})

        resources = allocation['resources']
        for resource_class in resources:
            allocation = objects.Allocation(
                resource_provider=resource_provider,
                consumer_id=consumer_uuid,
                resource_class=resource_class,
                used=resources[resource_class])
            allocation_objects.append(allocation)

    allocations = objects.AllocationList(
        context,
        objects=allocation_objects,
        project_id=data.get('project_id'),
        user_id=data.get('user_id'),
    )

    try:
        allocations.create_all()
        LOG.debug("Successfully wrote allocations %s", allocations)
    # InvalidInventory is a parent for several exceptions that
    # indicate either that Inventory is not present, or that
    # capacity limits have been exceeded.
    except exception.NotFound as exc:
        raise webob.exc.HTTPBadRequest(
                _("Unable to allocate inventory for resource provider "
                  "%(rp_uuid)s: %(error)s") %
            {'rp_uuid': resource_provider_uuid, 'error': exc})
    except exception.InvalidInventory as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to allocate inventory: %(error)s') % {'error': exc})
    except exception.ConcurrentUpdateDetected as exc:
        raise webob.exc.HTTPConflict(
            _('Inventory changed while attempting to allocate: %(error)s') %
            {'error': exc})

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #45
0
def set_aggregates(req):
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    aggregate_uuids = util.extract_json(req.body, schema.PUT_AGGREGATES_SCHEMA)
    resource_provider.set_aggregates(aggregate_uuids)

    return _send_aggregates(req, aggregate_uuids)
Beispiel #46
0
def set_aggregates(req):
    microversion.raise_404_if_not_version(req, (1, 1))
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)
    aggregate_uuids = util.extract_json(req.body, PUT_AGGREGATES_SCHEMA)
    resource_provider.set_aggregates(aggregate_uuids)

    return _send_aggregates(req.response, aggregate_uuids)
Beispiel #47
0
def set_inventories(req):
    """PUT to set all inventory for a resource provider.

    Create, update and delete inventory as required to reset all
    the inventory.

    If the resource generation is out of sync, return a 409.
    If an inventory to be deleted is in use, return a 409.
    If any inventory to be created or updated has settings which are
    invalid (for example reserved exceeds capacity), return a 400.

    On success return a 200 with an application/json body representing
    the inventories.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    data = _extract_inventories(req.body, PUT_INVENTORY_SCHEMA)
    if data['resource_provider_generation'] != resource_provider.generation:
        raise webob.exc.HTTPConflict(
            _('resource provider generation conflict'))

    inv_list = []
    for res_class, inventory_data in data['inventories'].items():
        inventory = _make_inventory_object(
            resource_provider, res_class, **inventory_data)
        inv_list.append(inventory)
    inventories = objects.InventoryList(objects=inv_list)

    try:
        resource_provider.set_inventory(inventories)
    except exception.ResourceClassNotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unknown resource class in inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                           'error': exc})
    except exception.InventoryWithResourceClassNotFound as exc:
        raise webob.exc.HTTPConflict(
            _('Race condition detected when setting inventory. No inventory '
              'record with resource class for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                           'error': exc})
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'error': exc})
    except exception.InvalidInventoryCapacity as exc:
        raise webob.exc.HTTPBadRequest(
            _('Unable to update inventory for resource provider '
              '%(rp_uuid)s: %(error)s') % {'rp_uuid': resource_provider.uuid,
                                          'error': exc})

    return _send_inventories(req.response, resource_provider, inventories)
Beispiel #48
0
def _set_allocations_for_consumer(req, schema):
    context = req.environ['placement.context']
    context.can(policies.ALLOC_UPDATE)
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')
    data = util.extract_json(req.body, schema)
    allocation_data = data['allocations']

    # Normalize allocation data to dict.
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
    if not want_version.matches((1, 12)):
        allocations_dict = {}
        # Allocation are list-ish, transform to dict-ish
        for allocation in allocation_data:
            resource_provider_uuid = allocation['resource_provider']['uuid']
            allocations_dict[resource_provider_uuid] = {
                'resources': allocation['resources']
            }
        allocation_data = allocations_dict

    # If the body includes an allocation for a resource provider
    # that does not exist, raise a 400.
    allocation_objects = []
    for resource_provider_uuid, allocation in allocation_data.items():
        new_allocations = _new_allocations(context, resource_provider_uuid,
                                           consumer_uuid,
                                           allocation['resources'],
                                           data.get('project_id'),
                                           data.get('user_id'))
        allocation_objects.extend(new_allocations)

    allocations = rp_obj.AllocationList(context, objects=allocation_objects)

    try:
        allocations.create_all()
        LOG.debug("Successfully wrote allocations %s", allocations)
    # InvalidInventory is a parent for several exceptions that
    # indicate either that Inventory is not present, or that
    # capacity limits have been exceeded.
    except exception.NotFound as exc:
        raise webob.exc.HTTPBadRequest(
            _("Unable to allocate inventory for consumer "
              "%(consumer_uuid)s: %(error)s") % {
                  'consumer_uuid': consumer_uuid,
                  'error': exc
              })
    except exception.InvalidInventory as exc:
        raise webob.exc.HTTPConflict(
            _('Unable to allocate inventory: %(error)s') % {'error': exc})
    except exception.ConcurrentUpdateDetected as exc:
        raise webob.exc.HTTPConflict(
            _('Inventory changed while attempting to allocate: %(error)s') %
            {'error': exc})

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #49
0
def set_aggregates(req):
    microversion.raise_http_status_code_if_not_version(req, 404, (1, 1))
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)
    aggregate_uuids = util.extract_json(req.body, PUT_AGGREGATES_SCHEMA)
    resource_provider.set_aggregates(aggregate_uuids)

    return _send_aggregates(req.response, aggregate_uuids)
Beispiel #50
0
def get_inventory(req):
    """GET one inventory.

    On success return a 200 an application/json body representing one
    inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)
    inventory = objects.InventoryList.get_all_by_resource_provider_uuid(
        context, resource_provider.uuid).find(resource_class)

    if not inventory:
        raise webob.exc.HTTPNotFound('No inventory of class %s for %s' %
                                     (resource_class, resource_provider.uuid),
                                     json_formatter=util.json_error_formatter)

    return _send_inventory(req.response, resource_provider, inventory)
Beispiel #51
0
def get_inventory(req):
    """GET one inventory.

    On success return a 200 an application/json body representing one
    inventory.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_class = util.wsgi_path_item(req.environ, 'resource_class')

    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)
    inventory = objects.InventoryList.get_all_by_resource_provider_uuid(
        context, resource_provider.uuid).find(resource_class)

    if not inventory:
        raise webob.exc.HTTPNotFound(
            _('No inventory of class %(class)s for %(rp_uuid)s') %
            {'class': resource_class, 'rp_uuid': resource_provider.uuid})

    return _send_inventory(req.response, resource_provider, inventory)
Beispiel #52
0
def get_trait(req):
    context = req.environ['placement.context']
    name = util.wsgi_path_item(req.environ, 'name')

    try:
        objects.Trait.get_by_name(context, name)
    except exception.TraitNotFound as ex:
        raise webob.exc.HTTPNotFound(
            explanation=ex.format_message())

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #53
0
def delete_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    resource_provider = objects.ResourceProvider.get_by_uuid(context, uuid)
    try:
        resource_provider.set_traits(objects.TraitList(objects=[]))
    except exception.ConcurrentUpdateDetected as e:
        raise webob.exc.HTTPConflict(explanation=e.format_message())

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #54
0
def handle_405(environ, start_response):
    """Return a 405 response when method is not allowed.

    If _methods are in routing_args, send an allow header listing
    the methods that are possible on the provided URL.
    """
    _methods = util.wsgi_path_item(environ, '_methods')
    headers = {}
    if _methods:
        headers['allow'] = _methods
    raise webob.exc.HTTPMethodNotAllowed(
        _('The method specified is not allowed for this resource.'),
        headers=headers, json_formatter=util.json_error_formatter)
Beispiel #55
0
def get_inventories(req):
    """GET a list of inventories.

    On success return a 200 with an application/json body representing
    a collection of inventories.
    """
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)
    inventories = objects.InventoryList.get_all_by_resource_provider_uuid(
        context, resource_provider.uuid)

    return _send_inventories(req.response, resource_provider, inventories)
Beispiel #56
0
def delete_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    context.can(policies.RP_TRAIT_DELETE)
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid)
    try:
        resource_provider.set_traits(rp_obj.TraitList(objects=[]))
    except exception.ConcurrentUpdateDetected as e:
        raise webob.exc.HTTPConflict(e.format_message(),
                                     comment=errors.CONCURRENT_UPDATE)

    req.response.status = 204
    req.response.content_type = None
    return req.response
Beispiel #57
0
def list_traits_for_resource_provider(req):
    context = req.environ['placement.context']
    uuid = util.wsgi_path_item(req.environ, 'uuid')

    resource_provider = objects.ResourceProvider.get_by_uuid(
        context, uuid)

    response_body = _serialize_traits(resource_provider.get_traits())
    response_body[
        "resource_provider_generation"] = resource_provider.generation

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(response_body))
    req.response.content_type = 'application/json'
    return req.response