コード例 #1
0
    def _query(self, location, method, depth=0):
        if depth > MAX_REDIRECTS:
            msg = ("The HTTP URL exceeded %(max_redirects)s maximum "
                   "redirects.", {
                       'max_redirects': MAX_REDIRECTS
                   })
            LOG.debug(msg)
            raise exception.MaxRedirectsExceeded(redirects=MAX_REDIRECTS)
        loc = location.store_location
        cookie = self._build_vim_cookie_header(
            self._session.vim.client.options.transport.cookiejar)
        headers = {'Cookie': cookie}
        try:
            conn = self._get_http_conn(method, loc, headers)
            resp = conn.getresponse()
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception(_LE('Failed to access image %(image)s content.'),
                              {'image': location.image_id})
        if resp.status >= 400:
            if resp.status == httplib.UNAUTHORIZED:
                self._create_session()
                raise exception.NotAuthenticated()
            if resp.status == httplib.NOT_FOUND:
                msg = 'VMware datastore could not find image at URI.'
                LOG.debug(msg)
                raise exception.NotFound(msg)
            reason = (_('HTTP request returned a %(status)s status code.') % {
                'status': resp.status
            })
            LOG.info(reason)
            raise exception.BadStoreUri(message=reason)
        location_header = resp.getheader('location')
        if location_header:
            if resp.status not in (301, 302):
                reason = (_("The HTTP URL %(path)s attempted to redirect "
                            "with an invalid %(status)s status code.") % {
                                'path': loc.path,
                                'status': resp.status
                            })
                LOG.info(reason)
                raise exception.BadStoreUri(message=reason)
            location_class = glance.store.location.Location
            new_loc = location_class(location.store_name,
                                     location.store_location.__class__,
                                     uri=location_header,
                                     image_id=location.image_id,
                                     store_specs=location.store_specs)
            return self._query(new_loc, method, depth + 1)
        content_length = int(resp.getheader('content-length', 0))

        return (conn, resp, content_length)
コード例 #2
0
ファイル: metadef_properties.py プロジェクト: crowdy/glance
    def show(self, req, namespace, property_name, filters=None):
        ns_repo = self.gateway.get_metadef_namespace_repo(
            req.context, authorization_layer=False)
        try:
            namespace_obj = ns_repo.get(namespace)
        except (exception.Forbidden, exception.NotFound):
            # NOTE (abhishekk): Returning 404 Not Found as the
            # namespace is outside of this user's project
            msg = _("Namespace %s not found") % namespace
            raise webob.exc.HTTPNotFound(explanation=msg)

        try:
            # NOTE(abhishekk): Metadef properties are associated with
            # namespace, so made provision to pass namespace here
            # for visibility check
            api_pol = api_policy.MetadefAPIPolicy(req.context,
                                                  md_resource=namespace_obj,
                                                  enforcer=self.policy)
            api_pol.get_metadef_property()

            if filters and filters['resource_type']:
                # Verify that you can fetch resource type details
                api_pol.get_metadef_resource_type()

                rs_repo = self.gateway.get_metadef_resource_type_repo(
                    req.context, authorization_layer=False)
                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, authorization_layer=False)
            db_property = prop_repo.get(namespace, property_name)
            property = self._to_model(db_property)
        except exception.Forbidden as e:
            LOG.debug(
                "User not permitted to show metadata property '%s' "
                "within '%s' namespace", property_name, namespace)
            raise webob.exc.HTTPForbidden(explanation=e.msg)
        except exception.NotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.msg)
        return property
コード例 #3
0
 def test_execute_drop_lock_fails(self, mock_get_task):
     mock_get_task.return_value = self.task
     self.wrapper.drop_lock_for_task.side_effect = exception.NotFound()
     complete = import_flow._CompleteTask(TASK_ID1, TASK_TYPE,
                                          self.task_repo, self.wrapper)
     with mock.patch('glance.async_.flows.api_image_import.LOG') as m_log:
         complete.execute()
         m_log.error.assert_called_once_with('Image %(image)s import task '
                                             '%(task)s did not hold the '
                                             'lock upon completion!',
                                             {'image': IMAGE_ID1,
                                              'task': TASK_ID1})
     self.task.succeed.assert_called_once_with({'image_id': IMAGE_ID1})
