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') 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'] 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 }) 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 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'] context.can(policies.DELETE) uuid = util.wsgi_path_item(req.environ, 'uuid') resource_provider = rp_obj.ResourceProvider.get_by_uuid( context, uuid) try: resource_provider.set_inventory([]) 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}, comment=errors.CONCURRENT_UPDATE) except exception.InventoryInUse as ex: raise webob.exc.HTTPConflict(ex.format_message(), comment=errors.INVENTORY_INUSE) response = req.response response.status = 204 response.content_type = None 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, schema.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 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 delete_allocations(req): context = req.environ['placement.context'] context.can(policies.ALLOC_DELETE) consumer_uuid = util.wsgi_path_item(req.environ, 'consumer_uuid') allocations = rp_obj.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.HTTPNotFound( _("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 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 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 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 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 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'] context.can(policies.UPDATE) data = util.extract_json(req.body, schema.PUT_RC_SCHEMA_V1_2) # The containing application will catch a not found here. rc = rc_obj.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}) except exception.ResourceClassCannotUpdateStandard: raise webob.exc.HTTPBadRequest( 'Cannot update standard resource class %(rp_name)s' % {'rp_name': name}) 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 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 = rc_obj.ResourceClass.get_by_name(context, name) except exception.NotFound: try: rc = rc_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 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, schema.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 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 = rc_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'] want_version = req.environ[microversion.MICROVERSION_ENVIRON] uuid = util.wsgi_path_item(req.environ, 'uuid') data = util.extract_json(req.body, schema.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, last_modified = _serialize_traits(trait_objs, want_version) response_body[ 'resource_provider_generation'] = resource_provider.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'] 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_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 _set_allocations_for_consumer(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'] # 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 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'] context.can(policies.UPDATE) want_version = req.environ[microversion.MICROVERSION_ENVIRON] # The containing application will catch a not found here. resource_provider = rp_obj.ResourceProvider.get_by_uuid( context, uuid) schema = rp_schema.PUT_RESOURCE_PROVIDER_SCHEMA if want_version.matches((1, 14)): schema = rp_schema.PUT_RP_SCHEMA_V1_14 data = util.extract_json(req.body, schema) for field in rp_obj.ResourceProvider.SETTABLE_FIELDS: if field in data: setattr(resource_provider, field, data[field]) try: resource_provider.save() except db.ClientError as e: if "ConstraintValidationFailed" in e.message: raise webob.exc.HTTPConflict( 'Conflicting resource provider %(name)s already exists.' % {'name': data['name']}, comment=errors.DUPLICATE_NAME) except db_exc.DBDuplicateEntry: raise webob.exc.HTTPConflict( 'Conflicting resource provider %(name)s already exists.' % {'name': data['name']}, comment=errors.DUPLICATE_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}) response = req.response response.status = 200 response.body = encodeutils.to_utf8(jsonutils.dumps( _serialize_provider(req.environ, resource_provider, want_version))) response.content_type = 'application/json' if want_version.matches((1, 15)): response.last_modified = resource_provider.updated_at response.cache_control = 'no-cache' return response
def delete_traits_for_resource_provider(req): context = req.environ['placement.context'] 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(explanation=e.format_message()) req.response.status = 204 req.response.content_type = None return req.response
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. """ 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 = resource_provider.get_aggregates() return _send_aggregates(req, resource_provider, aggregate_uuids)
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 get_trait(req): context = req.environ['placement.context'] want_version = req.environ[microversion.MICROVERSION_ENVIRON] name = util.wsgi_path_item(req.environ, 'name') try: trait = rp_obj.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 if want_version.matches((1, 15)): req.response.last_modified = trait.created_at req.response.cache_control = 'no-cache' return req.response
def delete_trait(req): context = req.environ['placement.context'] name = util.wsgi_path_item(req.environ, 'name') try: trait = rp_obj.Trait.get_by_name(context, name) trait.destroy() except exception.TraitNotFound as ex: raise webob.exc.HTTPNotFound(explanation=ex.format_message()) except exception.TraitCannotDeleteStandard as ex: raise webob.exc.HTTPBadRequest(explanation=ex.format_message()) except exception.TraitInUse as ex: raise webob.exc.HTTPConflict(explanation=ex.format_message()) req.response.status = 204 req.response.content_type = None return req.response
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'] context.can(policies.LIST) uuid = util.wsgi_path_item(req.environ, 'uuid') 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 = inv_obj.get_all_by_resource_provider(context, rp) return _send_inventories(req, rp, inv_list)
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) # Use Exception class as WSGI Application. We don't want to raise here. response = webob.exc.HTTPMethodNotAllowed( _('The method specified is not allowed for this resource.'), headers=headers, json_formatter=util.json_error_formatter) return response(environ, start_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'] context.can(policies.PROVIDER_USAGES) uuid = util.wsgi_path_item(req.environ, 'uuid') want_version = req.environ[microversion.MICROVERSION_ENVIRON] # 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 = 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 }) usage = usage_obj.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' if want_version.matches((1, 15)): req.response.cache_control = 'no-cache' # While it would be possible to generate a last-modified time # based on the collection of allocations that result in a usage # value (with some spelunking in the SQL) that doesn't align with # the question that is being asked in a request for usages: What # is the usage, now? So the last-modified time is set to utcnow. req.response.last_modified = timeutils.utcnow(with_timezone=True) 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 = rp_obj.ResourceClass.get_by_name(context, name) try: rc.destroy() except exception.ResourceClassCannotDeleteStandard as exc: raise webob.exc.HTTPBadRequest( _('Error in delete resource class: %(error)s') % {'error': exc}) except exception.ResourceClassInUse as exc: raise webob.exc.HTTPConflict( _('Error in delete resource class: %(error)s') % {'error': exc}) req.response.status = 204 req.response.content_type = None return req.response
def associate(req): """Associate a resource provider with one or more other resource providers. This is commonly used to create a sharing relationship among resource providers. 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.UPDATE) schema = rp_schema.POST_RPS_ASSOCIATE want_version = req.environ[microversion.MICROVERSION_ENVIRON] data = util.extract_json(req.body, schema) target_uuids = data.get("targets", []) # The containing application will catch a not found here. resource_provider = rp_obj.ResourceProvider.get_by_uuid(context, uuid) rp_obj.associate(context, resource_provider, target_uuids) response = req.response response.status = 204