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
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)
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
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)
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)
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)
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)
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
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
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
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
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
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
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
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
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
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)
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
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
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)
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
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)
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
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
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
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)
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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)
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
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)
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)
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)
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
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)
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)
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)
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
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
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)
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)
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
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