if ret != 0:
raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
+def requires_not_closed(f):
+ def wrapper(self, *args, **kwargs):
+ self.require_not_closed()
+ return f(self, *args, **kwargs)
+
+ return wrapper
+
cdef class Image(object):
"""
This class represents an RBD image. It is used to perform I/O on
completion_obj.rbd_comp = completion
return completion_obj
+ def require_not_closed(self):
+ """
+ Checks if the Image is not closed
+
+ :raises: :class:`InvalidArgument`
+ """
+ if self.closed:
+ raise InvalidArgument("image is closed")
+
def close(self):
"""
Release the resources used by this image object.
def __repr__(self):
return "rbd.Image(ioctx, %r)" % self.name
+ @requires_not_closed
def resize(self, size, allow_shrink=True):
"""
Change the size of the image, allow shrink.
if ret < 0:
raise make_ex(ret, 'error resizing image %s' % self.name)
+ @requires_not_closed
def stat(self):
"""
Get information about the image. Currently parent pool and
'parent_name' : info.parent_name
}
+ @requires_not_closed
def get_name(self):
"""
Get the RBD image name
finally:
free(image_name)
+ @requires_not_closed
def id(self):
"""
Get the RBD v2 internal image id
finally:
free(image_id)
+ @requires_not_closed
def block_name_prefix(self):
"""
Get the RBD block name prefix
finally:
free(prefix)
+ @requires_not_closed
def data_pool_id(self):
"""
Get the pool id of the pool where the data of this RBD image is stored.
"""
return rbd_get_data_pool_id(self.image)
+ @requires_not_closed
def get_parent_image_spec(self):
"""
Get spec of the cloned image's parent
rbd_snap_spec_cleanup(&snap_spec)
return result
+ @requires_not_closed
def parent_info(self):
"""
Deprecated. Use `get_parent_image_spec` instead.
parent = self.get_parent_image_spec()
return (parent['pool_name'], parent['image_name'], parent['snap_name'])
+ @requires_not_closed
def parent_id(self):
"""
Get image id of a cloned image's parent (if any)
rbd_snap_spec_cleanup(&snap_spec)
return result
+ @requires_not_closed
def old_format(self):
"""
Find out whether the image uses the old RBD format.
raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
return old != 0
+ @requires_not_closed
def size(self):
"""
Get the size of the image. If open to a snapshot, returns the
raise make_ex(ret, 'error getting size for image %s' % (self.name))
return image_size
+ @requires_not_closed
def features(self):
"""
Get the features bitmask of the image.
raise make_ex(ret, 'error getting features for image %s' % (self.name))
return features
+ @requires_not_closed
def update_features(self, features, enabled):
"""
Update the features bitmask of the image by enabling/disabling
raise make_ex(ret, 'error updating features for image %s' %
(self.name))
+ @requires_not_closed
def op_features(self):
"""
Get the op features bitmask of the image.
raise make_ex(ret, 'error getting op features for image %s' % (self.name))
return op_features
+ @requires_not_closed
def overlap(self):
"""
Get the number of overlapping bytes between the image and its parent
raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
return overlap
+ @requires_not_closed
def flags(self):
"""
Get the flags bitmask of the image.
raise make_ex(ret, 'error getting flags for image %s' % (self.name))
return flags
+ @requires_not_closed
def group(self):
"""
Get information about the image's group.
rbd_group_info_cleanup(&info, sizeof(info))
return result
+ @requires_not_closed
def is_exclusive_lock_owner(self):
"""
Get the status of the image exclusive lock.
raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
return owner == 1
+ @requires_not_closed
def copy(self, dest_ioctx, dest_name, features=None, order=None,
stripe_unit=None, stripe_count=None, data_pool=None):
"""
if ret < 0:
raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
+ @requires_not_closed
def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
stripe_unit=None, stripe_count=None, data_pool=None):
"""
if ret < 0:
raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
+ @requires_not_closed
def list_snaps(self):
"""
Iterate over the snapshots of an image.
"""
return SnapIterator(self)
+ @requires_not_closed
def create_snap(self, name):
"""
Create a snapshot of the image.
if ret != 0:
raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
+ @requires_not_closed
def rename_snap(self, srcname, dstname):
"""
rename a snapshot of the image.
if ret != 0:
raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
+ @requires_not_closed
def remove_snap(self, name):
"""
Delete a snapshot of the image.
if ret != 0:
raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
+ @requires_not_closed
def remove_snap2(self, name, flags):
"""
Delete a snapshot of the image.
:type name: str
:raises: :class:`IOError`, :class:`ImageBusy`
"""
+ self.require_not_closed()
+
name = cstr(name, 'name')
cdef:
char *_name = name
if ret != 0:
raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
+ @requires_not_closed
def remove_snap_by_id(self, snap_id):
"""
Delete a snapshot of the image by its id.
if ret != 0:
raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
+ @requires_not_closed
def rollback_to_snap(self, name):
"""
Revert the image to its contents at a snapshot. This is a
if ret != 0:
raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
+ @requires_not_closed
def protect_snap(self, name):
"""
Mark a snapshot as protected. This means it can't be deleted
if ret != 0:
raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
+ @requires_not_closed
def unprotect_snap(self, name):
"""
Mark a snapshot unprotected. This allows it to be deleted if
if ret != 0:
raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
+ @requires_not_closed
def is_protected_snap(self, name):
"""
Find out whether a snapshot is protected from deletion.
raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
return is_protected == 1
+ @requires_not_closed
def snap_exists(self, name):
"""
Find out whether a snapshot is exists.
raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
return bool(_exists != 0)
+ @requires_not_closed
def get_snap_limit(self):
"""
Get the snapshot limit for an image.
:returns: int - the snapshot limit for an image
"""
-
cdef:
uint64_t limit
with nogil:
raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
return limit
+ @requires_not_closed
def set_snap_limit(self, limit):
"""
Set the snapshot limit for an image.
:param limit: the new limit to set
"""
-
cdef:
uint64_t _limit = limit
with nogil:
raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
return ret
+ @requires_not_closed
def get_snap_timestamp(self, snap_id):
"""
Get the snapshot timestamp for an image.
raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
return datetime.utcfromtimestamp(timestamp.tv_sec)
+ @requires_not_closed
def remove_snap_limit(self):
"""
Remove the snapshot limit for an image, essentially setting
raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
return ret
+ @requires_not_closed
def set_snap(self, name):
"""
Set the snapshot to read from. Writes will raise ReadOnlyImage
if ret != 0:
raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
+ @requires_not_closed
def set_snap_by_id(self, snap_id):
"""
Set the snapshot to read from. Writes will raise ReadOnlyImage
if ret != 0:
raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
+ @requires_not_closed
def snap_get_name(self, snap_id):
"""
Get snapshot name by id.
finally:
free(image_name)
+ @requires_not_closed
def snap_get_id(self, snap_name):
"""
Get snapshot id by name.
:returns: int - snapshot id
:raises: :class:`ImageNotFound`
"""
-
snap_name = cstr(snap_name, 'snap_name')
cdef:
const char *_snap_name = snap_name
raise make_ex(ret, 'error snap_get_id.')
return snap_id
+ @requires_not_closed
def read(self, offset, length, fadvise_flags=0):
"""
Read data from the image. Raises :class:`InvalidArgument` if
# itself and set ret_s to NULL, hence XDECREF).
ref.Py_XDECREF(ret_s)
+ @requires_not_closed
def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
include_parent = True, whole_object = False):
"""
msg = 'error generating diff from snapshot %s' % from_snapshot
raise make_ex(ret, msg)
+ @requires_not_closed
def write(self, data, offset, fadvise_flags=0):
"""
Write data to the image. Raises :class:`InvalidArgument` if
returned %d, but %d was the maximum number of bytes it could have \
written." % (self.name, ret, length))
+ @requires_not_closed
def discard(self, offset, length):
"""
Trim the range from the image. It will be logically filled
msg = 'error discarding region %d~%d' % (offset, length)
raise make_ex(ret, msg)
+ @requires_not_closed
def flush(self):
"""
Block until all writes are fully flushed if caching is enabled.
if ret < 0:
raise make_ex(ret, 'error flushing image')
+ @requires_not_closed
def invalidate_cache(self):
"""
Drop any cached data for the image.
if ret < 0:
raise make_ex(ret, 'error invalidating cache')
+ @requires_not_closed
def stripe_unit(self):
"""
Return the stripe unit used for the image.
raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
return stripe_unit
+ @requires_not_closed
def stripe_count(self):
"""
Return the stripe count used for the image.
raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
return stripe_count
+ @requires_not_closed
def create_timestamp(self):
"""
Return the create timestamp for the image.
raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
return datetime.utcfromtimestamp(timestamp.tv_sec)
+ @requires_not_closed
def access_timestamp(self):
"""
Return the access timestamp for the image.
raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
return datetime.fromtimestamp(timestamp.tv_sec)
+ @requires_not_closed
def modify_timestamp(self):
"""
Return the modify timestamp for the image.
raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
return datetime.fromtimestamp(timestamp.tv_sec)
+ @requires_not_closed
def flatten(self, on_progress=None):
"""
Flatten clone image (copy all blocks from parent to child)
if ret < 0:
raise make_ex(ret, "error flattening %s" % self.name)
+ @requires_not_closed
def sparsify(self, sparse_size):
"""
Reclaim space for zeroed image extents
if ret < 0:
raise make_ex(ret, "error sparsifying %s" % self.name)
+ @requires_not_closed
def rebuild_object_map(self):
"""
Rebuild the object map for the image HEAD or currently set snapshot
if ret < 0:
raise make_ex(ret, "error rebuilding object map %s" % self.name)
+ @requires_not_closed
def list_children(self):
"""
List children of the currently set snapshot (set via set_snap()).
rbd_linked_image_spec_list_cleanup(children, num_children)
free(children)
+ @requires_not_closed
def list_children2(self):
"""
Iterate over the children of the image or its snapshot.
"""
return ChildIterator(self)
+ @requires_not_closed
def list_descendants(self):
"""
Iterate over the descendants of the image.
"""
return ChildIterator(self, True)
+ @requires_not_closed
def list_lockers(self):
"""
List clients that have locked the image and information
free(c_addrs)
free(c_tag)
+ @requires_not_closed
def lock_acquire(self, lock_mode):
"""
Acquire a managed lock on the image.
if ret < 0:
raise make_ex(ret, 'error acquiring lock on image')
+ @requires_not_closed
def lock_release(self):
"""
Release a managed lock on the image that was previously acquired.
if ret < 0:
raise make_ex(ret, 'error releasing lock on image')
+ @requires_not_closed
def lock_get_owners(self):
"""
Iterate over the lock owners of an image.
"""
return LockOwnerIterator(self)
+ @requires_not_closed
def lock_break(self, lock_mode, lock_owner):
"""
Break the image lock held by a another client.
if ret < 0:
raise make_ex(ret, 'error breaking lock on image')
+ @requires_not_closed
def lock_exclusive(self, cookie):
"""
Take an exclusive lock on the image.
if ret < 0:
raise make_ex(ret, 'error acquiring exclusive lock on image')
+ @requires_not_closed
def lock_shared(self, cookie, tag):
"""
Take a shared lock on the image. The tag must match
if ret < 0:
raise make_ex(ret, 'error acquiring shared lock on image')
+ @requires_not_closed
def unlock(self, cookie):
"""
Release a lock on the image that was locked by this rados client.
if ret < 0:
raise make_ex(ret, 'error unlocking image')
+ @requires_not_closed
def break_lock(self, client, cookie):
"""
Release a lock held by another rados client.
if ret < 0:
raise make_ex(ret, 'error unlocking image')
+ @requires_not_closed
def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
"""
Enable mirroring for the image.
if ret < 0:
raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
+ @requires_not_closed
def mirror_image_disable(self, force):
"""
Disable mirroring for the image.
if ret < 0:
raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
+ @requires_not_closed
def mirror_image_promote(self, force):
"""
Promote the image to primary for mirroring.
if ret < 0:
raise make_ex(ret, 'error promoting image %s to primary' % self.name)
+ @requires_not_closed
def mirror_image_demote(self):
"""
Demote the image to secondary for mirroring.
if ret < 0:
raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
+ @requires_not_closed
def mirror_image_resync(self):
"""
Flag the image to resync.
if ret < 0:
raise make_ex(ret, 'error to resync image %s' % self.name)
+ @requires_not_closed
def mirror_image_create_snapshot(self):
"""
Create mirror snapshot.
self.name)
return snap_id
+ @requires_not_closed
def mirror_image_get_info(self):
"""
Get mirror info for the image.
rbd_mirror_image_get_info_cleanup(&c_info)
return info
+ @requires_not_closed
def mirror_image_get_mode(self):
"""
Get mirror mode for the image.
raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
return int(c_mode)
+ @requires_not_closed
def mirror_image_get_status(self):
"""
Get mirror status for the image.
rbd_mirror_image_global_status_cleanup(&c_status)
return status
+ @requires_not_closed
def mirror_image_get_instance_id(self):
"""
Get mirror instance id for the image.
finally:
free(instance_id)
+ @requires_not_closed
def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
"""
Asynchronously read data from the image
:returns: :class:`Completion` - the completion object
:raises: :class:`InvalidArgument`, :class:`IOError`
"""
-
cdef:
char *ret_buf
uint64_t _offset = offset
return completion
+ @requires_not_closed
def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
"""
Asynchronously write data to the image
:returns: :class:`Completion` - the completion object
:raises: :class:`InvalidArgument`, :class:`IOError`
"""
-
cdef:
uint64_t _offset = offset
char *_data = data
return completion
+ @requires_not_closed
def aio_discard(self, offset, length, oncomplete):
"""
Asynchronously trim the range from the image. It will be logically
filled with zeroes.
"""
-
cdef:
uint64_t _offset = offset
size_t _length = length
return completion
+ @requires_not_closed
def aio_flush(self, oncomplete):
"""
Asynchronously wait until all writes are fully flushed if caching is
enabled.
"""
-
cdef Completion completion = self.__get_completion(oncomplete)
try:
completion.__persist()
return completion
+ @requires_not_closed
def metadata_get(self, key):
"""
Get image metadata for the given key.
finally:
free(value)
+ @requires_not_closed
def metadata_set(self, key, value):
"""
Set image metadata for the given key.
raise make_ex(ret, 'error setting metadata %s for image %s' %
(key, self.name))
-
+ @requires_not_closed
def metadata_remove(self, key):
"""
Remove image metadata for the given key.
raise make_ex(ret, 'error removing metadata %s for image %s' %
(key, self.name))
+ @requires_not_closed
def metadata_list(self):
"""
List image metadata.
"""
return MetadataIterator(self)
+ @requires_not_closed
def watchers_list(self):
"""
List image watchers.
"""
return WatcherIterator(self)
+ @requires_not_closed
def config_list(self):
"""
List image-level config overrides.
"""
return ConfigImageIterator(self)
-
+ @requires_not_closed
def config_set(self, key, value):
"""
Set an image-level configuration override.
raise make_ex(ret, 'error setting config %s for image %s' %
(key, self.name))
-
+ @requires_not_closed
def config_get(self, key):
"""
Get an image-level configuration override.
finally:
free(value)
-
+ @requires_not_closed
def config_remove(self, key):
"""
Remove an image-level configuration override.
raise make_ex(ret, 'error removing config %s for image %s' %
(key, self.name))
-
+ @requires_not_closed
def snap_get_namespace_type(self, snap_id):
"""
Get the snapshot namespace type.
return namespace_type
+ @requires_not_closed
def snap_get_group_namespace(self, snap_id):
"""
get the group namespace details.
sizeof(rbd_snap_group_namespace_t))
return info
+ @requires_not_closed
def snap_get_trash_namespace(self, snap_id):
"""
get the trash namespace details.
finally:
free(_name)
+ @requires_not_closed
def snap_get_mirror_namespace(self, snap_id):
"""
get the mirror namespace details.
object image
def __init__(self, Image image):
+ image.require_not_closed()
+
self.image = image
self.lock_owners = NULL
self.num_lock_owners = 8
&self.num_lock_owners)
if ret >= 0:
break
+ elif ret == -errno.ENOENT:
+ self.num_lock_owners = 0
+ break
elif ret != -errno.ERANGE:
raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
"""
cdef:
- object image_name
- rbd_image_t image
+ cdef object image
+ rbd_image_t c_image
char *last_read
uint64_t max_read
object next_chunk
def __init__(self, Image image):
- self.image_name = image.name
- self.image = image.image
+ image.require_not_closed()
+
+ self.image = image
+ self.c_image = image.image
self.last_read = strdup("")
self.max_read = 32
self.get_next_chunk()
free(self.last_read)
def get_next_chunk(self):
+ self.image.require_not_closed()
+
cdef:
char *c_keys = NULL
size_t keys_size = 4096
c_keys = <char *>realloc_chk(c_keys, keys_size)
c_vals = <char *>realloc_chk(c_vals, vals_size)
with nogil:
- ret = rbd_metadata_list(self.image, self.last_read,
+ ret = rbd_metadata_list(self.c_image, self.last_read,
self.max_read, c_keys, &keys_size,
c_vals, &vals_size)
if ret >= 0:
break
elif ret != -errno.ERANGE:
raise make_ex(ret, 'error listing metadata for image %s' %
- self.image_name)
+ self.image.name)
keys = [decode_cstr(key) for key in
c_keys[:keys_size].split(b'\0') if key]
vals = [decode_cstr(val) for val in
cdef object image
def __init__(self, Image image):
+ image.require_not_closed()
+
self.image = image
self.snaps = NULL
self.num_snaps = 10
cdef object image
def __init__(self, Image image, descendants=False):
+ image.require_not_closed()
+
self.image = image
self.children = NULL
self.num_children = 10
cdef object image
def __init__(self, Image image):
+ image.require_not_closed()
+
self.image = image
self.watchers = NULL
self.num_watchers = 10
int num_options
def __init__(self, Image image):
+ image.require_not_closed()
+
self.options = NULL
self.num_options = 32
while True: