def cache_tee_iter(self, image_id, image_iter, image_checksum): try: current_checksum = hashlib.md5() with self.driver.open_for_write(image_id) as cache_file: for chunk in image_iter: try: cache_file.write(chunk) finally: current_checksum.update(chunk) yield chunk cache_file.flush() if (image_checksum and image_checksum != current_checksum.hexdigest()): msg = _("Checksum verification failed. Aborted " "caching of image '%s'.") % image_id raise exception.GlanceException(msg) except exception.GlanceException as e: with excutils.save_and_reraise_exception(): # image_iter has given us bad, (size_checked_iter has found a # bad length), or corrupt data (checksum is wrong). LOG.exception(utils.exception_to_str(e)) except Exception as e: LOG.exception(_LE("Exception encountered while tee'ing " "image '%(image_id)s' into cache: %(error)s. " "Continuing with response.") % {'image_id': image_id, 'error': utils.exception_to_str(e)}) # If no checksum provided continue responding even if # caching failed. for chunk in image_iter: yield chunk
def create(self, req, image, extra_properties, tags): image_factory = self.gateway.get_image_factory(req.context) image_repo = self.gateway.get_repo(req.context) try: image = image_factory.new_image(extra_properties=extra_properties, tags=tags, **image) image_repo.add(image) except exception.DuplicateLocation as dup: raise webob.exc.HTTPBadRequest(explanation=dup.msg) except exception.Invalid as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.InvalidParameterValue as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.LimitExceeded as e: LOG.warn(utils.exception_to_str(e)) raise webob.exc.HTTPRequestEntityTooLarge( explanation=e.msg, request=req, content_type='text/plain') except exception.Duplicate as dupex: raise webob.exc.HTTPConflict(explanation=dupex.msg) except exception.ReservedProperty as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.ReadonlyProperty as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except TypeError as e: LOG.debug(utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest( explanation=utils.exception_to_str(e)) return image
def index(self, req, marker=None, limit=None, sort_key='created_at', sort_dir='desc', filters=None): result = {} if filters is None: filters = {} filters['deleted'] = False if limit is None: limit = CONF.limit_param_default limit = min(CONF.api_limit_max, limit) task_repo = self.gateway.get_task_stub_repo(req.context) try: tasks = task_repo.list(marker, limit, sort_key, sort_dir, filters) if len(tasks) != 0 and len(tasks) == limit: result['next_marker'] = tasks[-1].task_id except (exception.NotFound, exception.InvalidSortKey, exception.InvalidFilterRangeValue) as e: LOG.warn(utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.Forbidden as e: LOG.warn(utils.exception_to_str(e)) raise webob.exc.HTTPForbidden(explanation=e.msg) result['tasks'] = tasks return result
def update(self, req, image_id, changes): image_repo = self.gateway.get_repo(req.context) try: image = image_repo.get(image_id) for change in changes: change_method_name = '_do_%s' % change['op'] assert hasattr(self, change_method_name) change_method = getattr(self, change_method_name) change_method(req, image, change) if changes: image_repo.save(image) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Invalid as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.InvalidParameterValue as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.StorageQuotaFull as e: msg = (_("Denying attempt to upload image because it exceeds the" " quota: %s") % utils.exception_to_str(e)) LOG.warn(msg) raise webob.exc.HTTPRequestEntityTooLarge( explanation=msg, request=req, content_type='text/plain') except exception.LimitExceeded as e: LOG.exception(utils.exception_to_str(e)) raise webob.exc.HTTPRequestEntityTooLarge( explanation=e.msg, request=req, content_type='text/plain') return image
def set_data(self, data, size=None): self.send_notification('image.prepare', self.repo) notify_error = self.notifier.error try: self.repo.set_data(data, size) except glance_store.StorageFull as e: msg = (_("Image storage media is full: %s") % utils.exception_to_str(e)) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg) except glance_store.StorageWriteDenied as e: msg = (_("Insufficient permissions on image storage media: %s") % utils.exception_to_str(e)) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPServiceUnavailable(explanation=msg) except ValueError as e: msg = (_("Cannot save data for image %(image_id)s: %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPBadRequest( explanation=utils.exception_to_str(e)) except exception.Duplicate as e: msg = (_("Unable to upload duplicate image data for image" "%(image_id)s: %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPConflict(explanation=msg) except exception.Forbidden as e: msg = (_("Not allowed to upload image data for image %(image_id)s:" " %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPForbidden(explanation=msg) except exception.NotFound as e: msg = (_("Image %(image_id)s could not be found after upload." " The image may have been deleted during the upload:" " %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPNotFound(explanation=utils.exception_to_str(e)) except webob.exc.HTTPError as e: with excutils.save_and_reraise_exception(): msg = (_("Failed to upload image data for image %(image_id)s" " due to HTTP error: %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) except Exception as e: with excutils.save_and_reraise_exception(): msg = (_("Failed to upload image data for image %(image_id)s " "due to internal error: %(error)s") % {'image_id': self.repo.image_id, 'error': utils.exception_to_str(e)}) _send_notification(notify_error, 'image.upload', msg) else: self.send_notification('image.upload', self.repo) self.send_notification('image.activate', self.repo)
def update_all(self, req, image_id, body): """ Replaces the members of the image with those specified in the body. The body is a dict with the following format:: {"memberships": [ {"member_id": <MEMBER_ID>, ["can_share": [True|False]]}, ... ]} """ self._check_can_access_image_members(req.context) self._enforce(req, 'modify_member') self._raise_404_if_image_deleted(req, image_id) memberships = body.get('memberships') if memberships: new_number_of_members = len(body['memberships']) self._enforce_image_member_quota(req, new_number_of_members) try: registry.replace_members(req.context, image_id, body) self._update_store_acls(req, image_id) except exception.Invalid as e: LOG.debug(utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.NotFound as e: LOG.debug(utils.exception_to_str(e)) raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Forbidden as e: LOG.debug(utils.exception_to_str(e)) raise webob.exc.HTTPNotFound(explanation=e.msg) return webob.exc.HTTPNoContent()
def _get_metadata(self): if CONF.filesystem_store_metadata_file is None: return {} try: with open(CONF.filesystem_store_metadata_file, 'r') as fptr: metadata = jsonutils.load(fptr) glance.store.check_location_metadata(metadata) return metadata except glance.store.BackendException as bee: LOG.error(_('The JSON in the metadata file %(file)s could not be ' 'used: %(error)s An empty dictionary will be ' 'returned to the client.') % {'file': CONF.filesystem_store_metadata_file, 'error': utils.exception_to_str(bee)}) return {} except IOError as ioe: LOG.error(_('The path for the metadata file %(file)s could not be ' 'opened: %(error)s An empty dictionary will be ' 'returned to the client.') % {'file': CONF.filesystem_store_metadata_file, 'error': utils.exception_to_str(ioe)}) return {} except Exception as ex: LOG.exception(_('An error occurred processing the storage systems ' 'meta data file: %s. An empty dictionary will be ' 'returned to the client.') % utils.exception_to_str(ex)) return {}
def configure(self): """ Configure the Store to use the stored configuration options Any store that needs special configuration should implement this method. If the store was not able to successfully configure itself, it should raise `exception.BadStoreConfiguration` """ try: self.chunk_size = CONF.sheepdog_store_chunk_size * units.Mi self.addr = CONF.sheepdog_store_address.strip() self.port = CONF.sheepdog_store_port except cfg.ConfigFileValueError as e: reason = (_("Error in store configuration: %s") % utils.exception_to_str(e)) LOG.error(reason) raise exception.BadStoreConfiguration(store_name='sheepdog', reason=reason) if ' ' in self.addr: reason = (_("Invalid address configuration of sheepdog store: %s") % self.addr) LOG.error(reason) raise exception.BadStoreConfiguration(store_name='sheepdog', reason=reason) try: cmd = ["collie", "vdi", "list", "-a", self.addr, "-p", self.port] processutils.execute(*cmd) except Exception as e: reason = (_("Error in store configuration: %s") % utils.exception_to_str(e)) LOG.error(reason) raise exception.BadStoreConfiguration(store_name='sheepdog', reason=reason)
def main(): """The main function.""" try: config.parse_args() except RuntimeError as e: sys.exit("ERROR: %s" % utils.exception_to_str(e)) # Setup logging logging.setup('glance') if CONF.token: CONF.slavetoken = CONF.token CONF.mastertoken = CONF.token command = lookup_command(CONF.command) try: command(CONF, CONF.args) except TypeError as e: LOG.error(_LE(command.__doc__) % {'prog': command.__name__}) # noqa sys.exit("ERROR: %s" % utils.exception_to_str(e)) except ValueError as e: LOG.error(_LE(command.__doc__) % {'prog': command.__name__}) # noqa sys.exit("ERROR: %s" % utils.exception_to_str(e))
def rollback(e): set_attr('error', utils.exception_to_str(e)) invalid_path = self.get_image_filepath(image_id, 'invalid') LOG.debug("Fetch of cache file failed (%(e)s), rolling back by " "moving '%(incomplete_path)s' to " "'%(invalid_path)s'" % {'e': utils.exception_to_str(e), 'incomplete_path': incomplete_path, 'invalid_path': invalid_path}) os.rename(incomplete_path, invalid_path)
def test_exception_to_str(self): class FakeException(Exception): def __str__(self): raise UnicodeError() ret = utils.exception_to_str(Exception('error message')) self.assertEqual('error message', ret) ret = utils.exception_to_str(Exception('\xa5 error message')) self.assertEqual(' error message', ret) ret = utils.exception_to_str(FakeException('\xa5 error message')) self.assertEqual("Caught '%(exception)s' exception." % {'exception': 'FakeException'}, ret)
def get(self, req, task_id): try: task_repo = self.gateway.get_task_repo(req.context) task = task_repo.get(task_id) except exception.NotFound as e: msg = (_("Failed to find task %(task_id)s. Reason: %(reason)s") % {'task_id': task_id, 'reason': utils.exception_to_str(e)}) LOG.info(msg) raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Forbidden as e: msg = (_("Forbidden to get task %(task_id)s. Reason: %(reason)s") % {'task_id': task_id, 'reason': utils.exception_to_str(e)}) LOG.info(msg) raise webob.exc.HTTPForbidden(explanation=e.msg) return task
def _execute(t_id, task_repo, image_repo, image_factory): task = script_utils.get_task(task_repo, t_id) if task is None: # NOTE: This happens if task is not found in the database. In # such cases, there is no way to update the task status so, # it's ignored here. return try: task_input = script_utils.unpack_task_input(task) uri = script_utils.validate_location_uri(task_input.get('import_from')) image_id = import_image(image_repo, image_factory, task_input, t_id, uri) task.succeed({'image_id': image_id}) except Exception as e: # Note: The message string contains Error in it to indicate # in the task.message that it's a error message for the user. # TODO(nikhil): need to bring back save_and_reraise_exception when # necessary err_msg = ("Error: " + six.text_type(type(e)) + ': ' + common_utils.exception_to_str(e)) log_msg = _LE(err_msg + ("Task ID %s" % task.task_id)) # noqa LOG.exception(log_msg) task.fail(_LE(err_msg)) # noqa finally: task_repo.save(task)
def migrate_location_credentials(migrate_engine, to_quoted): """ Migrate location credentials for swift uri's between the quoted and unquoted forms. :param migrate_engine: The configured db engine :param to_quoted: If True, migrate location credentials from unquoted to quoted form. If False, do the reverse. """ meta = sqlalchemy.schema.MetaData() meta.bind = migrate_engine images_table = sqlalchemy.Table('images', meta, autoload=True) images = list(images_table.select(images_table.c.location.startswith( 'swift')).execute()) for image in images: try: fixed_uri = legacy_parse_uri(image['location'], to_quoted) images_table.update().where( images_table.c.id == image['id']).values( location=fixed_uri).execute() except exception.BadStoreUri as e: reason = utils.exception_to_str(e) msg = _LE("Invalid store uri for image: %(image_id)s. " "Details: %(reason)s") % {'image_id': image.id, 'reason': reason} LOG.exception(msg) raise
def main(): CONF.register_cli_opt(command_opt) try: cfg_files = cfg.find_config_files( project='glance', prog='glance-registry') cfg_files.extend( cfg.find_config_files(project='glance', prog='glance-api')) config.parse_args( default_config_files=cfg_files, usage="%(prog)s [options] <cmd>") log.setup('glance') except RuntimeError as e: sys.exit("ERROR: %s" % e) try: if CONF.command.action.startswith('db'): return CONF.command.action_fn() else: func_kwargs = {} for k in CONF.command.action_kwargs: v = getattr(CONF.command, 'action_kwarg_' + k) if v is None: continue func_kwargs[k] = strutils.safe_decode(v) func_args = [ strutils.safe_decode(arg) for arg in CONF.command.action_args ] return CONF.command.action_fn(*func_args, **func_kwargs) except exception.GlanceException as e: sys.exit("ERROR: %s" % utils.exception_to_str(e))
def _activate(self, req, image_id, location, location_metadata=None, from_state=None): """ Sets the image status to `active` and the image's location attribute. :param req: The WSGI/Webob Request object :param image_id: Opaque image identifier :param location: Location of where Glance stored this image :param location_metadata: a dictionary of storage specific information """ image_meta = {} image_meta["location"] = location image_meta["status"] = "active" if location_metadata: image_meta["location_data"] = [{"url": location, "metadata": location_metadata}] try: s = from_state image_meta_data = registry.update_image_metadata(req.context, image_id, image_meta, from_state=s) self.notifier.info("image.activate", redact_loc(image_meta_data)) self.notifier.info("image.update", redact_loc(image_meta_data)) return image_meta_data except exception.Duplicate: with excutils.save_and_reraise_exception(): # Delete image data since it has been supersceded by another # upload and re-raise. LOG.debug( "duplicate operation - deleting image data for " " %(id)s (location:%(location)s)" % {"id": image_id, "location": image_meta["location"]} ) upload_utils.initiate_deletion(req, image_meta["location"], image_id, CONF.delayed_delete) except exception.Invalid as e: msg = "Failed to activate image. Got error: %s" % utils.exception_to_str(e) LOG.debug(msg) raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain")
def show(self, req, namespace, property_name, filters=None): try: if filters and filters['resource_type']: rs_repo = self.gateway.get_metadef_resource_type_repo( req.context) db_resource_type = rs_repo.get(filters['resource_type'], namespace) prefix = db_resource_type.prefix if prefix and property_name.startswith(prefix): property_name = property_name[len(prefix):] else: msg = (_("Property %(property_name)s does not start " "with the expected resource type association " "prefix of '%(prefix)s'.") % {'property_name': property_name, 'prefix': prefix}) raise exception.NotFound(msg) prop_repo = self.gateway.get_metadef_property_repo(req.context) db_property = prop_repo.get(namespace, property_name) property = self._to_model(db_property) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return property
def update(self, req, image_id, member_id, status): """ Adds a membership to the image. :param req: the Request object coming from the wsgi layer :param image_id: the image identifier :param member_id: the member identifier :retval The response body is a mapping of the following form:: {'member_id': <MEMBER>, 'image_id': <IMAGE>, 'status': <MEMBER_STATUS> 'created_at': .., 'updated_at': ..} """ image_repo = self.gateway.get_repo(req.context) try: image = image_repo.get(image_id) member_repo = image.get_member_repo() member = member_repo.get(member_id) member.status = status member_repo.save(member) return member except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except ValueError as e: raise webob.exc.HTTPBadRequest(explanation= utils.exception_to_str(e))
def update(self, req, user_ns, namespace): namespace_repo = self.gateway.get_metadef_namespace_repo(req.context) try: ns_obj = namespace_repo.get(namespace) ns_obj.namespace = wsme_utils._get_value(user_ns.namespace) ns_obj.display_name = wsme_utils._get_value(user_ns.display_name) ns_obj.description = wsme_utils._get_value(user_ns.description) # Following optional fields will default to same values as in # create namespace if not specified ns_obj.visibility = ( wsme_utils._get_value(user_ns.visibility) or 'private') ns_obj.protected = ( wsme_utils._get_value(user_ns.protected) or False) ns_obj.owner = ( wsme_utils._get_value(user_ns.owner) or req.context.owner) updated_namespace = namespace_repo.save(ns_obj) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Duplicate as e: raise webob.exc.HTTPConflict(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return Namespace.to_wsme_model(updated_namespace, get_namespace_href(updated_namespace), self.ns_schema_link)
def index(self, req, namespace, marker=None, limit=None, sort_key='created_at', sort_dir='desc', filters=None): try: filters = filters or dict() filters['namespace'] = namespace tag_repo = self.gateway.get_metadef_tag_repo(req.context) if marker: metadef_tag = tag_repo.get(namespace, marker) marker = metadef_tag.tag_id db_metatag_list = tag_repo.list( marker=marker, limit=limit, sort_key=sort_key, sort_dir=sort_dir, filters=filters) tag_list = [MetadefTag(**{'name': db_metatag.name}) for db_metatag in db_metatag_list] metadef_tags = MetadefTags() metadef_tags.tags = tag_list except exception.Forbidden as e: LOG.debug("User not permitted to retrieve metadata tags " "within '%s' namespace" % namespace) raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return metadef_tags
def create_tags(self, req, metadata_tags, namespace): tag_factory = self.gateway.get_metadef_tag_factory(req.context) tag_repo = self.gateway.get_metadef_tag_repo(req.context) try: tag_list = [] for metadata_tag in metadata_tags.tags: tag_list.append(tag_factory.new_tag( namespace=namespace, **metadata_tag.to_dict())) tag_repo.add_tags(tag_list) tag_list_out = [MetadefTag(**{'name': db_metatag.name}) for db_metatag in tag_list] metadef_tags = MetadefTags() metadef_tags.tags = tag_list_out except exception.Forbidden as e: LOG.debug("User not permitted to create metadata tags within " "'%s' namespace" % namespace) raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Duplicate as e: raise webob.exc.HTTPConflict(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return metadef_tags
def test_remove_image_not_found(self): fake_uuid = str(uuid.uuid4()) image = self.image_repo.get(UUID1) image.image_id = fake_uuid exc = self.assertRaises( exception.ImageNotFound, self.image_repo.remove, image) self.assertIn(fake_uuid, utils.exception_to_str(exc))
def store_add_to_backend(image_id, data, size, store): """ A wrapper around a call to each stores add() method. This gives glance a common place to check the output :param image_id: The image add to which data is added :param data: The data to be stored :param size: The length of the data in bytes :param store: The store to which the data is being added :return: The url location of the file, the size amount of data, the checksum of the data the storage systems metadata dictionary for the location """ (location, size, checksum, metadata) = store.add(image_id, data, size) if metadata is not None: if not isinstance(metadata, dict): msg = (_("The storage driver %(store)s returned invalid metadata " "%(metadata)s. This must be a dictionary type") % {'store': six.text_type(store), 'metadata': six.text_type(metadata)}) LOG.error(msg) raise BackendException(msg) try: check_location_metadata(metadata) except BackendException as e: e_msg = (_("A bad metadata structure was returned from the " "%(store)s storage driver: %(metadata)s. %(error)s.") % {'store': six.text_type(store), 'metadata': six.text_type(metadata), 'error': utils.exception_to_str(e)}) LOG.error(e_msg) raise BackendException(e_msg) return (location, size, checksum, metadata)
def show(self, req, namespace, filters=None): try: # Get namespace ns_repo = self.gateway.get_metadef_namespace_repo(req.context) namespace_obj = ns_repo.get(namespace) namespace_detail = Namespace.to_wsme_model( namespace_obj, get_namespace_href(namespace_obj), self.ns_schema_link) ns_filters = dict() ns_filters['namespace'] = namespace # Get objects object_repo = self.gateway.get_metadef_object_repo(req.context) db_metaobject_list = object_repo.list(filters=ns_filters) object_list = [MetadefObject.to_wsme_model( db_metaobject, get_object_href(namespace, db_metaobject), self.obj_schema_link) for db_metaobject in db_metaobject_list] if object_list: namespace_detail.objects = object_list # Get resource type associations rs_repo = self.gateway.get_metadef_resource_type_repo(req.context) db_resource_type_list = rs_repo.list(filters=ns_filters) resource_type_list = [ResourceTypeAssociation.to_wsme_model( resource_type) for resource_type in db_resource_type_list] if resource_type_list: namespace_detail.resource_type_associations = ( resource_type_list) # Get properties prop_repo = self.gateway.get_metadef_property_repo(req.context) db_properties = prop_repo.list(filters=ns_filters) property_list = Namespace.to_model_properties(db_properties) if property_list: namespace_detail.properties = property_list if filters and filters['resource_type']: namespace_detail = self._prefix_property_name( namespace_detail, filters['resource_type']) # Get tags tag_repo = self.gateway.get_metadef_tag_repo(req.context) db_metatag_list = tag_repo.list(filters=ns_filters) tag_list = [MetadefTag(**{'name': db_metatag.name}) for db_metatag in db_metatag_list] if tag_list: namespace_detail.tags = tag_list except exception.Forbidden as e: LOG.debug("User not permitted to show metadata namespace " "'%s'", namespace) raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return namespace_detail
def safe_delete_from_backend(context, image_id, location): """ Given a location, delete an image from the store and update location status to db. This function try to handle all known exceptions which might be raised by those calls on store and DB modules in its implementation. :param context: The request context :param image_id: The image identifier :param location: The image location entry """ try: ret = store_api.delete_from_backend(location['url'], context=context) location['status'] = 'deleted' if 'id' in location: db_api.get_api().image_location_delete(context, image_id, location['id'], 'deleted') return ret except store_api.NotFound: msg = _LW('Failed to delete image %s in store from URI') % image_id LOG.warn(msg) except store_api.StoreDeleteNotSupported as e: LOG.warn(utils.exception_to_str(e)) except store_api.UnsupportedBackend: exc_type = sys.exc_info()[0].__name__ msg = (_LE('Failed to delete image %(image_id)s from store: %(exc)s') % dict(image_id=image_id, exc=exc_type)) LOG.error(msg)
def execute(self, image_id): """Finishing the task flow :param image_id: Glance Image ID """ task = script_utils.get_task(self.task_repo, self.task_id) if task is None: return try: task.succeed({'image_id': image_id}) except Exception as e: # Note: The message string contains Error in it to indicate # in the task.message that it's a error message for the user. # TODO(nikhil): need to bring back save_and_reraise_exception when # necessary err_msg = ("Error: " + six.text_type(type(e)) + ': ' + common_utils.exception_to_str(e)) log_msg = err_msg + _LE("Task ID %s") % task.task_id LOG.exception(log_msg) task.fail(err_msg) finally: self.task_repo.save(task) LOG.info(_LI("%(task_id)s of %(task_type)s completed") % {'task_id': self.task_id, 'task_type': self.task_type})
def _deserialize(self, request): result = {} try: result["image_meta"] = utils.get_image_meta_from_headers(request) except exception.InvalidParameterValue as e: msg = utils.exception_to_str(e) LOG.warn(msg, exc_info=True) raise HTTPBadRequest(explanation=e.msg, request=request) image_meta = result["image_meta"] image_meta = validate_image_meta(request, image_meta) if request.content_length: image_size = request.content_length elif "size" in image_meta: image_size = image_meta["size"] else: image_size = None data = request.body_file if self.has_body(request) else None if image_size is None and data is not None: data = utils.LimitingReader(data, CONF.image_size_cap) # NOTE(bcwaldon): this is a hack to make sure the downstream code # gets the correct image data request.body_file = data elif image_size > CONF.image_size_cap: max_image_size = CONF.image_size_cap msg = _("Denying attempt to upload image larger than %d bytes.") LOG.warn(msg % max_image_size) raise HTTPBadRequest(explanation=msg % max_image_size, request=request) result["image_data"] = data return result
def test_remove_namespace_not_found(self): fake_name = 'fake_name' namespace = self.namespace_repo.get(NAMESPACE1) namespace.namespace = fake_name exc = self.assertRaises(exception.NotFound, self.namespace_repo.remove, namespace) self.assertIn(fake_name, utils.exception_to_str(exc))
def test_add_no_container_no_create(self): """ Tests that adding an image with a non-existing container raises an appropriate exception """ self.config(swift_store_create_container_on_put=False, swift_store_container='noexist') self.store = Store() image_swift = six.StringIO("nevergonnamakeit") global SWIFT_PUT_OBJECT_CALLS SWIFT_PUT_OBJECT_CALLS = 0 # We check the exception text to ensure the container # missing text is found in it, otherwise, we would have # simply used self.assertRaises here exception_caught = False try: self.store.add(str(uuid.uuid4()), image_swift, 0) except BackendException as e: exception_caught = True self.assertIn("container noexist does not exist " "in Swift", utils.exception_to_str(e)) self.assertTrue(exception_caught) self.assertEqual(SWIFT_PUT_OBJECT_CALLS, 0)
def update(self, req, id, type_name, type_version, changes, **kwargs): """Performs an update via json patch request""" artifact_repo = self.gateway.get_artifact_repo(req.context) try: artifact = self._get_artifact_with_dependencies(artifact_repo, id, type_name, type_version) updated = artifact for change in changes: updated = self._do_update_op(updated, change) artifact_repo.save(updated) return self._get_artifact_with_dependencies(artifact_repo, id) except (exception.InvalidArtifactPropertyValue, exception.InvalidJsonPatchPath, exception.InvalidParameterValue) as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.StorageQuotaFull as e: msg = (_("Denying attempt to upload artifact because it exceeds " "the quota: %s") % utils.exception_to_str(e)) raise webob.exc.HTTPRequestEntityTooLarge( explanation=msg, request=req, content_type='text/plain') except exception.Invalid as e: raise webob.exc.HTTPBadRequest(explanation=e.msg) except exception.LimitExceeded as e: raise webob.exc.HTTPRequestEntityTooLarge( explanation=e.msg, request=req, content_type='text/plain')
def test_get_tag_not_found(self): exc = self.assertRaises(exception.NotFound, self.tag_repo.get, NAMESPACE2, TAG1) self.assertIn(TAG1, utils.exception_to_str(exc))
def test_get_property_not_found(self): exc = self.assertRaises(exception.NotFound, self.property_repo.get, NAMESPACE2, PROPERTY1) self.assertIn(PROPERTY1, utils.exception_to_str(exc))
def update_all(self, req, image_id, body): """ Replaces the members of the image with those specified in the body. The body is a dict with the following format:: {"memberships": [ {"member_id": <MEMBER_ID>, ["can_share": [True|False]]}, ... ]} """ self._check_can_access_image_members(req.context) # Make sure the image exists try: image = self.db_api.image_get(req.context, image_id) except exception.NotFound: msg = _("Image %(id)s not found") % {'id': image_id} LOG.info(msg) raise webob.exc.HTTPNotFound(msg) except exception.Forbidden: # If it's private and doesn't belong to them, don't let on # that it exists msg = _("Access denied to image %(id)s but returning 'not found'") LOG.info(msg % {'id': image_id}) raise webob.exc.HTTPNotFound() # Can they manipulate the membership? if not self.is_image_sharable(req.context, image): msg = _("User lacks permission to share image %(id)s") LOG.info(msg % {'id': image_id}) msg = _("No permission to share that image") raise webob.exc.HTTPForbidden(msg) # Get the membership list try: memb_list = body['memberships'] except Exception as e: # Malformed entity... msg = _("Invalid membership association specified for " "image %(id)s") LOG.info(msg % {'id': image_id}) msg = (_("Invalid membership association: %s") % utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest(explanation=msg) add = [] existing = {} # Walk through the incoming memberships for memb in memb_list: try: datum = dict(image_id=image['id'], member=memb['member_id'], can_share=None) except Exception as e: # Malformed entity... msg = _("Invalid membership association specified for " "image %(id)s") LOG.info(msg % {'id': image_id}) msg = (_("Invalid membership association: %s") % utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest(explanation=msg) # Figure out what can_share should be if 'can_share' in memb: datum['can_share'] = bool(memb['can_share']) # Try to find the corresponding membership members = self.db_api.image_member_find(req.context, image_id=datum['image_id'], member=datum['member']) try: member = members[0] except IndexError: # Default can_share datum['can_share'] = bool(datum['can_share']) add.append(datum) else: # Are we overriding can_share? if datum['can_share'] is None: datum['can_share'] = members[0]['can_share'] existing[member['id']] = { 'values': datum, 'membership': member, } # We now have a filtered list of memberships to add and # memberships to modify. Let's start by walking through all # the existing image memberships... existing_members = self.db_api.image_member_find(req.context, image_id=image['id']) for member in existing_members: if member['id'] in existing: # Just update the membership in place update = existing[member['id']]['values'] self.db_api.image_member_update(req.context, member['id'], update) else: # Outdated one; needs to be deleted self.db_api.image_member_delete(req.context, member['id']) # Now add the non-existent ones for memb in add: self.db_api.image_member_create(req.context, memb) # Make an appropriate result msg = _("Successfully updated memberships for image %(id)s") LOG.info(msg % {'id': image_id}) return webob.exc.HTTPNoContent()
def update(self, req, id, body): """Updates an existing image with the registry. :param req: wsgi Request object :param body: Dictionary of information about the image :param id: The opaque internal identifier for the image :retval Returns the updated image information as a mapping, """ image_data = body['image'] from_state = body.get('from_state', None) # Prohibit modification of 'owner' if not req.context.is_admin and 'owner' in image_data: del image_data['owner'] if 'location' in image_data: image_data['locations'] = [image_data.pop('location')] purge_props = req.headers.get("X-Glance-Registry-Purge-Props", "false") try: LOG.debug( "Updating image %(id)s with metadata: %(image_data)r", { 'id': id, 'image_data': {k: v for k, v in image_data.items() if k != 'locations'} }) image_data = _normalize_image_location_for_db(image_data) if purge_props == "true": purge_props = True else: purge_props = False updated_image = self.db_api.image_update(req.context, id, image_data, purge_props=purge_props, from_state=from_state) msg = _LI("Updating metadata for image %(id)s") % {'id': id} LOG.info(msg) return dict(image=make_image_dict(updated_image)) except exception.Invalid as e: msg = (_("Failed to update image metadata. " "Got error: %s") % utils.exception_to_str(e)) LOG.error(msg) return exc.HTTPBadRequest(msg) except exception.ImageNotFound: msg = _LI("Image %(id)s not found") % {'id': id} LOG.info(msg) raise exc.HTTPNotFound(body='Image not found', request=req, content_type='text/plain') except exception.ForbiddenPublicImage: msg = _LI("Update denied for public image %(id)s") % {'id': id} LOG.info(msg) raise exc.HTTPForbidden() except exception.Forbidden: # If it's private and doesn't belong to them, don't let on # that it exists msg = _LI("Access denied to image %(id)s but returning" " 'not found'") % { 'id': id } LOG.info(msg) raise exc.HTTPNotFound(body='Image not found', request=req, content_type='text/plain') except exception.Conflict as e: LOG.info(utils.exception_to_str(e)) raise exc.HTTPConflict(body='Image operation conflicts', request=req, content_type='text/plain') except Exception: LOG.exception(_LE("Unable to update image %s") % id) raise
def create(self, req, namespace): try: namespace_created = False # Create Namespace ns_factory = self.gateway.get_metadef_namespace_factory( req.context) ns_repo = self.gateway.get_metadef_namespace_repo(req.context) new_namespace = ns_factory.new_namespace(**namespace.to_dict()) ns_repo.add(new_namespace) namespace_created = True # Create Resource Types if namespace.resource_type_associations: rs_factory = (self.gateway.get_metadef_resource_type_factory( req.context)) rs_repo = self.gateway.get_metadef_resource_type_repo( req.context) for resource_type in namespace.resource_type_associations: new_resource = rs_factory.new_resource_type( namespace=namespace.namespace, **resource_type.to_dict()) rs_repo.add(new_resource) # Create Objects if namespace.objects: object_factory = self.gateway.get_metadef_object_factory( req.context) object_repo = self.gateway.get_metadef_object_repo(req.context) for metadata_object in namespace.objects: new_meta_object = object_factory.new_object( namespace=namespace.namespace, **metadata_object.to_dict()) object_repo.add(new_meta_object) # Create Tags if namespace.tags: tag_factory = self.gateway.get_metadef_tag_factory(req.context) tag_repo = self.gateway.get_metadef_tag_repo(req.context) for metadata_tag in namespace.tags: new_meta_tag = tag_factory.new_tag( namespace=namespace.namespace, **metadata_tag.to_dict()) tag_repo.add(new_meta_tag) # Create Namespace Properties if namespace.properties: prop_factory = (self.gateway.get_metadef_property_factory( req.context)) prop_repo = self.gateway.get_metadef_property_repo(req.context) for (name, value) in namespace.properties.items(): new_property_type = (prop_factory.new_namespace_property( namespace=namespace.namespace, **self._to_property_dict(name, value))) prop_repo.add(new_property_type) except exception.Forbidden as e: self._cleanup_namespace(ns_repo, namespace, namespace_created) raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: self._cleanup_namespace(ns_repo, namespace, namespace_created) raise webob.exc.HTTPNotFound(explanation=e.msg) except exception.Duplicate as e: self._cleanup_namespace(ns_repo, namespace, namespace_created) raise webob.exc.HTTPConflict(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() # Return the user namespace as we don't expose the id to user new_namespace.properties = namespace.properties new_namespace.objects = namespace.objects new_namespace.resource_type_associations = ( namespace.resource_type_associations) new_namespace.tags = namespace.tags return Namespace.to_wsme_model(new_namespace, get_namespace_href(new_namespace), self.ns_schema_link)
def _populate_metadata(meta, metadata_path=None): if not metadata_path: metadata_path = CONF.metadata_source_path try: json_schema_files = [ f for f in os.listdir(metadata_path) if isfile(join(metadata_path, f)) and f.endswith('.json') ] except OSError as e: LOG.error(utils.exception_to_str(e)) return metadef_namespaces_table = get_metadef_namespaces_table(meta) metadef_namespace_resource_types_tables =\ get_metadef_namespace_resource_types_table(meta) metadef_objects_table = get_metadef_objects_table(meta) metadef_properties_table = get_metadef_properties_table(meta) metadef_resource_types_table = get_metadef_resource_types_table(meta) if not json_schema_files: LOG.error(_LE("Json schema files not found in %s. Aborting."), metadata_path) return for namespace_id, json_schema_file in enumerate(json_schema_files, start=1): try: file = join(metadata_path, json_schema_file) json_metadata = open(file) metadata = json.load(json_metadata) json_metadata.close() except Exception as e: LOG.error(utils.exception_to_str(e)) continue values = { 'id': namespace_id, 'namespace': metadata.get('namespace', None), 'display_name': metadata.get('display_name', None), 'description': metadata.get('description', None), 'visibility': metadata.get('visibility', None), 'protected': metadata.get('protected', None), 'owner': metadata.get('owner', 'admin'), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_namespaces_table, values) for resource_type in metadata.get('resource_type_associations', []): try: resource_type_id = \ _get_resource_type_id(meta, resource_type['name']) except AttributeError: values = { 'name': resource_type['name'], 'protected': True, 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_resource_types_table, values) resource_type_id =\ _get_resource_type_id(meta, resource_type['name']) values = { 'resource_type_id': resource_type_id, 'namespace_id': namespace_id, 'created_at': timeutils.utcnow(), 'properties_target': resource_type.get('properties_target'), 'prefix': resource_type.get('prefix', None) } _insert_data_to_db(metadef_namespace_resource_types_tables, values) for property, schema in metadata.get('properties', {}).iteritems(): values = { 'name': property, 'namespace_id': namespace_id, 'schema': json.dumps(schema), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_properties_table, values) for object in metadata.get('objects', []): values = { 'name': object.get('name', None), 'description': object.get('description', None), 'namespace_id': namespace_id, 'schema': json.dumps(object.get('properties', None)), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_objects_table, values) LOG.info(_LI("File %s loaded to database."), file) LOG.info(_LI("Metadata loading finished"))
def upload_data_to_store(req, image_meta, image_data, store, notifier): """ Upload image data to specified store. Upload image data to the store and cleans up on error. """ image_id = image_meta['id'] db_api = glance.db.get_api() image_size = image_meta.get('size') try: remaining = glance.api.common.check_quota( req.context, image_size, db_api, image_id=image_id) if remaining is not None: image_data = utils.LimitingReader(image_data, remaining) (uri, size, checksum, location_metadata) = store_api.store_add_to_backend( image_meta['id'], utils.CooperativeReader(image_data), image_meta['size'], store) location_data = {'url': uri, 'metadata': location_metadata, 'status': 'active'} try: # recheck the quota in case there were simultaneous uploads that # did not provide the size glance.api.common.check_quota( req.context, size, db_api, image_id=image_id) except exception.StorageQuotaFull: with excutils.save_and_reraise_exception(): LOG.info(_LI('Cleaning up %s after exceeding ' 'the quota') % image_id) store_utils.safe_delete_from_backend( req.context, image_meta['id'], location_data) def _kill_mismatched(image_meta, attr, actual): supplied = image_meta.get(attr) if supplied and supplied != actual: msg = (_("Supplied %(attr)s (%(supplied)s) and " "%(attr)s generated from uploaded image " "(%(actual)s) did not match. Setting image " "status to 'killed'.") % {'attr': attr, 'supplied': supplied, 'actual': actual}) LOG.error(msg) safe_kill(req, image_id, 'saving') initiate_deletion(req, location_data, image_id) raise webob.exc.HTTPBadRequest(explanation=msg, content_type="text/plain", request=req) # Verify any supplied size/checksum value matches size/checksum # returned from store when adding image _kill_mismatched(image_meta, 'size', size) _kill_mismatched(image_meta, 'checksum', checksum) # Update the database with the checksum returned # from the backend store LOG.debug("Updating image %(image_id)s data. " "Checksum set to %(checksum)s, size set " "to %(size)d", {'image_id': image_id, 'checksum': checksum, 'size': size}) update_data = {'checksum': checksum, 'size': size} try: image_meta = registry.update_image_metadata(req.context, image_id, update_data, from_state='saving') except exception.NotFound as e: msg = _LI("Image %s could not be found after upload. The image may" " have been deleted during the upload.") % image_id LOG.info(msg) # NOTE(jculp): we need to clean up the datastore if an image # resource is deleted while the image data is being uploaded # # We get "location_data" from above call to store.add(), any # exceptions that occur there handle this same issue internally, # Since this is store-agnostic, should apply to all stores. initiate_deletion(req, location_data, image_id) raise webob.exc.HTTPPreconditionFailed(explanation=msg, request=req, content_type='text/plain') except exception.Duplicate as e: msg = u"Attempt to upload duplicate image: %s" % e LOG.debug(msg) # NOTE(dosaboy): do not delete the image since it is likely that this # conflict is a result of another concurrent upload that will be # successful. notifier.error('image.upload', msg) raise webob.exc.HTTPConflict(explanation=msg, request=req, content_type="text/plain") except exception.Forbidden as e: msg = u"Forbidden upload attempt: %s" % e LOG.debug(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPForbidden(explanation=msg, request=req, content_type="text/plain") except store_api.StorageFull as e: msg = _("Image storage media is full: %s") % utils.exception_to_str(e) LOG.error(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req, content_type='text/plain') except store_api.StorageWriteDenied as e: msg = (_("Insufficient permissions on image storage media: %s") % utils.exception_to_str(e)) LOG.error(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPServiceUnavailable(explanation=msg, request=req, content_type='text/plain') except exception.ImageSizeLimitExceeded as e: msg = (_("Denying attempt to upload image larger than %d bytes.") % CONF.image_size_cap) LOG.info(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req, content_type='text/plain') except exception.StorageQuotaFull as e: msg = (_("Denying attempt to upload image because it exceeds the ." "quota: %s") % utils.exception_to_str(e)) LOG.info(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req, content_type='text/plain') except webob.exc.HTTPError: #NOTE(bcwaldon): Ideally, we would just call 'raise' here, # but something in the above function calls is affecting the # exception context and we must explicitly re-raise the # caught exception. msg = _LE("Received HTTP error while uploading image %s") % image_id notifier.error('image.upload', msg) with excutils.save_and_reraise_exception(): LOG.exception(msg) safe_kill(req, image_id, 'saving') except (ValueError, IOError) as e: msg = "Client disconnected before sending all data to backend" LOG.debug(msg) safe_kill(req, image_id, 'saving') raise webob.exc.HTTPBadRequest(explanation=msg, content_type="text/plain", request=req) except Exception as e: msg = _("Failed to upload image %s") % image_id LOG.exception(msg) safe_kill(req, image_id, 'saving') notifier.error('image.upload', msg) raise webob.exc.HTTPInternalServerError(explanation=msg, request=req, content_type='text/plain') return image_meta, location_data
def upload(self, req, image_id, data, size): image_repo = self.gateway.get_repo(req.context) image = None try: image = image_repo.get(image_id) image.status = 'saving' try: image_repo.save(image) image.set_data(data, size) image_repo.save(image) except exception.NotFound as e: msg = (_("Image %(id)s could not be found after upload." "The image may have been deleted during the upload: " "%(error)s Cleaning up the chunks uploaded") % {'id': image_id, 'error': utils.exception_to_str(e)}) LOG.warn(msg) # NOTE(sridevi): Cleaning up the uploaded chunks. try: image.delete() except exception.NotFound: # NOTE(sridevi): Ignore this exception pass raise webob.exc.HTTPGone(explanation=msg, request=req, content_type='text/plain') except ValueError as e: LOG.debug("Cannot save data for image %(id)s: %(e)s", {'id': image_id, 'e': utils.exception_to_str(e)}) self._restore(image_repo, image) raise webob.exc.HTTPBadRequest( explanation=utils.exception_to_str(e)) except glance_store.StoreAddDisabled: msg = _("Error in store configuration. Adding images to store " "is disabled.") LOG.exception(msg) self._restore(image_repo, image) raise webob.exc.HTTPGone(explanation=msg, request=req, content_type='text/plain') except exception.InvalidImageStatusTransition as e: msg = utils.exception_to_str(e) LOG.debug(msg) raise webob.exc.HTTPConflict(explanation=e.msg, request=req) except exception.Forbidden as e: msg = ("Not allowed to upload image data for image %s" % image_id) LOG.debug(msg) raise webob.exc.HTTPForbidden(explanation=msg, request=req) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except glance_store.StorageFull as e: msg = _("Image storage media " "is full: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(image_repo, image) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except exception.StorageQuotaFull as e: msg = _("Image exceeds the storage " "quota: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(image_repo, image) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except exception.ImageSizeLimitExceeded as e: msg = _("The incoming image is " "too large: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(image_repo, image) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except glance_store.StorageWriteDenied as e: msg = _("Insufficient permissions on image " "storage media: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(image_repo, image) raise webob.exc.HTTPServiceUnavailable(explanation=msg, request=req) except webob.exc.HTTPError as e: with excutils.save_and_reraise_exception(): LOG.error(_LE("Failed to upload image data due to HTTP error")) self._restore(image_repo, image) except Exception as e: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Failed to upload image data due to " "internal error")) self._restore(image_repo, image)
def update(self, req, id, image_meta, image_data): """ Updates an existing image with the registry. :param request: The WSGI/Webob Request object :param id: The opaque image identifier :retval Returns the updated image information as a mapping """ self._enforce(req, 'modify_image') is_public = image_meta.get('is_public') if is_public: self._enforce(req, 'publicize_image') if Controller._copy_from(req): self._enforce(req, 'copy_from') if image_data or Controller._copy_from(req): self._enforce(req, 'upload_image') orig_image_meta = self.get_image_meta_or_404(req, id) orig_status = orig_image_meta['status'] # Do not allow any updates on a deleted image. # Fix for LP Bug #1060930 if orig_status == 'deleted': msg = _("Forbidden to update deleted image.") raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") if req.context.is_admin is False: # Once an image is 'active' only an admin can # modify certain core metadata keys for key in ACTIVE_IMMUTABLE: if (orig_status == 'active' and image_meta.get(key) is not None and image_meta.get(key) != orig_image_meta.get(key)): msg = _("Forbidden to modify '%s' of active image.") % key raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") # The default behaviour for a PUT /images/<IMAGE_ID> is to # override any properties that were previously set. This, however, # leads to a number of issues for the common use case where a caller # registers an image with some properties and then almost immediately # uploads an image file along with some more properties. Here, we # check for a special header value to be false in order to force # properties NOT to be purged. However we also disable purging of # properties if an image file is being uploaded... purge_props = req.headers.get('x-glance-registry-purge-props', True) purge_props = (strutils.bool_from_string(purge_props) and image_data is None) if image_data is not None and orig_status != 'queued': raise HTTPConflict(_("Cannot upload to an unqueued image")) # Only allow the Location|Copy-From fields to be modified if the # image is in queued status, which indicates that the user called # POST /images but originally supply neither a Location|Copy-From # field NOR image data location = self._external_source(image_meta, req) reactivating = orig_status != 'queued' and location activating = orig_status == 'queued' and (location or image_data) # Make image public in the backend store (if implemented) orig_or_updated_loc = location or orig_image_meta.get('location') if orig_or_updated_loc: try: self.update_store_acls(req, id, orig_or_updated_loc, public=is_public) except exception.BadStoreUri: msg = "Invalid location %s" % location LOG.debug(msg) raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain") if reactivating: msg = _("Attempted to update Location field for an image " "not in queued status.") raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain") # ensure requester has permissions to create/update/delete properties # according to property-protections.conf orig_keys = set(orig_image_meta['properties']) new_keys = set(image_meta['properties']) self._enforce_update_protected_props(orig_keys.intersection(new_keys), image_meta, orig_image_meta, req) self._enforce_create_protected_props(new_keys.difference(orig_keys), req) if purge_props: self._enforce_delete_protected_props( orig_keys.difference(new_keys), image_meta, orig_image_meta, req) self._enforce_image_property_quota(image_meta, orig_image_meta=orig_image_meta, purge_props=purge_props, req=req) try: if location: image_meta['size'] = self._get_size(req.context, image_meta, location) image_meta = registry.update_image_metadata( req.context, id, image_meta, purge_props) if activating: image_meta = self._handle_source(req, id, image_meta, image_data) except exception.Invalid as e: msg = ("Failed to update image metadata. Got error: %(e)s" % { 'e': e }) LOG.debug(msg) raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain") except exception.NotFound as e: msg = _("Failed to find image to update: %(e)s") % {'e': e} for line in msg.split('\n'): LOG.info(line) raise HTTPNotFound(explanation=msg, request=req, content_type="text/plain") except exception.Forbidden as e: msg = _("Forbidden to update image: %(e)s") % {'e': e} for line in msg.split('\n'): LOG.info(line) raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") except (exception.Conflict, exception.Duplicate) as e: LOG.info(utils.exception_to_str(e)) raise HTTPConflict(body='Image operation conflicts', request=req, content_type='text/plain') else: self.notifier.info('image.update', redact_loc(image_meta)) # Prevent client from learning the location, as it # could contain security credentials image_meta = redact_loc(image_meta) self._enforce_read_protected_props(image_meta, req) return {'image_meta': image_meta}
def add(self, image_id, image_file, image_size, connection=None): location = self.create_location(image_id) if not connection: connection = self.get_connection(location) self._create_container_if_missing(location.container, connection) LOG.debug("Adding image object '%(obj_name)s' " "to Swift" % dict(obj_name=location.obj)) try: if image_size > 0 and image_size < self.large_object_size: # Image size is known, and is less than large_object_size. # Send to Swift with regular PUT. obj_etag = connection.put_object(location.container, location.obj, image_file, content_length=image_size) else: # Write the image into Swift in chunks. chunk_id = 1 if image_size > 0: total_chunks = str( int( math.ceil( float(image_size) / float(self.large_object_chunk_size)))) else: # image_size == 0 is when we don't know the size # of the image. This can occur with older clients # that don't inspect the payload size. LOG.debug("Cannot determine image size. Adding as a " "segmented object to Swift.") total_chunks = '?' checksum = hashlib.md5() written_chunks = [] combined_chunks_size = 0 while True: chunk_size = self.large_object_chunk_size if image_size == 0: content_length = None else: left = image_size - combined_chunks_size if left == 0: break if chunk_size > left: chunk_size = left content_length = chunk_size chunk_name = "%s-%05d" % (location.obj, chunk_id) reader = ChunkReader(image_file, checksum, chunk_size) try: chunk_etag = connection.put_object( location.container, chunk_name, reader, content_length=content_length) written_chunks.append(chunk_name) except Exception: # Delete orphaned segments from swift backend with excutils.save_and_reraise_exception(): LOG.exception( _("Error during chunked upload to " "backend, deleting stale chunks")) self._delete_stale_chunks(connection, location.container, written_chunks) bytes_read = reader.bytes_read msg = ("Wrote chunk %(chunk_name)s (%(chunk_id)d/" "%(total_chunks)s) of length %(bytes_read)d " "to Swift returning MD5 of content: " "%(chunk_etag)s" % { 'chunk_name': chunk_name, 'chunk_id': chunk_id, 'total_chunks': total_chunks, 'bytes_read': bytes_read, 'chunk_etag': chunk_etag }) LOG.debug(msg) if bytes_read == 0: # Delete the last chunk, because it's of zero size. # This will happen if size == 0. LOG.debug("Deleting final zero-length chunk") connection.delete_object(location.container, chunk_name) break chunk_id += 1 combined_chunks_size += bytes_read # In the case we have been given an unknown image size, # set the size to the total size of the combined chunks. if image_size == 0: image_size = combined_chunks_size # Now we write the object manifest and return the # manifest's etag... manifest = "%s/%s-" % (location.container, location.obj) headers = { 'ETag': hashlib.md5("").hexdigest(), 'X-Object-Manifest': manifest } # The ETag returned for the manifest is actually the # MD5 hash of the concatenated checksums of the strings # of each chunk...so we ignore this result in favour of # the MD5 of the entire image file contents, so that # users can verify the image file contents accordingly connection.put_object(location.container, location.obj, None, headers=headers) obj_etag = checksum.hexdigest() # NOTE: We return the user and key here! Have to because # location is used by the API server to return the actual # image data. We *really* should consider NOT returning # the location attribute from GET /images/<ID> and # GET /images/details if swift_store_utils.is_multiple_swift_store_accounts_enabled(): include_creds = False else: include_creds = True return (location.get_uri(credentials_included=include_creds), image_size, obj_etag, {}) except swiftclient.ClientException as e: if e.http_status == httplib.CONFLICT: raise exception.Duplicate( _("Swift already has an image at " "this location")) msg = (_("Failed to add object to Swift.\n" "Got error from Swift: %s") % utils.exception_to_str(e)) LOG.error(msg) raise glance.store.BackendException(msg)
def delete(self, req, id): """ Deletes the image and all its chunks from the Glance :param req: The WSGI/Webob Request object :param id: The opaque image identifier :raises HttpBadRequest if image registry is invalid :raises HttpNotFound if image or any chunk is not available :raises HttpUnauthorized if image or any chunk is not deleteable by the requesting user """ self._enforce(req, 'delete_image') image = self.get_image_meta_or_404(req, id) if image['protected']: msg = "Image is protected" LOG.debug(msg) raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") if image['status'] == 'pending_delete': msg = "Forbidden to delete a %s image." % image['status'] LOG.debug(msg) raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") elif image['status'] == 'deleted': msg = "Image %s not found." % id LOG.debug(msg) raise HTTPNotFound(explanation=msg, request=req, content_type="text/plain") if image['location'] and CONF.delayed_delete: status = 'pending_delete' else: status = 'deleted' ori_status = image['status'] try: # Update the image from the registry first, since we rely on it # for authorization checks. # See https://bugs.launchpad.net/glance/+bug/1065187 image = registry.update_image_metadata(req.context, id, {'status': status}) try: # The image's location field may be None in the case # of a saving or queued image, therefore don't ask a backend # to delete the image if the backend doesn't yet store it. # See https://bugs.launchpad.net/glance/+bug/747799 if image['location']: for loc_data in image['location_data']: if loc_data['status'] == 'active': upload_utils.initiate_deletion(req, loc_data, id) except Exception: with excutils.save_and_reraise_exception(): registry.update_image_metadata(req.context, id, {'status': ori_status}) registry.delete_image_metadata(req.context, id) except exception.NotFound as e: msg = (_("Failed to find image to delete: %s") % utils.exception_to_str(e)) for line in msg.split('\n'): LOG.info(line) raise HTTPNotFound(explanation=msg, request=req, content_type="text/plain") except exception.Forbidden as e: msg = (_("Forbidden to delete image: %s") % utils.exception_to_str(e)) for line in msg.split('\n'): LOG.info(line) raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain") else: self.notifier.info('image.delete', redact_loc(image)) return Response(body='', status=200)
def _populate_metadata(meta, metadata_path=None): if not metadata_path: metadata_path = CONF.metadata_source_path try: json_schema_files = [ f for f in os.listdir(metadata_path) if isfile(join(metadata_path, f)) and f.endswith('.json') ] except OSError as e: LOG.error(utils.exception_to_str(e)) return metadef_namespaces_table = get_metadef_namespaces_table(meta) metadef_namespace_resource_types_tables =\ get_metadef_namespace_resource_types_table(meta) metadef_objects_table = get_metadef_objects_table(meta) metadef_tags_table = get_metadef_tags_table(meta) metadef_properties_table = get_metadef_properties_table(meta) metadef_resource_types_table = get_metadef_resource_types_table(meta) if not json_schema_files: LOG.error(_LE("Json schema files not found in %s. Aborting."), metadata_path) return for json_schema_file in json_schema_files: try: file = join(metadata_path, json_schema_file) with open(file) as json_file: metadata = json.load(json_file) except Exception as e: LOG.error(utils.exception_to_str(e)) continue values = { 'namespace': metadata.get('namespace', None), 'display_name': metadata.get('display_name', None), 'description': metadata.get('description', None), 'visibility': metadata.get('visibility', None), 'protected': metadata.get('protected', None), 'owner': metadata.get('owner', 'admin'), 'created_at': timeutils.utcnow() } temp = metadef_namespaces_table.select( whereclause='namespace = \'%s\'' % values['namespace'])\ .execute().fetchone() if temp is not None: LOG.info( _LI("Skipping namespace %s. It already exists in the " "database."), values['namespace']) continue _insert_data_to_db(metadef_namespaces_table, values) db_namespace = select([ metadef_namespaces_table.c.id ]).where(metadef_namespaces_table.c.namespace == values['namespace'] ).select_from(metadef_namespaces_table).execute().fetchone() namespace_id = db_namespace['id'] for resource_type in metadata.get('resource_type_associations', []): try: resource_type_id = \ _get_resource_type_id(meta, resource_type['name']) except AttributeError: values = { 'name': resource_type['name'], 'protected': True, 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_resource_types_table, values) resource_type_id =\ _get_resource_type_id(meta, resource_type['name']) values = { 'resource_type_id': resource_type_id, 'namespace_id': namespace_id, 'created_at': timeutils.utcnow(), 'properties_target': resource_type.get('properties_target'), 'prefix': resource_type.get('prefix', None) } _insert_data_to_db(metadef_namespace_resource_types_tables, values) for property, schema in six.iteritems(metadata.get('properties', {})): values = { 'name': property, 'namespace_id': namespace_id, 'json_schema': json.dumps(schema), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_properties_table, values) for object in metadata.get('objects', []): values = { 'name': object.get('name'), 'description': object.get('description', None), 'namespace_id': namespace_id, 'json_schema': json.dumps(object.get('properties', None)), 'created_at': timeutils.utcnow() } _insert_data_to_db(metadef_objects_table, values) for tag in metadata.get('tags', []): timeutils_utcnow = timeutils.utcnow() values = { 'name': tag.get('name'), 'namespace_id': namespace_id, 'created_at': timeutils_utcnow, 'updated_at': timeutils_utcnow } _insert_data_to_db(metadef_tags_table, values) LOG.info(_LI("File %s loaded to database."), file) LOG.info(_LI("Metadata loading finished"))
def test_get_not_found(self): fake_uuid = str(uuid.uuid4()) exc = self.assertRaises(exception.NotFound, self.image_repo.get, fake_uuid) self.assertIn(fake_uuid, utils.exception_to_str(exc))
def _export_data_to_file(meta, path): if not path: path = CONF.metadata_source_path namespace_table = get_metadef_namespaces_table(meta) namespaces = namespace_table.select().execute().fetchall() pattern = re.compile('[\W_]+', re.UNICODE) for id, namespace in enumerate(namespaces, start=1): namespace_id = namespace['id'] namespace_file_name = pattern.sub('', namespace['display_name']) values = { 'namespace': namespace['namespace'], 'display_name': namespace['display_name'], 'description': namespace['description'], 'visibility': namespace['visibility'], 'protected': namespace['protected'], 'owner': namespace['owner'], 'resource_type_associations': [], 'properties': {}, 'objects': [], 'tags': [] } namespace_resource_types = _get_namespace_resource_types( meta, namespace_id) db_objects = _get_objects(meta, namespace_id) db_properties = _get_properties(meta, namespace_id) db_tags = _get_tags(meta, namespace_id) resource_types = [] for namespace_resource_type in namespace_resource_types: resource_type =\ _get_resource_type(meta, namespace_resource_type['resource_type_id']) resource_types.append({ 'name': resource_type['name'], 'protected': resource_type['protected'] }) values.update({'resource_type_associations': resource_types}) objects = [] for object in db_objects: objects.append({ "name": object['name'], "description": object['description'], "properties": json.loads(object['json_schema']) }) values.update({'objects': objects}) properties = {} for property in db_properties: properties.update( {property['name']: json.loads(property['json_schema'])}) values.update({'properties': properties}) tags = [] for tag in db_tags: tags.append({"name": tag['name']}) values.update({'tags': tags}) try: file_name = ''.join([path, namespace_file_name, '.json']) with open(file_name, 'w') as json_file: json_file.write(json.dumps(values)) except Exception as e: LOG.exception(utils.exception_to_str(e)) LOG.info( _LI("Namespace %(namespace)s saved in %(file)s") % { 'namespace': namespace_file_name, 'file': file_name })
def test_list_object_namespace_not_found(self): exc = self.assertRaises(exception.NotFound, self.object_repo.list, filters={'namespace': 'not-a-namespace'}) self.assertIn('not-a-namespace', utils.exception_to_str(exc))
def _check_allowed(cls, image): for key in cls._disallowed_properties: if key in image: msg = _("Attribute '%s' is read-only.") % key raise webob.exc.HTTPForbidden( explanation=utils.exception_to_str(msg))
def _reserve(self, req, image_meta): """ Adds the image metadata to the registry and assigns an image identifier if one is not supplied in the request headers. Sets the image's status to `queued`. :param req: The WSGI/Webob Request object :param id: The opaque image identifier :param image_meta: The image metadata :raises HTTPConflict if image already exists :raises HTTPBadRequest if image metadata is not valid """ location = self._external_source(image_meta, req) store = image_meta.get('store') if store and store not in get_known_stores(): msg = "Required store %s is invalid" % store LOG.debug(msg) raise HTTPBadRequest(explanation=msg, content_type='text/plain') image_meta['status'] = ('active' if image_meta.get('size') == 0 else 'queued') if location: try: store = get_store_from_location(location) except exception.BadStoreUri: msg = "Invalid location %s" % location LOG.debug(msg) raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain") # check the store exists before we hit the registry, but we # don't actually care what it is at this point self.get_store_or_400(req, store) # retrieve the image size from remote store (if not provided) image_meta['size'] = self._get_size(req.context, image_meta, location) else: # Ensure that the size attribute is set to zero for directly # uploadable images (if not provided). The size will be set # to a non-zero value during upload image_meta['size'] = image_meta.get('size', 0) try: image_meta = registry.add_image_metadata(req.context, image_meta) self.notifier.info("image.create", redact_loc(image_meta)) return image_meta except exception.Duplicate: msg = ("An image with identifier %s already exists" % image_meta['id']) LOG.debug(msg) raise HTTPConflict(explanation=msg, request=req, content_type="text/plain") except exception.Invalid as e: msg = (_("Failed to reserve image. Got error: %s") % utils.exception_to_str(e)) for line in msg.split('\n'): LOG.debug(line) raise HTTPBadRequest(explanation=msg, request=req, content_type="text/plain") except exception.Forbidden: msg = "Forbidden to reserve image." LOG.debug(msg) raise HTTPForbidden(explanation=msg, request=req, content_type="text/plain")
def test_get_object_not_found(self): exc = self.assertRaises(exception.NotFound, self.object_repo.get, NAMESPACE2, OBJECT1) self.assertIn(OBJECT1, utils.exception_to_str(exc))
def fail(e): global KNOWN_EXCEPTIONS return_code = KNOWN_EXCEPTIONS.index(type(e)) + 1 sys.stderr.write("ERROR: %s\n" % utils.exception_to_str(e)) sys.exit(return_code)
def set_data(self, data, size=None): self.send_notification('image.prepare', self.repo) notify_error = self.notifier.error try: self.repo.set_data(data, size) except glance_store.StorageFull as e: msg = (_("Image storage media is full: %s") % utils.exception_to_str(e)) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg) except glance_store.StorageWriteDenied as e: msg = (_("Insufficient permissions on image storage media: %s") % utils.exception_to_str(e)) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPServiceUnavailable(explanation=msg) except ValueError as e: msg = (_("Cannot save data for image %(image_id)s: %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPBadRequest( explanation=utils.exception_to_str(e)) except exception.Duplicate as e: msg = (_("Unable to upload duplicate image data for image" "%(image_id)s: %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPConflict(explanation=msg) except exception.Forbidden as e: msg = (_("Not allowed to upload image data for image %(image_id)s:" " %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPForbidden(explanation=msg) except exception.NotFound as e: msg = (_("Image %(image_id)s could not be found after upload." " The image may have been deleted during the upload:" " %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) raise webob.exc.HTTPNotFound(explanation=utils.exception_to_str(e)) except webob.exc.HTTPError as e: with excutils.save_and_reraise_exception(): msg = (_("Failed to upload image data for image %(image_id)s" " due to HTTP error: %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) except Exception as e: with excutils.save_and_reraise_exception(): msg = (_("Failed to upload image data for image %(image_id)s " "due to internal error: %(error)s") % { 'image_id': self.repo.image_id, 'error': utils.exception_to_str(e) }) _send_notification(notify_error, 'image.upload', msg) else: self.send_notification('image.upload', self.repo) self.send_notification('image.activate', self.repo)
def update(self, req, image_id, id, body=None): """ Adds a membership to the image, or updates an existing one. If a body is present, it is a dict with the following format:: {"member": { "can_share": [True|False] }} If "can_share" is provided, the member's ability to share is set accordingly. If it is not provided, existing memberships remain unchanged and new memberships default to False. """ self._check_can_access_image_members(req.context) # Make sure the image exists try: image = self.db_api.image_get(req.context, image_id) except exception.NotFound: msg = _("Image %(id)s not found") % {'id': image_id} LOG.info(msg) raise webob.exc.HTTPNotFound(msg) except exception.Forbidden: # If it's private and doesn't belong to them, don't let on # that it exists msg = _("Access denied to image %(id)s but returning 'not found'") LOG.info(msg % {'id': image_id}) raise webob.exc.HTTPNotFound() # Can they manipulate the membership? if not self.is_image_sharable(req.context, image): msg = _("User lacks permission to share image %(id)s") LOG.info(msg % {'id': image_id}) msg = _("No permission to share that image") raise webob.exc.HTTPForbidden(msg) # Determine the applicable can_share value can_share = None if body: try: can_share = bool(body['member']['can_share']) except Exception as e: # Malformed entity... msg = _("Invalid membership association specified for " "image %(id)s") LOG.info(msg % {'id': image_id}) msg = (_("Invalid membership association: %s") % utils.exception_to_str(e)) raise webob.exc.HTTPBadRequest(explanation=msg) # Look up an existing membership... members = self.db_api.image_member_find(req.context, image_id=image_id, member=id) if members: if can_share is not None: values = dict(can_share=can_share) self.db_api.image_member_update(req.context, members[0]['id'], values) else: values = dict(image_id=image['id'], member=id, can_share=bool(can_share)) self.db_api.image_member_create(req.context, values) msg = _("Successfully updated a membership for image %(id)s") LOG.info(msg % {'id': image_id}) return webob.exc.HTTPNoContent()
def test_get_namespace_not_found(self): fake_namespace = "fake_namespace" exc = self.assertRaises(exception.NotFound, self.namespace_repo.get, fake_namespace) self.assertIn(fake_namespace, utils.exception_to_str(exc))
def fail(returncode, e): sys.stderr.write("ERROR: %s\n" % utils.exception_to_str(e)) sys.exit(returncode)
def validate(self, obj): try: jsonschema.validate(obj, self.raw()) except jsonschema.ValidationError as e: raise exception.InvalidObject(schema=self.name, reason=utils.exception_to_str(e))
def upload(self, req, id, type_name, type_version, attr, size, data, index, **kwargs): artifact_repo = self.gateway.get_artifact_repo(req.context) artifact = None try: artifact = self._get_artifact_with_dependencies( artifact_repo, id, type_name, type_version) blob_prop = artifact.metadata.attributes.blobs.get(attr) if blob_prop is None: raise webob.exc.HTTPBadRequest( explanation=_("Not a blob property '%s'") % attr) if isinstance(blob_prop, list): blob_list = getattr(artifact, attr) self._upload_list_property(req.method, blob_list, index, data, size) else: if index is not None: raise webob.exc.HTTPBadRequest( explanation=_("Not a list property '%s'") % attr) setattr(artifact, attr, (data, size)) artifact_repo.save(artifact) return artifact except ValueError as e: LOG.debug("Cannot save data for artifact %(id)s: %(e)s", { 'id': id, 'e': utils.exception_to_str(e) }) self._restore(artifact_repo, artifact) raise webob.exc.HTTPBadRequest( explanation=utils.exception_to_str(e)) except glance_store.StoreAddDisabled: msg = _("Error in store configuration. Adding artifacts to store " "is disabled.") LOG.exception(msg) self._restore(artifact_repo, artifact) raise webob.exc.HTTPGone(explanation=msg, request=req, content_type='text/plain') except (glance_store.Duplicate, exception.InvalidImageStatusTransition) as e: msg = utils.exception_to_str(e) LOG.exception(msg) raise webob.exc.HTTPConflict(explanation=e.msg, request=req) except exception.Forbidden as e: msg = ("Not allowed to upload data for artifact %s" % id) LOG.debug(msg) raise webob.exc.HTTPForbidden(explanation=msg, request=req) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except glance_store.StorageFull as e: msg = _("Artifact storage media " "is full: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(artifact_repo, artifact) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except exception.StorageQuotaFull as e: msg = _("Artifact exceeds the storage " "quota: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(artifact_repo, artifact) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except exception.ImageSizeLimitExceeded as e: msg = _("The incoming artifact blob is " "too large: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(artifact_repo, artifact) raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg, request=req) except glance_store.StorageWriteDenied as e: msg = _("Insufficient permissions on artifact " "storage media: %s") % utils.exception_to_str(e) LOG.error(msg) self._restore(artifact_repo, artifact) raise webob.exc.HTTPServiceUnavailable(explanation=msg, request=req) except webob.exc.HTTPGone as e: with excutils.save_and_reraise_exception(): LOG.error( _LE("Failed to upload artifact blob data due to" " HTTP error")) except webob.exc.HTTPError as e: with excutils.save_and_reraise_exception(): LOG.error( _LE("Failed to upload artifact blob data due to HTTP" " error")) self._restore(artifact_repo, artifact) except Exception as e: with excutils.save_and_reraise_exception(): LOG.exception( _LE("Failed to upload artifact blob data due to " "internal error")) self._restore(artifact_repo, artifact)
def show(self, req, namespace, filters=None): try: # Get namespace ns_repo = self.gateway.get_metadef_namespace_repo(req.context) namespace_obj = ns_repo.get(namespace) namespace_detail = Namespace.to_wsme_model( namespace_obj, get_namespace_href(namespace_obj), self.ns_schema_link) ns_filters = dict() ns_filters['namespace'] = namespace # Get objects object_repo = self.gateway.get_metadef_object_repo(req.context) db_metaobject_list = object_repo.list(filters=ns_filters) object_list = [ MetadefObject.to_wsme_model( db_metaobject, get_object_href(namespace, db_metaobject), self.obj_schema_link) for db_metaobject in db_metaobject_list ] if object_list: namespace_detail.objects = object_list # Get resource type associations rs_repo = self.gateway.get_metadef_resource_type_repo(req.context) db_resource_type_list = rs_repo.list(filters=ns_filters) resource_type_list = [ ResourceTypeAssociation.to_wsme_model(resource_type) for resource_type in db_resource_type_list ] if resource_type_list: namespace_detail.resource_type_associations = ( resource_type_list) # Get properties prop_repo = self.gateway.get_metadef_property_repo(req.context) db_properties = prop_repo.list(filters=ns_filters) property_list = Namespace.to_model_properties(db_properties) if property_list: namespace_detail.properties = property_list if filters and filters['resource_type']: namespace_detail = self._prefix_property_name( namespace_detail, filters['resource_type']) # Get tags tag_repo = self.gateway.get_metadef_tag_repo(req.context) db_metatag_list = tag_repo.list(filters=ns_filters) tag_list = [ MetadefTag(**{'name': db_metatag.name}) for db_metatag in db_metatag_list ] if tag_list: namespace_detail.tags = tag_list except exception.Forbidden as e: raise webob.exc.HTTPForbidden(explanation=e.msg) except exception.NotFound as e: raise webob.exc.HTTPNotFound(explanation=e.msg) except Exception as e: LOG.error(utils.exception_to_str(e)) raise webob.exc.HTTPInternalServerError() return namespace_detail