コード例 #4
0
    def download(self, req, image_id):
        image_repo = self.gateway.get_repo(req.context)
        try:
            image = image_repo.get(image_id)
            if not image.locations:
                reason = _("No image data could be found")
                raise exception.NotFound(reason)
        except exception.NotFound as e:
            raise webob.exc.HTTPNotFound(explanation=unicode(e))
        except exception.Forbidden as e:
            raise webob.exc.HTTPForbidden(explanation=unicode(e))

        return image
コード例 #5
0
 def save(self, image):
     image_values = self._format_image_to_db(image)
     try:
         new_values = self.db_api.image_update(self.context,
                                               image.image_id,
                                               image_values,
                                               purge_props=True)
     except (exception.NotFound, exception.Forbidden):
         msg = _("No image found with ID %s") % image.image_id
         raise exception.NotFound(msg)
     self.db_api.image_tag_set_all(self.context, image.image_id,
                                   image.tags)
     image.updated_at = new_values['updated_at']
コード例 #6
0
ファイル: cache.py プロジェクト: zhangheng1442/openstack
    def _verify_metadata(self, image_meta):
        """
        Sanity check the 'deleted' and 'size' metadata values.
        """
        # NOTE: admins can see image metadata in the v1 API, but shouldn't
        # be able to download the actual image data.
        if image_meta['deleted']:
            raise exception.NotFound()

        if not image_meta['size']:
            # override image size metadata with the actual cached
            # file size, see LP Bug #900959
            image_meta['size'] = self.cache.get_image_size(image_id)
コード例 #7
0
    def image_update(self, context, image_id, image_values):
        LOG.info('Updating image %s with values %s' %
                 (image_id, str(image_values)))
        try:
            image = self.images[image_id]
            LOG.info('Found image %s: %s' % (image_id, str(image)))
        except KeyError:
            raise exception.NotFound(image_id=image_id)

        image.update(image_values)
        self.images[image_id] = image
        LOG.info('Image %s updated to %s' % (image_id, str(image)))
        return image
コード例 #8
0
ファイル: __init__.py プロジェクト: phani01/glance
 def get(self, namespace, property_name):
     try:
         namespace_entity = self.meta_namespace_repo.get(namespace)
         db_property_type = self.db_api.metadef_property_get(
             self.context,
             namespace,
             property_name
         )
     except (exception.NotFound, exception.Forbidden):
         msg = _('Could not find property %s') % property_name
         raise exception.NotFound(msg)
     return self._format_metadef_property_from_db(
         db_property_type, namespace_entity)
コード例 #9
0
def image_tag_delete(context, image_id, value, session=None):
    """Delete an image tag."""
    session = session or get_session()
    query = session.query(models.ImageTag)\
                   .filter_by(image_id=image_id)\
                   .filter_by(value=value)\
                   .filter_by(deleted=False)
    try:
        tag_ref = query.one()
    except sa_orm.exc.NoResultFound:
        raise exception.NotFound()

    tag_ref.delete(session=session)
コード例 #10
0
 def remove(self, image):
     image_values = self._format_image_to_db(image)
     try:
         self.db_api.image_update(self.context,
                                  image.image_id,
                                  image_values,
                                  purge_props=True)
     except (exception.NotFound, exception.Forbidden):
         msg = _("No image found with ID %s") % image.image_id
         raise exception.NotFound(msg)
     # NOTE(markwash): don't update tags?
     new_values = self.db_api.image_destroy(self.context, image.image_id)
     image.updated_at = new_values['updated_at']
コード例 #11
0
ファイル: gridfs.py プロジェクト: pipul/glance
    def _get_file(self, location):
        store_location = location
        if isinstance(location, glance.store.location.Location):
            store_location = location.store_location
        try:

            parsed = urlparse.urlparse(store_location.get_uri())
            return self.fs.get(parsed.netloc)
        except gridfs.errors.NoFile:
            msg = _("Could not find %s image in GridFS") % \
                store_location.get_uri()
            LOG.debug(msg)
            raise exception.NotFound(msg)
