Ejemplo n.º 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)
    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},
             json_formatter=util.json_error_formatter)

    response = req.response
    response.status = 204
    response.content_type = None
    return response
Ejemplo n.º 2
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)
Ejemplo n.º 3
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
            },
            json_formatter=util.json_error_formatter)

    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
Ejemplo n.º 4
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.ResourceClassObject.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
Ejemplo n.º 5
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
Ejemplo n.º 6
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
Ejemplo n.º 7
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.ResourceClassObject.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
Ejemplo n.º 8
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})
    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
Ejemplo n.º 9
0
def set_allocations(req):
    context = req.environ['placement.context']
    consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid')
    data = _extract_allocations(req.body, ALLOCATION_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)

    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:
        LOG.exception(_LE("Bad inventory"))
        raise webob.exc.HTTPConflict(
            _('Unable to allocate inventory: %(error)s') % {'error': exc})
    except exception.ConcurrentUpdateDetected as exc:
        LOG.exception(_LE("Concurrent Update"))
        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
Ejemplo n.º 10
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)
Ejemplo n.º 11
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},
            json_formatter=util.json_error_formatter)

    return _send_inventory(req.response, resource_provider, inventory)
Ejemplo n.º 12
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']
    # The containing application will catch a not found here.
    rc = objects.ResourceClassObject.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'
    return req.response
Ejemplo n.º 13
0
def get_aggregates(req):
    """GET a list of aggregates associated with a resource provider.

    If the resource provider does not exist return a 404.

    On success return a 200 with an application/json body containing a
    list of aggregate uuids.
    """
    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 = resource_provider.get_aggregates()

    return _send_aggregates(req.response, aggregate_uuids)
Ejemplo n.º 14
0
def get_resource_provider(req):
    """Get a single resource provider.

    On success return a 200 with an application/json body representing
    the resource provider.
    """
    uuid = util.wsgi_path_item(req.environ, 'uuid')
    # The containing application will catch a not found here.
    context = req.environ['placement.context']

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

    req.response.body = encodeutils.to_utf8(jsonutils.dumps(
        _serialize_provider(req.environ, resource_provider)))
    req.response.content_type = 'application/json'
    return req.response
Ejemplo n.º 15
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:
        # Ensure allow header is a python 2 or 3 native string (thus
        # not unicode in python 2 but stay a string in python 3)
        # In the process done by Routes to save the allowed methods
        # to its routing table they become unicode in py2.
        headers['allow'] = str(_methods)
    raise webob.exc.HTTPMethodNotAllowed(
        _('The method specified is not allowed for this resource.'),
        headers=headers,
        json_formatter=util.json_error_formatter)
Ejemplo n.º 16
0
def list_for_consumer(req):
    """List allocations associated with a consumer."""
    context = req.environ['placement.context']
    consumer_id = util.wsgi_path_item(req.environ, 'consumer_uuid')

    # 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 = objects.AllocationList.get_all_by_consumer_id(
        context, consumer_id)

    allocations_json = jsonutils.dumps(
        _serialize_allocations_for_consumer(allocations))

    req.response.status = 200
    req.response.body = encodeutils.to_utf8(allocations_json)
    req.response.content_type = 'application/json'
    return req.response
Ejemplo n.º 17
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')
    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},
             json_formatter=util.json_error_formatter)

    inventories = objects.InventoryList.get_all_by_resource_provider_uuid(
        context, resource_provider.uuid)

    return _send_inventories(req.response, resource_provider, inventories)
Ejemplo n.º 18
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']
    # The containing application will catch a not found here.
    try:
        resource_provider = objects.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})
    except exception.NotFound as exc:
        raise webob.exc.HTTPNotFound(
            _("No resource provider with uuid %s found for delete") % uuid)
    req.response.status = 204
    req.response.content_type = None
    return req.response
Ejemplo n.º 19
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)
    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},
            json_formatter=util.json_error_formatter)
    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},
            json_formatter=util.json_error_formatter)

    response = req.response
    response.location = util.inventory_url(
        req.environ, resource_provider, resource_class)
    return _send_inventory(response, resource_provider, inventory,
                           status=201)
Ejemplo n.º 20
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'),
            json_formatter=util.json_error_formatter)

    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},
            json_formatter=util.json_error_formatter)
    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},
            json_formatter=util.json_error_formatter)
    except (exception.ConcurrentUpdateDetected,
            exception.InventoryInUse,
            db_exc.DBDuplicateEntry) as exc:
        raise webob.exc.HTTPConflict(
            _('update conflict: %(error)s') % {'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_inventories(req.response, resource_provider, inventories)