def create_resource_provider(req): """POST to create a resource provider. On success return a 201 response with an empty body (microversions 1.0 - 1.19) or a 200 response with a payload representing the newly created resource provider (microversions 1.20 - latest), and a location header pointing to the resource provider. """ context = req.environ['placement.context'] context.can(policies.CREATE) schema = rp_schema.POST_RESOURCE_PROVIDER_SCHEMA want_version = req.environ[microversion.MICROVERSION_ENVIRON] if want_version.matches((1, 14)): schema = rp_schema.POST_RP_SCHEMA_V1_14 data = util.extract_json(req.body, schema) if data.get('uuid'): # Normalize UUID with no proper dashes into dashed one # with format {8}-{4}-{4}-{4}-{12} data['uuid'] = str(uuidlib.UUID(data['uuid'])) else: data['uuid'] = uuidutils.generate_uuid() data["generation"] = 0 try: resource_provider = rp_obj.ResourceProvider(context, **data) resource_provider.create() except db.ClientError as e: if "ConstraintValidationFailed" in str(e): if "property `uuid`" in str(e): duplicate = "uuid: %s" % data.get("uuid") else: duplicate = "name: %s" % data.get("name") raise webob.exc.HTTPConflict("Conflicting resource provider " "%(duplicate)s already exists." % {'duplicate': duplicate}, comment=errors.DUPLICATE_NAME) else: raise webob.exc.HTTPBadRequest("Unable to create resource " "provider '%(rp_uuid)s': %(error)s" % {"rp_uuid": data.get("uuid"), "error": e}) except exception.ObjectActionError as exc: raise webob.exc.HTTPBadRequest( 'Unable to create resource provider "%(name)s", %(rp_uuid)s: ' '%(error)s' % {'name': data['name'], 'rp_uuid': data['uuid'], 'error': exc}) req.response.location = util.resource_provider_url( req.environ, resource_provider) if want_version.matches(min_version=(1, 20)): req.response.body = encodeutils.to_utf8(jsonutils.dumps( _serialize_provider(req.environ, resource_provider, want_version))) req.response.content_type = 'application/json' modified = util.pick_last_modified(None, resource_provider) req.response.last_modified = modified req.response.cache_control = 'no-cache' else: req.response.status = 201 req.response.content_type = None return req.response
def create_resource_tree(req): """This method accepts a nested dict that describes a tree-like relationship among resource providers. Each node on the tree should contain the following keys: name: the name given to the resource. If not supplied, no name is set. uuid: the resource's UUID. If not supplied, one will be generated. resources: a dict of resources that this node provides directly. Each member should be of the form `resource_class: amount` traits: a list of traits to apply to this node. children: a list of nodes representing the children of this node. Each child node should be the same format dict as described here. returns: the UUID of the root of the newly-created tree There is no limit to the level of nesting for child resource providers. """ context = req.environ["placement.context"] context.can(policies.UPDATE) schema = rp_schema.POST_RP_TREE want_version = req.environ[microversion.MICROVERSION_ENVIRON] data = util.extract_json(req.body, schema) root_rp = rp_obj.ResourceProvider.create_tree(context, data) response = req.response response.status = 200 req.response.location = util.resource_provider_url(req.environ, root_rp) req.response.body = encodeutils.to_utf8( jsonutils.dumps( _serialize_provider(req.environ, root_rp, want_version))) req.response.content_type = "application/json" req.response.cache_control = "no-cache"
def test_resource_provider_url_prefix(self): # SCRIPT_NAME represents the mount point of a WSGI # application when it is hosted at a path/prefix. environ = {'SCRIPT_NAME': '/placement'} expected_url = ('/placement/resource_providers/%s' % uuidsentinel.rp_uuid) self.assertEqual(expected_url, util.resource_provider_url( environ, self.resource_provider))
def create_resource_provider(req): """POST to create a resource provider. On success return a 201 response with an empty body (microversions 1.0 - 1.19) or a 200 response with a payload representing the newly created resource provider (microversions 1.20 - latest), and a location header pointing to the resource provider. """ context = req.environ['placement.context'] context.can(policies.CREATE) schema = rp_schema.POST_RESOURCE_PROVIDER_SCHEMA want_version = req.environ[microversion.MICROVERSION_ENVIRON] if want_version.matches((1, 14)): schema = rp_schema.POST_RP_SCHEMA_V1_14 data = util.extract_json(req.body, schema) try: if data.get('uuid'): # Normalize UUID with no proper dashes into dashed one # with format {8}-{4}-{4}-{4}-{12} data['uuid'] = str(uuidlib.UUID(data['uuid'])) else: data['uuid'] = uuidutils.generate_uuid() resource_provider = rp_obj.ResourceProvider(context, **data) resource_provider.create() except db_exc.DBDuplicateEntry as exc: # Whether exc.columns has one or two entries (in the event # of both fields being duplicates) appears to be database # dependent, so going with the complete solution here. duplicate = ', '.join( ['%s: %s' % (column, data[column]) for column in exc.columns]) raise webob.exc.HTTPConflict( 'Conflicting resource provider %(duplicate)s already exists.' % {'duplicate': duplicate}, comment=errors.DUPLICATE_NAME) except exception.ObjectActionError as exc: raise webob.exc.HTTPBadRequest( 'Unable to create resource provider "%(name)s", %(rp_uuid)s: ' '%(error)s' % {'name': data['name'], 'rp_uuid': data['uuid'], 'error': exc}) req.response.location = util.resource_provider_url( req.environ, resource_provider) if want_version.matches(min_version=(1, 20)): req.response.body = encodeutils.to_utf8(jsonutils.dumps( _serialize_provider(req.environ, resource_provider, want_version))) req.response.content_type = 'application/json' modified = util.pick_last_modified(None, resource_provider) req.response.last_modified = modified req.response.cache_control = 'no-cache' else: req.response.status = 201 req.response.content_type = None return req.response
def _serialize_links(environ, resource_provider): url = util.resource_provider_url(environ, resource_provider) links = [{'rel': 'self', 'href': url}] rel_types = ['inventories', 'usages'] want_version = environ[microversion.MICROVERSION_ENVIRON] if want_version >= (1, 1): rel_types.append('aggregates') if want_version >= (1, 6): rel_types.append('traits') if want_version >= (1, 11): rel_types.append('allocations') for rel in rel_types: links.append({'rel': rel, 'href': '%s/%s' % (url, rel)}) return links
def create_resource_provider(req): """POST to create a resource provider. On success return a 201 response with an empty body and a location header pointing to the newly created resource provider. """ context = req.environ['placement.context'] schema = rp_schema.POST_RESOURCE_PROVIDER_SCHEMA want_version = req.environ[microversion.MICROVERSION_ENVIRON] if want_version.matches((1, 14)): schema = rp_schema.POST_RP_SCHEMA_V1_14 data = util.extract_json(req.body, schema) try: uuid = data.setdefault('uuid', uuidutils.generate_uuid()) resource_provider = rp_obj.ResourceProvider(context, **data) resource_provider.create() except db_exc.DBDuplicateEntry as exc: # Whether exc.columns has one or two entries (in the event # of both fields being duplicates) appears to be database # dependent, so going with the complete solution here. duplicate = ', '.join(['%s: %s' % (column, data[column]) for column in exc.columns]) raise webob.exc.HTTPConflict( _('Conflicting resource provider %(duplicate)s already exists.') % {'duplicate': duplicate}) except exception.ObjectActionError as exc: raise webob.exc.HTTPBadRequest( _('Unable to create resource provider "%(name)s", %(rp_uuid)s: ' '%(error)s') % {'name': data['name'], 'rp_uuid': uuid, 'error': exc}) req.response.location = util.resource_provider_url( req.environ, resource_provider) if want_version.matches(min_version=(1, 20)): req.response.body = encodeutils.to_utf8(jsonutils.dumps( _serialize_provider(req.environ, resource_provider, want_version))) req.response.content_type = 'application/json' modified = util.pick_last_modified(None, resource_provider) req.response.last_modified = modified req.response.cache_control = 'no-cache' else: req.response.status = 201 req.response.content_type = None return req.response
def test_resource_provider_url(self): environ = {} expected_url = '/resource_providers/%s' % uuidsentinel.rp_uuid self.assertEqual( expected_url, util.resource_provider_url(environ, self.resource_provider))
def create_resource_provider(req): """POST to create a resource provider. On success return a 201 response with an empty body (microversions 1.0 - 1.19) or a 200 response with a payload representing the newly created resource provider (microversions 1.20 - latest), and a location header pointing to the resource provider. """ context = req.environ['placement.context'] context.can(policies.CREATE) schema = rp_schema.POST_RESOURCE_PROVIDER_SCHEMA want_version = req.environ[microversion.MICROVERSION_ENVIRON] if want_version.matches((1, 14)): schema = rp_schema.POST_RP_SCHEMA_V1_14 data = util.extract_json(req.body, schema) try: if data.get('uuid'): # Normalize UUID with no proper dashes into dashed one # with format {8}-{4}-{4}-{4}-{12} data['uuid'] = str(uuidlib.UUID(data['uuid'])) else: data['uuid'] = uuidutils.generate_uuid() resource_provider = rp_obj.ResourceProvider(context, **data) resource_provider.create() except db_exc.DBDuplicateEntry as exc: # Whether exc.columns has one or two entries (in the event # of both fields being duplicates) appears to be database # dependent, so going with the complete solution here. duplicates = [] for column in exc.columns: # For MySQL, this is error 1062: # # Duplicate entry '%s' for key %d # # The 'key' value is captured in 'DBDuplicateEntry.columns'. # Despite the name, this isn't always a column name. While MySQL # 5.x does indeed use the name of the column, 8.x uses the name of # the constraint. oslo.db should probably fix this, but until that # happens we need to handle both cases if column == 'uniq_resource_providers0uuid': duplicates.append(f'uuid: {data["uuid"]}') elif column == 'uniq_resource_providers0name': duplicates.append(f'name: {data["name"]}') else: duplicates.append(f'{column}: {data[column]}') raise webob.exc.HTTPConflict( 'Conflicting resource provider %(duplicate)s already exists.' % {'duplicate': ', '.join(duplicates)}, comment=errors.DUPLICATE_NAME) except exception.ObjectActionError as exc: raise webob.exc.HTTPBadRequest( 'Unable to create resource provider "%(name)s", %(rp_uuid)s: ' '%(error)s' % { 'name': data['name'], 'rp_uuid': data['uuid'], 'error': exc }) req.response.location = util.resource_provider_url(req.environ, resource_provider) if want_version.matches(min_version=(1, 20)): req.response.body = encodeutils.to_utf8( jsonutils.dumps( _serialize_provider(req.environ, resource_provider, want_version))) req.response.content_type = 'application/json' modified = util.pick_last_modified(None, resource_provider) req.response.last_modified = modified req.response.cache_control = 'no-cache' else: req.response.status = 201 req.response.content_type = None return req.response