コード例 #12
0
    def update(self, req, metadata_object, namespace, object_name):
        meta_repo = self.gateway.get_metadef_object_repo(
            req.context, authorization_layer=False)
        try:
            ns_repo = self.gateway.get_metadef_namespace_repo(
                req.context, authorization_layer=False)
            try:
                # NOTE(abhishekk): Verifying that namespace is visible
                # to user
                namespace_obj = ns_repo.get(namespace)
            except exception.Forbidden:
                # NOTE (abhishekk): Returning 404 Not Found as the
                # namespace is outside of this user's project
                msg = _("Namespace %s not found") % namespace
                raise exception.NotFound(msg)

            # NOTE(abhishekk): Metadef object is created for Metadef namespaces
            # Here we are just checking if user is authorized to modify metadef
            # object or not.
            api_policy.MetadefAPIPolicy(
                req.context, md_resource=namespace_obj,
                enforcer=self.policy).modify_metadef_object()

            metadef_object = meta_repo.get(namespace, object_name)
            metadef_object._old_name = metadef_object.name
            metadef_object.name = wsme_utils._get_value(metadata_object.name)
            metadef_object.description = wsme_utils._get_value(
                metadata_object.description)
            metadef_object.required = wsme_utils._get_value(
                metadata_object.required)
            metadef_object.properties = wsme_utils._get_value(
                metadata_object.properties)
            updated_metadata_obj = meta_repo.save(metadef_object)
        except exception.Invalid as e:
            msg = (_("Couldn't update metadata object: %s") %
                   encodeutils.exception_to_unicode(e))
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.Forbidden as e:
            LOG.debug(
                "User not permitted to update metadata object '%s' "
                "within '%s' namespace ", object_name, 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)
        return MetadefObject.to_wsme_model(
            updated_metadata_obj,
            get_object_href(namespace, updated_metadata_obj),
            self.obj_schema_link)
コード例 #13
0
ファイル: api.py プロジェクト: young8/openstack-bill
def image_member_find(context, image_id, member, session=None):
    """Find a membership association between image and member."""
    session = session or get_session()
    try:
        # Note lack of permissions check; this function is called from
        # RequestContext.is_image_visible(), so avoid recursive calls
        return session.query(models.ImageMember).\
                        options(joinedload(models.ImageMember.image)).\
                        filter_by(image_id=image_id).\
                        filter_by(member=member).\
                        one()
    except exc.NoResultFound:
        raise exception.NotFound("No membership found for image %s member %s" %
                                 (image_id, member))
コード例 #14
0
 def test_revert_drops_lock_missing(self, mock_log):
     wrapper = import_flow.ImportActionWrapper(self.img_repo, IMAGE_ID1,
                                               TASK_ID1)
     imagelock = import_flow._ImageLock(TASK_ID1, TASK_TYPE, wrapper)
     with mock.patch.object(wrapper, 'drop_lock_for_task') as mock_drop:
         mock_drop.side_effect = exception.NotFound()
         imagelock.revert(None)
     mock_log.warning.assert_called_once_with(
         'Image %(image)s import task '
         '%(task)s lost its lock '
         'during execution!', {
             'image': IMAGE_ID1,
             'task': TASK_ID1
         })
コード例 #15
0
    def execute(self):
        """Create temp file into store and return path to it

        :param image_id: Glance Image ID
        """
        image = self.image_repo.get(self.image_id)
        # NOTE (abhishekk): If ``all_stores_must_succeed`` is set to True
        # and copying task fails then we keep data in staging area as it
        # is so that if second call is made to copy the same image then
        # no need to copy the data in staging area again.
        file_path = "%s/%s" % (getattr(
            CONF,
            'os_glance_staging_store').filesystem_store_datadir, self.image_id)

        if os.path.exists(file_path):
            return file_path, 0

        # At first search image in default_backend
        default_store = CONF.glance_store.default_backend
        for loc in image.locations:
            if loc['metadata'].get('store') == default_store:
                try:
                    return self._copy_to_staging_store(loc)
                except store_api.exceptions.NotFound:
                    msg = (_LE("Image not present in default store, searching "
                               "in all glance-api specific available "
                               "stores"))
                    LOG.error(msg)
                    break

        available_backends = CONF.enabled_backends
        for loc in image.locations:
            image_backend = loc['metadata'].get('store')
            if (image_backend in available_backends.keys()
                    and image_backend != default_store):
                try:
                    return self._copy_to_staging_store(loc)
                except store_api.exceptions.NotFound:
                    LOG.error(
                        _LE('Image: %(img_id)s is not present in store '
                            '%(store)s.'), {
                                'img_id': self.image_id,
                                'store': image_backend
                            })
                    continue

        raise exception.NotFound(
            _("Image not found in any configured "
              "store"))
コード例 #16
0
ファイル: s3.py プロジェクト: young8/openstack-bill
def get_key(bucket, obj):
    """
    Get a key from a bucket

    :param bucket: The ``boto.s3.Bucket``
    :param obj: Object to get the key for
    :raises ``glance.exception.NotFound`` if key is not found.
    """

    key = bucket.get_key(obj)
    if not key or not key.exists():
        msg = _("Could not find key %(obj)s in bucket %(bucket)s") % locals()
        logger.error(msg)
        raise exception.NotFound(msg)
    return key
コード例 #17
0
 def save(self, image, from_state=None):
     image_values = self._format_image_to_db(image)
     if image_values['size'] > CONF.image_size_cap:
         raise exception.ImageSizeLimitExceeded
     try:
         new_values = self.db_api.image_update(self.context,
                                               image.image_id,
                                               image_values,
                                               purge_props=True,
                                               from_state=from_state)
     except (exception.NotFound, exception.Forbidden):
         msg = _("No image found with ID %s") % image.image_id
         raise exception.NotFound(msg)
     self.db_api.image_tag_set_all(self.context, image.image_id, image.tags)
     image.updated_at = new_values['updated_at']
コード例 #18
0
ファイル: s3.py プロジェクト: wputra/MOS-centos
def get_key(bucket, obj):
    """
    Get a key from a bucket

    :param bucket: The ``boto.s3.Bucket``
    :param obj: Object to get the key for
    :raises ``glance.exception.NotFound`` if key is not found.
    """

    key = bucket.get_key(obj)
    if not key or not key.exists():
        msg = (_("Could not find key %(obj)s in bucket %(bucket)s") %
               {'obj': obj, 'bucket': bucket})
        LOG.debug(msg)
        raise exception.NotFound(msg)
    return key
コード例 #19
0
ファイル: swift.py プロジェクト: zhangheng1442/openstack
    def get(self, location, connection=None):
        location = location.store_location
        if not connection:
            connection = self.get_connection(location)

        try:
            resp_headers, resp_body = connection.get_object(
                    container=location.container, obj=location.obj,
                    resp_chunk_size=self.CHUNKSIZE)
        except swiftclient.ClientException, e:
            if e.http_status == httplib.NOT_FOUND:
                uri = location.get_uri()
                msg = _("Swift could not find image at URI.")
                raise exception.NotFound(msg)
            else:
                raise
コード例 #20
0
ファイル: s3.py プロジェクト: young8/openstack-bill
def get_bucket(conn, bucket_id):
    """
    Get a bucket from an s3 connection

    :param conn: The ``boto.s3.connection.S3Connection``
    :param bucket_id: ID of the bucket to fetch
    :raises ``glance.exception.NotFound`` if bucket is not found.
    """

    bucket = conn.get_bucket(bucket_id)
    if not bucket:
        msg = _("Could not find bucket with ID %(bucket_id)s") % locals()
        logger.error(msg)
        raise exception.NotFound(msg)

    return bucket
コード例 #21
0
ファイル: api.py プロジェクト: young8/openstack-bill
def image_member_get(context, member_id, session=None):
    """Get an image member or raise if it does not exist."""
    session = session or get_session()
    try:
        member = session.query(models.ImageMember).\
                        options(joinedload(models.ImageMember.image)).\
                        filter_by(deleted=_deleted(context)).\
                        filter_by(id=member_id).\
                        one()
    except exc.NoResultFound:
        raise exception.NotFound("No membership found with ID %s" % member_id)

    # Make sure they can look at it
    if not context.is_image_visible(member.image):
        raise exception.NotAuthorized("Image not visible to you")

    return member
コード例 #22
0
ファイル: sheepdog.py プロジェクト: pipul/glance
    def get_size(self, location):
        """
        Takes a `glance.store.location.Location` object that indicates
        where to find the image file and returns the image size

        :param location `glance.store.location.Location` object, supplied
                        from glance.store.location.get_location_from_uri()
        :raises `glance.exception.NotFound` if image does not exist
        :rtype int
        """

        loc = location.store_location
        image = SheepdogImage(self.addr, self.port, loc.image, self.chunk_size)
        if not image.exist():
            raise exception.NotFound(
                _("Sheepdog image %s does not exist") % image.name)
        return image.get_size()
コード例 #23
0
ファイル: sheepdog.py プロジェクト: pipul/glance
    def delete(self, location):
        """
        Takes a `glance.store.location.Location` object that indicates
        where to find the image file to delete

        :location `glance.store.location.Location` object, supplied
                  from glance.store.location.get_location_from_uri()

        :raises NotFound if image does not exist
        """

        loc = location.store_location
        image = SheepdogImage(self.addr, self.port, loc.image, self.chunk_size)
        if not image.exist():
            raise exception.NotFound(
                _("Sheepdog image %s does not exist") % loc.image)
        image.delete()
コード例 #24
0
    def create(self, req, metadata_object, namespace):
        object_factory = self.gateway.get_metadef_object_factory(
            req.context, authorization_layer=False)
        object_repo = self.gateway.get_metadef_object_repo(
            req.context, authorization_layer=False)
        try:
            ns_repo = self.gateway.get_metadef_namespace_repo(
                req.context, authorization_layer=False)
            try:
                # NOTE(abhishekk): Verifying that namespace is visible
                # to user
                namespace_obj = ns_repo.get(namespace)
            except exception.Forbidden:
                # NOTE (abhishekk): Returning 404 Not Found as the
                # namespace is outside of this user's project
                msg = _("Namespace %s not found") % namespace
                raise exception.NotFound(msg)

            # NOTE(abhishekk): Metadef object is created for Metadef namespaces
            # Here we are just checking if user is authorized to create metadef
            # object or not.
            api_policy.MetadefAPIPolicy(
                req.context, md_resource=namespace_obj,
                enforcer=self.policy).add_metadef_object()

            new_meta_object = object_factory.new_object(
                namespace=namespace, **metadata_object.to_dict())
            object_repo.add(new_meta_object)

        except exception.Forbidden as e:
            LOG.debug(
                "User not permitted to create metadata object within "
                "'%s' namespace", namespace)
            raise webob.exc.HTTPForbidden(explanation=e.msg)
        except exception.Invalid as e:
            msg = (_("Couldn't create metadata object: %s") %
                   encodeutils.exception_to_unicode(e))
            raise webob.exc.HTTPBadRequest(explanation=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)
        return MetadefObject.to_wsme_model(
            new_meta_object, get_object_href(namespace, new_meta_object),
            self.obj_schema_link)
コード例 #25
0
    def delete(self, req, namespace, resource_type):
        rs_type_repo = self.gateway.get_metadef_resource_type_repo(
            req.context, authorization_layer=False)
        ns_repo = self.gateway.get_metadef_namespace_repo(
            req.context, authorization_layer=False)
        try:
            namespace_obj = ns_repo.get(namespace)
        except (exception.Forbidden, exception.NotFound):
            # NOTE (abhishekk): Returning 404 Not Found as the
            # namespace is outside of this user's project
            msg = _("Namespace %s not found") % namespace
            raise webob.exc.HTTPNotFound(explanation=msg)

        try:
            # NOTE(abhishekk): Metadef resource type is created for Metadef
            # namespaces. Here we are just checking if user is authorized
            # to delete metadef resource types or not.
            api_policy.MetadefAPIPolicy(
                req.context, md_resource=namespace_obj,
                enforcer=self.policy).remove_metadef_resource_type_association(
                )

            filters = {}
            found = False
            filters['namespace'] = namespace
            db_resource_type_list = rs_type_repo.list(filters=filters)
            for db_resource_type in db_resource_type_list:
                if db_resource_type.name == resource_type:
                    db_resource_type.delete()
                    rs_type_repo.remove(db_resource_type)
                    found = True
            if not found:
                raise exception.NotFound()
        except exception.Forbidden as e:
            LOG.debug(
                "User not permitted to delete metadata resource type "
                "'%s' within '%s' namespace", resource_type, namespace)
            raise webob.exc.HTTPForbidden(explanation=e.msg)
        except exception.NotFound:
            msg = (_("Failed to find resource type %(resourcetype)s to "
                     "delete") % {
                         'resourcetype': resource_type
                     })
            LOG.error(msg)
            raise webob.exc.HTTPNotFound(explanation=msg)
コード例 #26
0
ファイル: filesystem.py プロジェクト: OpenStack-Kha/glance
    def get(self, location):
        """
        Takes a `glance.store.location.Location` object that indicates
        where to find the image file, and returns a tuple of generator
        (for reading the image file) and image_size

        :param location `glance.store.location.Location` object, supplied
                        from glance.store.location.get_location_from_uri()
        :raises `glance.exception.NotFound` if image does not exist
        """
        loc = location.store_location
        filepath = loc.path
        if not os.path.exists(filepath):
            raise exception.NotFound(_("Image file %s not found") % filepath)
        else:
            msg = _("Found image at %s. Returning in ChunkedFile.") % filepath
            logger.debug(msg)
            return (ChunkedFile(filepath), None)
コード例 #27
0
    def get(self, location):
        """
        Takes a `glance.store.location.Location` object that indicates
        where to find the image file, and returns a generator for reading
        the image file

        :param location `glance.store.location.Location` object, supplied
                        from glance.store.location.get_location_from_uri()
        :raises `glance.exception.NotFound` if image does not exist
        """

        loc = location.store_location
        image = SheepdogImage(self.addr, self.port, loc.image,
                              self.READ_CHUNKSIZE)
        if not image.exist():
            raise exception.NotFound(
                _("Sheepdog image %s does not exist") % image.name)
        return (ImageIterator(image), image.get_size())
コード例 #28
0
def image_update(context, image_id, image_values):
    global DATA
    try:
        image = DATA['images'][image_id]
    except KeyError:
        raise exception.NotFound(image_id=image_id)

    properties = image_values.pop('properties', {})
    properties = [{
        'name': k,
        'value': v,
        'deleted': False
    } for k, v in properties.items()]
    image['properties'] = properties
    image['updated_at'] = timeutils.utcnow()
    image.update(image_values)
    DATA['images'][image_id] = image
    return image
コード例 #29
0
def _do_pagination(context, images, marker, limit, show_deleted):
    start = 0
    end = -1
    if marker is None:
        start = 0
    else:
        # Check that the image is accessible
        image_get(context, marker, force_show_deleted=show_deleted)

        for i, image in enumerate(images):
            if image['id'] == marker:
                start = i + 1
                break
        else:
            raise exception.NotFound()

    end = start + limit if limit is not None else None
    return images[start:end]
コード例 #30
0
ファイル: rbd.py プロジェクト: carrierstack/glance
 def __iter__(self):
     try:
         with rados.Rados(conffile=self.conf_file,
                          rados_id=self.user) as conn:
             with conn.open_ioctx(self.pool) as ioctx:
                 with rbd.Image(ioctx, self.name) as image:
                     img_info = image.stat()
                     size = img_info['size']
                     bytes_left = size
                     while bytes_left > 0:
                         length = min(self.chunk_size, bytes_left)
                         data = image.read(size - bytes_left, length)
                         bytes_left -= len(data)
                         yield data
                     raise StopIteration()
     except rbd.ImageNotFound:
         raise exception.NotFound(
             _('RBD image %s does not exist') % self.name)