1 # cython: embedsignature=True
3 This module is a thin wrapper around librbd.
5 It currently provides all the synchronous methods of librbd that do
8 Error codes from librbd are turned into exceptions that subclass
9 :class:`Error`. Almost all methods may raise :class:`Error`
10 (the base class of all rbd exceptions), :class:`PermissionError`
11 and :class:`IOError`, in addition to those documented for the
14 # Copyright 2011 Josh Durgin
15 # Copyright 2015 Hector Martin <marcan@marcan.st>
20 from cpython cimport PyObject, ref, exc
21 from libc cimport errno
22 from libc.stdint cimport *
23 from libc.stdlib cimport realloc, free
24 from libc.string cimport strdup
26 from collections import Iterable
27 from datetime import datetime
32 cdef extern from "Python.h":
33 # These are in cpython/string.pxd, but use "object" types instead of
34 # PyObject*, which invokes assumptions in cpython that we need to
35 # legitimately break to implement zero-copy string buffers in Image.read().
36 # This is valid use of the Python API and documented as a special case.
37 PyObject *PyBytes_FromStringAndSize(char *v, Py_ssize_t len) except NULL
38 char* PyBytes_AsString(PyObject *string) except NULL
39 int _PyBytes_Resize(PyObject **string, Py_ssize_t newsize) except -1
41 cdef extern from "time.h":
42 ctypedef long int time_t
47 cdef extern from "limits.h":
48 cdef uint64_t INT64_MAX
50 cdef extern from "rbd/librbd.h" nogil:
52 _RBD_FEATURE_LAYERING "RBD_FEATURE_LAYERING"
53 _RBD_FEATURE_STRIPINGV2 "RBD_FEATURE_STRIPINGV2"
54 _RBD_FEATURE_EXCLUSIVE_LOCK "RBD_FEATURE_EXCLUSIVE_LOCK"
55 _RBD_FEATURE_OBJECT_MAP "RBD_FEATURE_OBJECT_MAP"
56 _RBD_FEATURE_FAST_DIFF "RBD_FEATURE_FAST_DIFF"
57 _RBD_FEATURE_DEEP_FLATTEN "RBD_FEATURE_DEEP_FLATTEN"
58 _RBD_FEATURE_JOURNALING "RBD_FEATURE_JOURNALING"
59 _RBD_FEATURE_DATA_POOL "RBD_FEATURE_DATA_POOL"
61 _RBD_FEATURES_INCOMPATIBLE "RBD_FEATURES_INCOMPATIBLE"
62 _RBD_FEATURES_RW_INCOMPATIBLE "RBD_FEATURES_RW_INCOMPATIBLE"
63 _RBD_FEATURES_MUTABLE "RBD_FEATURES_MUTABLE"
64 _RBD_FEATURES_SINGLE_CLIENT "RBD_FEATURES_SINGLE_CLIENT"
65 _RBD_FEATURES_ALL "RBD_FEATURES_ALL"
67 _RBD_FLAG_OBJECT_MAP_INVALID "RBD_FLAG_OBJECT_MAP_INVALID"
68 _RBD_FLAG_FAST_DIFF_INVALID "RBD_FLAG_FAST_DIFF_INVALID"
70 _RBD_IMAGE_OPTION_FORMAT "RBD_IMAGE_OPTION_FORMAT"
71 _RBD_IMAGE_OPTION_FEATURES "RBD_IMAGE_OPTION_FEATURES"
72 _RBD_IMAGE_OPTION_ORDER "RBD_IMAGE_OPTION_ORDER"
73 _RBD_IMAGE_OPTION_STRIPE_UNIT "RBD_IMAGE_OPTION_STRIPE_UNIT"
74 _RBD_IMAGE_OPTION_STRIPE_COUNT "RBD_IMAGE_OPTION_STRIPE_COUNT"
75 _RBD_IMAGE_OPTION_DATA_POOL "RBD_IMAGE_OPTION_DATA_POOL"
77 RBD_MAX_BLOCK_NAME_SIZE
78 RBD_MAX_IMAGE_NAME_SIZE
80 ctypedef void* rados_ioctx_t
81 ctypedef void* rbd_image_t
82 ctypedef void* rbd_image_options_t
83 ctypedef void *rbd_completion_t
85 ctypedef struct rbd_image_info_t:
90 char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]
92 char parent_name[RBD_MAX_IMAGE_NAME_SIZE]
94 ctypedef struct rbd_snap_info_t:
99 ctypedef enum rbd_mirror_mode_t:
100 _RBD_MIRROR_MODE_DISABLED "RBD_MIRROR_MODE_DISABLED"
101 _RBD_MIRROR_MODE_IMAGE "RBD_MIRROR_MODE_IMAGE"
102 _RBD_MIRROR_MODE_POOL "RBD_MIRROR_MODE_POOL"
104 ctypedef struct rbd_mirror_peer_t:
109 ctypedef enum rbd_mirror_image_state_t:
110 _RBD_MIRROR_IMAGE_DISABLING "RBD_MIRROR_IMAGE_DISABLING"
111 _RBD_MIRROR_IMAGE_ENABLED "RBD_MIRROR_IMAGE_ENABLED"
112 _RBD_MIRROR_IMAGE_DISABLED "RBD_MIRROR_IMAGE_DISABLED"
114 ctypedef struct rbd_mirror_image_info_t:
116 rbd_mirror_image_state_t state
119 ctypedef enum rbd_mirror_image_status_state_t:
120 _MIRROR_IMAGE_STATUS_STATE_UNKNOWN "MIRROR_IMAGE_STATUS_STATE_UNKNOWN"
121 _MIRROR_IMAGE_STATUS_STATE_ERROR "MIRROR_IMAGE_STATUS_STATE_ERROR"
122 _MIRROR_IMAGE_STATUS_STATE_SYNCING "MIRROR_IMAGE_STATUS_STATE_SYNCING"
123 _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY"
124 _MIRROR_IMAGE_STATUS_STATE_REPLAYING "MIRROR_IMAGE_STATUS_STATE_REPLAYING"
125 _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY"
126 _MIRROR_IMAGE_STATUS_STATE_STOPPED "MIRROR_IMAGE_STATUS_STATE_STOPPED"
128 ctypedef struct rbd_mirror_image_status_t:
130 rbd_mirror_image_info_t info
131 rbd_mirror_image_status_state_t state
136 ctypedef enum rbd_lock_mode_t:
137 _RBD_LOCK_MODE_EXCLUSIVE "RBD_LOCK_MODE_EXCLUSIVE"
138 _RBD_LOCK_MODE_SHARED "RBD_LOCK_MODE_SHARED"
140 ctypedef enum rbd_trash_image_source_t:
141 _RBD_TRASH_IMAGE_SOURCE_USER "RBD_TRASH_IMAGE_SOURCE_USER",
142 _RBD_TRASH_IMAGE_SOURCE_MIRRORING "RBD_TRASH_IMAGE_SOURCE_MIRRORING"
144 ctypedef struct rbd_trash_image_info_t:
147 rbd_trash_image_source_t source
149 time_t deferment_end_time
151 ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
152 ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
154 void rbd_version(int *major, int *minor, int *extra)
156 void rbd_image_options_create(rbd_image_options_t* opts)
157 void rbd_image_options_destroy(rbd_image_options_t opts)
158 int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
160 int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
162 int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
163 char* optval, size_t maxlen)
164 int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
166 int rbd_image_options_unset(rbd_image_options_t opts, int optname)
167 void rbd_image_options_clear(rbd_image_options_t opts)
168 int rbd_image_options_is_empty(rbd_image_options_t opts)
170 int rbd_list(rados_ioctx_t io, char *names, size_t *size)
171 int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
173 int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
174 rbd_image_options_t opts)
175 int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
176 const char *p_snapname, rados_ioctx_t c_ioctx,
177 const char *c_name, rbd_image_options_t c_opts)
178 int rbd_remove(rados_ioctx_t io, const char *name)
179 int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
180 const char *destname)
182 int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay)
183 int rbd_trash_get(rados_ioctx_t io, const char *id,
184 rbd_trash_image_info_t *info)
185 void rbd_trash_get_cleanup(rbd_trash_image_info_t *info)
186 int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries,
188 void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
190 int rbd_trash_remove(rados_ioctx_t io, const char *id, int force)
191 int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
193 int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
194 int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
195 int rbd_mirror_peer_add(rados_ioctx_t io, char *uuid,
196 size_t uuid_max_length, const char *cluster_name,
197 const char *client_name)
198 int rbd_mirror_peer_remove(rados_ioctx_t io, const char *uuid)
199 int rbd_mirror_peer_list(rados_ioctx_t io_ctx, rbd_mirror_peer_t *peers,
201 void rbd_mirror_peer_list_cleanup(rbd_mirror_peer_t *peers, int max_peers)
202 int rbd_mirror_peer_set_client(rados_ioctx_t io, const char *uuid,
203 const char *client_name)
204 int rbd_mirror_peer_set_cluster(rados_ioctx_t io_ctx, const char *uuid,
205 const char *cluster_name)
206 int rbd_mirror_image_status_list(rados_ioctx_t io, const char *start_id,
207 size_t max, char **image_ids,
208 rbd_mirror_image_status_t *images,
210 void rbd_mirror_image_status_list_cleanup(char **image_ids,
211 rbd_mirror_image_status_t *images,
213 int rbd_mirror_image_status_summary(rados_ioctx_t io,
214 rbd_mirror_image_status_state_t *states,
215 int *counts, size_t *maxlen)
217 int rbd_open(rados_ioctx_t io, const char *name,
218 rbd_image_t *image, const char *snap_name)
219 int rbd_open_read_only(rados_ioctx_t io, const char *name,
220 rbd_image_t *image, const char *snap_name)
221 int rbd_close(rbd_image_t image)
222 int rbd_resize(rbd_image_t image, uint64_t size)
223 int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
224 int rbd_get_old_format(rbd_image_t image, uint8_t *old)
225 int rbd_get_size(rbd_image_t image, uint64_t *size)
226 int rbd_get_features(rbd_image_t image, uint64_t *features)
227 int rbd_update_features(rbd_image_t image, uint64_t features,
229 int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
230 int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
231 int rbd_get_create_timestamp(rbd_image_t image, timespec *timestamp)
232 int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
233 int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
234 int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
236 int64_t rbd_get_data_pool_id(rbd_image_t image)
237 int rbd_get_parent_info2(rbd_image_t image,
238 char *parent_poolname, size_t ppoolnamelen,
239 char *parent_name, size_t pnamelen,
240 char *parent_id, size_t pidlen,
241 char *parent_snapname, size_t psnapnamelen)
242 int rbd_get_flags(rbd_image_t image, uint64_t *flags)
243 ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
244 char *buf, int op_flags)
245 ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
246 const char *buf, int op_flags)
247 int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
248 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
249 const char *destname, rbd_image_options_t dest_opts)
250 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
252 void rbd_snap_list_end(rbd_snap_info_t *snaps)
253 int rbd_snap_create(rbd_image_t image, const char *snapname)
254 int rbd_snap_remove(rbd_image_t image, const char *snapname)
255 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
256 librbd_progress_fn_t cb, void *cbdata)
257 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
258 int rbd_snap_rename(rbd_image_t image, const char *snapname,
259 const char* dstsnapsname)
260 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
261 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
262 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
264 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
265 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
266 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
267 int rbd_snap_set(rbd_image_t image, const char *snapname)
268 int rbd_flatten(rbd_image_t image)
269 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
271 ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len,
272 char *images, size_t *images_len)
273 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
274 char *tag, size_t *tag_len,
275 char *clients, size_t *clients_len,
276 char *cookies, size_t *cookies_len,
277 char *addrs, size_t *addrs_len)
278 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
279 int rbd_lock_shared(rbd_image_t image, const char *cookie,
281 int rbd_unlock(rbd_image_t image, const char *cookie)
282 int rbd_break_lock(rbd_image_t image, const char *client,
285 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
286 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
287 int rbd_lock_release(rbd_image_t image)
288 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
289 char **lock_owners, size_t *max_lock_owners)
290 void rbd_lock_get_owners_cleanup(char **lock_owners,
291 size_t lock_owner_count)
292 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
295 # We use -9000 to propagate Python exceptions. We use except? to make sure
296 # things still work as intended if -9000 happens to be a valid errno value
298 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
299 uint64_t ofs, uint64_t len,
300 uint8_t include_parent, uint8_t whole_object,
301 int (*cb)(uint64_t, size_t, int, void *)
303 void *arg) except? -9000
305 int rbd_flush(rbd_image_t image)
306 int rbd_invalidate_cache(rbd_image_t image)
308 int rbd_mirror_image_enable(rbd_image_t image)
309 int rbd_mirror_image_disable(rbd_image_t image, bint force)
310 int rbd_mirror_image_promote(rbd_image_t image, bint force)
311 int rbd_mirror_image_demote(rbd_image_t image)
312 int rbd_mirror_image_resync(rbd_image_t image)
313 int rbd_mirror_image_get_info(rbd_image_t image,
314 rbd_mirror_image_info_t *mirror_image_info,
316 int rbd_mirror_image_get_status(rbd_image_t image,
317 rbd_mirror_image_status_t *mirror_image_status,
320 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
321 const char *buf, rbd_completion_t c, int op_flags)
322 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
323 char *buf, rbd_completion_t c, int op_flags)
324 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
327 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
329 int rbd_aio_is_complete(rbd_completion_t c)
330 int rbd_aio_wait_for_complete(rbd_completion_t c)
331 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
332 void rbd_aio_release(rbd_completion_t c)
333 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
335 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
337 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
338 int rbd_metadata_remove(rbd_image_t image, const char *key)
339 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
340 char *keys, size_t *key_len, char *values,
343 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
344 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
345 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
346 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
347 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
348 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
349 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
350 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
352 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
353 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
354 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
355 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
356 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
358 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
360 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
361 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
362 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
364 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
365 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
366 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
368 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
369 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
370 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
371 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
372 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
373 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
374 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
376 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
377 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
379 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
380 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
381 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
382 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
383 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
384 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
386 class Error(Exception):
390 class OSError(Error):
391 """ `OSError` class, derived from `Error` """
392 def __init__(self, message, errno=None):
393 super(OSError, self).__init__(message)
397 msg = super(OSError, self).__str__()
398 if self.errno is None:
400 return '[errno {0}] {1}'.format(self.errno, msg)
402 def __reduce__(self):
403 return (self.__class__, (self.message, self.errno))
405 class PermissionError(OSError):
409 class ImageNotFound(OSError):
413 class ImageExists(OSError):
417 class IOError(OSError):
421 class NoSpace(OSError):
425 class IncompleteWriteError(OSError):
429 class InvalidArgument(OSError):
433 class LogicError(Error):
437 class ReadOnlyImage(OSError):
441 class ImageBusy(OSError):
445 class ImageHasSnapshots(OSError):
449 class FunctionNotSupported(OSError):
453 class ArgumentOutOfRange(OSError):
457 class ConnectionShutdown(OSError):
461 class Timeout(OSError):
464 class DiskQuotaExceeded(OSError):
468 cdef errno_to_exception = {
469 errno.EPERM : PermissionError,
470 errno.ENOENT : ImageNotFound,
472 errno.ENOSPC : NoSpace,
473 errno.EEXIST : ImageExists,
474 errno.EINVAL : InvalidArgument,
475 errno.EROFS : ReadOnlyImage,
476 errno.EBUSY : ImageBusy,
477 errno.ENOTEMPTY : ImageHasSnapshots,
478 errno.ENOSYS : FunctionNotSupported,
479 errno.EDOM : ArgumentOutOfRange,
480 errno.ESHUTDOWN : ConnectionShutdown,
481 errno.ETIMEDOUT : Timeout,
482 errno.EDQUOT : DiskQuotaExceeded,
485 cdef make_ex(ret, msg):
487 Translate a librbd return code into an exception.
489 :param ret: the return code
491 :param msg: the error message to use
493 :returns: a subclass of :class:`Error`
496 if ret in errno_to_exception:
497 return errno_to_exception[ret](msg, errno=ret)
499 return OSError(msg, errno=ret)
502 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
503 return <rados_ioctx_t>ioctx.io
505 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr) nogil:
508 def cstr(val, name, encoding="utf-8", opt=False):
510 Create a byte string from a Python string
512 :param basestring val: Python string
513 :param str name: Name of the string parameter, for exceptions
514 :param str encoding: Encoding to use
515 :param bool opt: If True, None is allowed
517 :raises: :class:`InvalidArgument`
519 if opt and val is None:
521 if isinstance(val, bytes):
523 elif isinstance(val, str):
524 return val.encode(encoding)
525 elif sys.version_info < (3, 0) and isinstance(val, unicode):
526 return val.encode(encoding)
528 raise InvalidArgument('%s must be a string' % name)
530 def decode_cstr(val, encoding="utf-8"):
532 Decode a byte string into a Python string.
534 :param bytes val: byte string
535 :rtype: unicode or None
540 return val.decode(encoding)
543 cdef char* opt_str(s) except? NULL:
548 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
549 cdef void *ret = realloc(ptr, size)
551 raise MemoryError("realloc failed")
554 cdef class Completion
556 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
558 Callback to oncomplete() for asynchronous operations
560 cdef Completion cb = <Completion>args
564 cdef class Completion(object):
565 """completion object"""
570 rbd_completion_t rbd_comp
575 def __cinit__(self, image, object oncomplete):
576 self.oncomplete = oncomplete
578 self.persisted = False
580 def is_complete(self):
582 Has an asynchronous operation completed?
584 This does not imply that the callback has finished.
586 :returns: True if the operation is completed
589 ret = rbd_aio_is_complete(self.rbd_comp)
592 def wait_for_complete_and_cb(self):
594 Wait for an asynchronous operation to complete
596 This method waits for the callback to execute, if one was provided.
597 It will also re-raise any exceptions raised by the callback. You
598 should call this to "reap" asynchronous completions and ensure that
599 any exceptions in the callbacks are handled, as an exception internal
600 to this module may have occurred.
603 rbd_aio_wait_for_complete(self.rbd_comp)
606 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
608 def get_return_value(self):
610 Get the return value of an asychronous operation
612 The return value is set when the operation is complete.
614 :returns: int - return value of the operation
617 ret = rbd_aio_get_return_value(self.rbd_comp)
620 def __dealloc__(self):
624 This is automatically called when the completion object is freed.
626 ref.Py_XDECREF(self.buf)
628 if self.rbd_comp != NULL:
630 rbd_aio_release(self.rbd_comp)
633 cdef void _complete(self):
637 self.oncomplete(self)
638 # In the event that something raises an exception during the next 2
639 # lines of code, we will not be able to catch it, and this may result
640 # in the app not noticing a failed callback. However, this should only
641 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
642 # should not be a problem because the callback thread from librbd
643 # ought to have SIGINT blocked.
645 self.exc_info = sys.exc_info()
647 cdef __persist(self):
648 if self.oncomplete is not None and not self.persisted:
649 # Increment our own reference count to make sure the completion
650 # is not freed until the callback is called. The completion is
651 # allowed to be freed if there is no callback.
653 self.persisted = True
655 cdef __unpersist(self):
658 self.persisted = False
663 This class wraps librbd CRUD functions.
667 Get the version number of the ``librbd`` C library.
669 :returns: a tuple of ``(major, minor, extra)`` components of the
675 rbd_version(&major, &minor, &extra)
676 return (major, minor, extra)
678 def create(self, ioctx, name, size, order=None, old_format=True,
679 features=None, stripe_unit=None, stripe_count=None,
684 :param ioctx: the context in which to create the image
685 :type ioctx: :class:`rados.Ioctx`
686 :param name: what the image is called
688 :param size: how big the image is in bytes
690 :param order: the image is split into (2**order) byte objects
692 :param old_format: whether to create an old-style image that
693 is accessible by old clients, but can't
694 use more advanced features like layering.
695 :type old_format: bool
696 :param features: bitmask of features to enable
698 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
699 :type stripe_unit: int
700 :param stripe_count: objects to stripe over before looping
701 :type stripe_count: int
702 :param data_pool: optional separate pool for data blocks
704 :raises: :class:`ImageExists`
705 :raises: :class:`TypeError`
706 :raises: :class:`InvalidArgument`
707 :raises: :class:`FunctionNotSupported`
709 name = cstr(name, 'name')
710 data_pool = cstr(data_pool, 'data_pool', opt=True)
712 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
714 uint64_t _size = size
716 rbd_image_options_t opts
717 if order is not None:
721 ((stripe_unit is not None) and stripe_unit != 0) or
722 ((stripe_count is not None) and stripe_count != 0) or
724 raise InvalidArgument('format 1 images do not support feature '
725 'masks, non-default striping, nor data '
728 ret = rbd_create(_ioctx, _name, _size, &_order)
730 rbd_image_options_create(&opts)
732 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
733 1 if old_format else 2)
734 if features is not None:
735 rbd_image_options_set_uint64(opts,
736 RBD_IMAGE_OPTION_FEATURES,
738 if order is not None:
739 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
741 if stripe_unit is not None:
742 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
744 if stripe_count is not None:
745 rbd_image_options_set_uint64(opts,
746 RBD_IMAGE_OPTION_STRIPE_COUNT,
748 if data_pool is not None:
749 rbd_image_options_set_string(opts,
750 RBD_IMAGE_OPTION_DATA_POOL,
753 ret = rbd_create4(_ioctx, _name, _size, opts)
755 rbd_image_options_destroy(opts)
757 raise make_ex(ret, 'error creating image')
759 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
760 features=None, order=None, stripe_unit=None, stripe_count=None,
763 Clone a parent rbd snapshot into a COW sparse child.
765 :param p_ioctx: the parent context that represents the parent snap
766 :type ioctx: :class:`rados.Ioctx`
767 :param p_name: the parent image name
769 :param p_snapname: the parent image snapshot name
771 :param c_ioctx: the child context that represents the new clone
772 :type ioctx: :class:`rados.Ioctx`
773 :param c_name: the clone (child) name
775 :param features: bitmask of features to enable; if set, must include layering
777 :param order: the image is split into (2**order) byte objects
779 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
780 :type stripe_unit: int
781 :param stripe_count: objects to stripe over before looping
782 :type stripe_count: int
783 :param data_pool: optional separate pool for data blocks
785 :raises: :class:`TypeError`
786 :raises: :class:`InvalidArgument`
787 :raises: :class:`ImageExists`
788 :raises: :class:`FunctionNotSupported`
789 :raises: :class:`ArgumentOutOfRange`
791 p_snapname = cstr(p_snapname, 'p_snapname')
792 p_name = cstr(p_name, 'p_name')
793 c_name = cstr(c_name, 'c_name')
794 data_pool = cstr(data_pool, 'data_pool', opt=True)
796 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
797 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
798 char *_p_name = p_name
799 char *_p_snapname = p_snapname
800 char *_c_name = c_name
801 rbd_image_options_t opts
803 rbd_image_options_create(&opts)
805 if features is not None:
806 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
808 if order is not None:
809 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
811 if stripe_unit is not None:
812 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
814 if stripe_count is not None:
815 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
817 if data_pool is not None:
818 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
821 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
822 _c_ioctx, _c_name, opts)
824 rbd_image_options_destroy(opts)
826 raise make_ex(ret, 'error creating clone')
828 def list(self, ioctx):
832 :param ioctx: determines which RADOS pool is read
833 :type ioctx: :class:`rados.Ioctx`
834 :returns: list -- a list of image names
837 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
842 c_names = <char *>realloc_chk(c_names, size)
844 ret = rbd_list(_ioctx, c_names, &size)
847 elif ret != -errno.ERANGE:
848 raise make_ex(ret, 'error listing images')
849 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
854 def remove(self, ioctx, name):
856 Delete an RBD image. This may take a long time, since it does
857 not return until every object that comprises the image has
858 been deleted. Note that all snapshots must be deleted before
859 the image can be removed. If there are snapshots left,
860 :class:`ImageHasSnapshots` is raised. If the image is still
861 open, or the watch from a crashed client has not expired,
862 :class:`ImageBusy` is raised.
864 :param ioctx: determines which RADOS pool the image is in
865 :type ioctx: :class:`rados.Ioctx`
866 :param name: the name of the image to remove
868 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
869 :class:`ImageHasSnapshots`
871 name = cstr(name, 'name')
873 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
876 ret = rbd_remove(_ioctx, _name)
878 raise make_ex(ret, 'error removing image')
880 def rename(self, ioctx, src, dest):
884 :param ioctx: determines which RADOS pool the image is in
885 :type ioctx: :class:`rados.Ioctx`
886 :param src: the current name of the image
888 :param dest: the new name of the image
890 :raises: :class:`ImageNotFound`, :class:`ImageExists`
892 src = cstr(src, 'src')
893 dest = cstr(dest, 'dest')
895 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
899 ret = rbd_rename(_ioctx, _src, _dest)
901 raise make_ex(ret, 'error renaming image')
903 def trash_move(self, ioctx, name, delay=0):
905 Move an RBD image to the trash.
906 :param ioctx: determines which RADOS pool the image is in
907 :type ioctx: :class:`rados.Ioctx`
908 :param name: the name of the image to remove
910 :param delay: time delay in seconds before the image can be deleted
913 :raises: :class:`ImageNotFound`
915 name = cstr(name, 'name')
917 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
919 uint64_t _delay = delay
921 ret = rbd_trash_move(_ioctx, _name, _delay)
923 raise make_ex(ret, 'error moving image to trash')
925 def trash_remove(self, ioctx, image_id, force=False):
927 Delete an RBD image from trash. If image deferment time has not
928 expired :class:`PermissionError` is raised.
929 :param ioctx: determines which RADOS pool the image is in
930 :type ioctx: :class:`rados.Ioctx`
931 :param image_id: the id of the image to remove
933 :param force: force remove even if deferment time has not expired
935 :raises: :class:`ImageNotFound`, :class:`PermissionError`
937 image_id = cstr(image_id, 'image_id')
939 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
940 char *_image_id = image_id
943 ret = rbd_trash_remove(_ioctx, _image_id, _force)
945 raise make_ex(ret, 'error deleting image from trash')
947 def trash_get(self, ioctx, image_id):
949 Retrieve RBD image info from trash
950 :param ioctx: determines which RADOS pool the image is in
951 :type ioctx: :class:`rados.Ioctx`
952 :param image_id: the id of the image to restore
954 :returns: dict - contains the following keys:
956 * ``id`` (str) - image id
958 * ``name`` (str) - image name
960 * ``source`` (str) - source of deletion
962 * ``deletion_time`` (datetime) - time of deletion
964 * ``deferment_end_time`` (datetime) - time that an image is allowed
965 to be removed from trash
967 :raises: :class:`ImageNotFound`
969 image_id = cstr(image_id, 'image_id')
971 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
972 char *_image_id = image_id
973 rbd_trash_image_info_t c_info
975 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
977 raise make_ex(ret, 'error restoring image from trash')
979 __source_string = ['USER', 'MIRRORING']
981 'id' : decode_cstr(c_info.id),
982 'name' : decode_cstr(c_info.name),
983 'source' : __source_string[c_info.source],
984 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
985 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
987 rbd_trash_get_cleanup(&c_info)
990 def trash_list(self, ioctx):
992 List all entries from trash.
993 :param ioctx: determines which RADOS pool the image is in
994 :type ioctx: :class:`rados.Ioctx`
995 :returns: :class:`TrashIterator`
997 return TrashIterator(ioctx)
999 def trash_restore(self, ioctx, image_id, name):
1001 Restore an RBD image from trash.
1002 :param ioctx: determines which RADOS pool the image is in
1003 :type ioctx: :class:`rados.Ioctx`
1004 :param image_id: the id of the image to restore
1006 :param name: the new name of the restored image
1008 :raises: :class:`ImageNotFound`
1010 image_id = cstr(image_id, 'image_id')
1011 name = cstr(name, 'name')
1013 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1014 char *_image_id = image_id
1017 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1019 raise make_ex(ret, 'error restoring image from trash')
1021 def mirror_mode_get(self, ioctx):
1023 Get pool mirror mode.
1025 :param ioctx: determines which RADOS pool is read
1026 :type ioctx: :class:`rados.Ioctx`
1027 :returns: int - pool mirror mode
1030 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1031 rbd_mirror_mode_t mirror_mode
1033 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1035 raise make_ex(ret, 'error getting mirror mode')
1038 def mirror_mode_set(self, ioctx, mirror_mode):
1040 Set pool mirror mode.
1042 :param ioctx: determines which RADOS pool is written
1043 :type ioctx: :class:`rados.Ioctx`
1044 :param mirror_mode: mirror mode to set
1045 :type mirror_mode: int
1048 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1049 rbd_mirror_mode_t _mirror_mode = mirror_mode
1051 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1053 raise make_ex(ret, 'error setting mirror mode')
1055 def mirror_peer_add(self, ioctx, cluster_name, client_name):
1059 :param ioctx: determines which RADOS pool is used
1060 :type ioctx: :class:`rados.Ioctx`
1061 :param cluster_name: mirror peer cluster name
1062 :type cluster_name: str
1063 :param client_name: mirror peer client name
1064 :type client_name: str
1065 :returns: str - peer uuid
1067 cluster_name = cstr(cluster_name, 'cluster_name')
1068 client_name = cstr(client_name, 'client_name')
1070 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1072 size_t _uuid_max_length = 512
1073 char *_cluster_name = cluster_name
1074 char *_client_name = client_name
1076 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1077 ret = rbd_mirror_peer_add(_ioctx, _uuid, _uuid_max_length,
1078 _cluster_name, _client_name)
1080 raise make_ex(ret, 'error adding mirror peer')
1081 return decode_cstr(_uuid)
1085 def mirror_peer_remove(self, ioctx, uuid):
1089 :param ioctx: determines which RADOS pool is used
1090 :type ioctx: :class:`rados.Ioctx`
1091 :param uuid: peer uuid
1094 uuid = cstr(uuid, 'uuid')
1096 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1099 ret = rbd_mirror_peer_remove(_ioctx, _uuid)
1101 raise make_ex(ret, 'error removing mirror peer')
1103 def mirror_peer_list(self, ioctx):
1105 Iterate over the peers of a pool.
1107 :param ioctx: determines which RADOS pool is read
1108 :type ioctx: :class:`rados.Ioctx`
1109 :returns: :class:`MirrorPeerIterator`
1111 return MirrorPeerIterator(ioctx)
1113 def mirror_peer_set_client(self, ioctx, uuid, client_name):
1115 Set mirror peer client name
1117 :param ioctx: determines which RADOS pool is written
1118 :type ioctx: :class:`rados.Ioctx`
1119 :param uuid: uuid of the mirror peer
1121 :param client_name: client name of the mirror peer to set
1122 :type client_name: str
1124 uuid = cstr(uuid, 'uuid')
1125 client_name = cstr(client_name, 'client_name')
1127 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1129 char *_client_name = client_name
1131 ret = rbd_mirror_peer_set_client(_ioctx, _uuid, _client_name)
1133 raise make_ex(ret, 'error setting mirror peer client')
1135 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
1137 Set mirror peer cluster name
1139 :param ioctx: determines which RADOS pool is written
1140 :type ioctx: :class:`rados.Ioctx`
1141 :param uuid: uuid of the mirror peer
1143 :param cluster_name: cluster name of the mirror peer to set
1144 :type cluster_name: str
1146 uuid = cstr(uuid, 'uuid')
1147 cluster_name = cstr(cluster_name, 'cluster_name')
1149 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1151 char *_cluster_name = cluster_name
1153 ret = rbd_mirror_peer_set_cluster(_ioctx, _uuid, _cluster_name)
1155 raise make_ex(ret, 'error setting mirror peer cluster')
1157 def mirror_image_status_list(self, ioctx):
1159 Iterate over the mirror image statuses of a pool.
1161 :param ioctx: determines which RADOS pool is read
1162 :type ioctx: :class:`rados.Ioctx`
1163 :returns: :class:`MirrorImageStatus`
1165 return MirrorImageStatusIterator(ioctx)
1167 def mirror_image_status_summary(self, ioctx):
1169 Get mirror image status summary of a pool.
1171 :param ioctx: determines which RADOS pool is read
1172 :type ioctx: :class:`rados.Ioctx`
1173 :returns: list - a list of (state, count) tuples
1176 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1177 rbd_mirror_image_status_state_t *states = NULL
1181 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
1182 sizeof(rbd_mirror_image_status_state_t) * maxlen)
1183 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
1185 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
1188 raise make_ex(ret, 'error getting mirror image status summary')
1189 return [(states[i], counts[i]) for i in range(maxlen)]
1194 cdef class MirrorPeerIterator(object):
1196 Iterator over mirror peer info for a pool.
1198 Yields a dictionary containing information about a peer.
1202 * ``uuid`` (str) - uuid of the peer
1204 * ``cluster_name`` (str) - cluster name of the peer
1206 * ``client_name`` (str) - client name of the peer
1210 rbd_mirror_peer_t *peers
1213 def __init__(self, ioctx):
1215 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1219 self.peers = <rbd_mirror_peer_t *>realloc_chk(
1220 self.peers, self.num_peers * sizeof(rbd_mirror_peer_t))
1222 ret = rbd_mirror_peer_list(_ioctx, self.peers, &self.num_peers)
1224 if ret == -errno.ERANGE:
1227 raise make_ex(ret, 'error listing peers')
1231 for i in range(self.num_peers):
1233 'uuid' : decode_cstr(self.peers[i].uuid),
1234 'cluster_name' : decode_cstr(self.peers[i].cluster_name),
1235 'client_name' : decode_cstr(self.peers[i].client_name),
1238 def __dealloc__(self):
1240 rbd_mirror_peer_list_cleanup(self.peers, self.num_peers)
1243 cdef class MirrorImageStatusIterator(object):
1245 Iterator over mirror image status for a pool.
1247 Yields a dictionary containing mirror status of an image.
1251 * ``name`` (str) - mirror image name
1253 * `info` (dict) - mirror image info
1255 * `state` (int) - mirror state
1257 * `description` (str) - status description
1259 * `last_update` (datetime) - last status update time
1261 * ``up`` (bool) - is mirroring agent up
1269 rbd_mirror_image_status_t *images
1272 def __init__(self, ioctx):
1273 self.ioctx = convert_ioctx(ioctx)
1274 self.max_read = 1024
1275 self.last_read = strdup("")
1276 self.image_ids = <char **>realloc_chk(NULL,
1277 sizeof(char *) * self.max_read)
1278 self.images = <rbd_mirror_image_status_t *>realloc_chk(NULL,
1279 sizeof(rbd_mirror_image_status_t) * self.max_read)
1281 self.get_next_chunk()
1284 while self.size > 0:
1285 for i in range(self.size):
1287 'name' : decode_cstr(self.images[i].name),
1289 'global_id' : decode_cstr(self.images[i].info.global_id),
1290 'state' : self.images[i].info.state,
1292 'state' : self.images[i].state,
1293 'description' : decode_cstr(self.images[i].description),
1294 'last_update' : datetime.utcfromtimestamp(self.images[i].last_update),
1295 'up' : self.images[i].up,
1297 if self.size < self.max_read:
1299 self.get_next_chunk()
1301 def __dealloc__(self):
1302 rbd_mirror_image_status_list_cleanup(self.image_ids, self.images,
1305 free(self.last_read)
1307 free(self.image_ids)
1311 def get_next_chunk(self):
1313 rbd_mirror_image_status_list_cleanup(self.image_ids, self.images,
1317 ret = rbd_mirror_image_status_list(self.ioctx, self.last_read,
1318 self.max_read, self.image_ids,
1319 self.images, &self.size)
1321 raise make_ex(ret, 'error listing mirror images status')
1323 free(self.last_read)
1324 last_read = decode_cstr(self.image_ids[self.size - 1])
1325 self.last_read = strdup(last_read)
1327 free(self.last_read)
1328 self.last_read = strdup("")
1330 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
1331 except? -9000 with gil:
1332 # Make sure that if we wound up with an exception from a previous callback,
1333 # we stop calling back (just in case librbd ever fails to bail out on the
1334 # first negative return, as older versions did)
1335 if exc.PyErr_Occurred():
1337 ret = (<object>cb)(offset, length, bool(write))
1343 cdef class Image(object):
1345 This class represents an RBD image. It is used to perform I/O on
1346 the image and interact with snapshots.
1348 **Note**: Any method of this class may raise :class:`ImageNotFound`
1349 if the image has been deleted.
1351 cdef rbd_image_t image
1355 cdef rados_ioctx_t _ioctx
1357 def __init__(self, ioctx, name, snapshot=None, read_only=False):
1359 Open the image at the given snapshot.
1360 If a snapshot is specified, the image will be read-only, unless
1361 :func:`Image.set_snap` is called later.
1363 If read-only mode is used, metadata for the :class:`Image`
1364 object (such as which snapshots exist) may become obsolete. See
1365 the C api for more details.
1367 To clean up from opening the image, :func:`Image.close` should
1368 be called. For ease of use, this is done automatically when
1369 an :class:`Image` is used as a context manager (see :pep:`343`).
1371 :param ioctx: determines which RADOS pool the image is in
1372 :type ioctx: :class:`rados.Ioctx`
1373 :param name: the name of the image
1375 :param snapshot: which snapshot to read from
1376 :type snaphshot: str
1377 :param read_only: whether to open the image in read-only mode
1378 :type read_only: bool
1380 name = cstr(name, 'name')
1381 snapshot = cstr(snapshot, 'snapshot', opt=True)
1384 # Keep around a reference to the ioctx, so it won't get deleted
1387 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1389 char *_snapshot = opt_str(snapshot)
1392 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
1395 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
1397 raise make_ex(ret, 'error opening image %s at snapshot %s' % (name, snapshot))
1400 def __enter__(self):
1403 def __exit__(self, type_, value, traceback):
1405 Closes the image. See :func:`close`
1410 def __get_completion(self, oncomplete):
1412 Constructs a completion to use with asynchronous operations
1414 :param oncomplete: callback for the completion
1416 :raises: :class:`Error`
1417 :returns: completion object
1420 completion_obj = Completion(self, oncomplete)
1423 rbd_completion_t completion
1424 PyObject* p_completion_obj= <PyObject*>completion_obj
1427 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
1430 raise make_ex(ret, "error getting a completion")
1432 completion_obj.rbd_comp = completion
1433 return completion_obj
1437 Release the resources used by this image object.
1439 After this is called, this object should not be used.
1444 ret = rbd_close(self.image)
1446 raise make_ex(ret, 'error while closing image %s' % (
1449 def __dealloc__(self):
1453 return "rbd.Image(ioctx, %r)" % self.name
1455 def resize(self, size):
1457 Change the size of the image.
1459 :param size: the new size of the image
1462 cdef uint64_t _size = size
1464 ret = rbd_resize(self.image, _size)
1466 raise make_ex(ret, 'error resizing image %s' % (self.name,))
1470 Get information about the image. Currently parent pool and
1471 parent name are always -1 and ''.
1473 :returns: dict - contains the following keys:
1475 * ``size`` (int) - the size of the image in bytes
1477 * ``obj_size`` (int) - the size of each object that comprises the
1480 * ``num_objs`` (int) - the number of objects in the image
1482 * ``order`` (int) - log_2(object_size)
1484 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
1487 * ``parent_pool`` (int) - deprecated
1489 * ``parent_name`` (str) - deprecated
1491 See also :meth:`format` and :meth:`features`.
1494 cdef rbd_image_info_t info
1496 ret = rbd_stat(self.image, &info, sizeof(info))
1498 raise make_ex(ret, 'error getting info for image %s' % (self.name,))
1501 'obj_size' : info.obj_size,
1502 'num_objs' : info.num_objs,
1503 'order' : info.order,
1504 'block_name_prefix' : decode_cstr(info.block_name_prefix),
1505 'parent_pool' : info.parent_pool,
1506 'parent_name' : info.parent_name
1511 Get the RBD v2 internal image id
1513 :returns: str - image id
1516 int ret = -errno.ERANGE
1518 char *image_id = NULL
1520 while ret == -errno.ERANGE and size <= 4096:
1521 image_id = <char *>realloc_chk(image_id, size)
1523 ret = rbd_get_id(self.image, image_id, size)
1524 if ret == -errno.ERANGE:
1528 raise make_ex(ret, 'error getting id for image %s' % (self.name,))
1529 return decode_cstr(image_id)
1533 def block_name_prefix(self):
1535 Get the RBD block name prefix
1537 :returns: str - block name prefix
1540 int ret = -errno.ERANGE
1544 while ret == -errno.ERANGE and size <= 4096:
1545 prefix = <char *>realloc_chk(prefix, size)
1547 ret = rbd_get_block_name_prefix(self.image, prefix, size)
1548 if ret == -errno.ERANGE:
1552 raise make_ex(ret, 'error getting block name prefix for image %s' % (self.name,))
1553 return decode_cstr(prefix)
1557 def data_pool_id(self):
1559 Get the pool id of the pool where the data of this RBD image is stored.
1561 :returns: int - the pool id
1563 return rbd_get_data_pool_id(self.image)
1565 def parent_info(self):
1567 Get information about a cloned image's parent (if any)
1569 :returns: tuple - ``(pool name, image name, snapshot name)`` components
1571 :raises: :class:`ImageNotFound` if the image doesn't have a parent
1574 int ret = -errno.ERANGE
1578 char *snapname = NULL
1580 while ret == -errno.ERANGE and size <= 4096:
1581 pool = <char *>realloc_chk(pool, size)
1582 name = <char *>realloc_chk(name, size)
1583 snapname = <char *>realloc_chk(snapname, size)
1585 ret = rbd_get_parent_info2(self.image, pool, size, name,
1586 size, NULL, 0, snapname, size)
1587 if ret == -errno.ERANGE:
1591 raise make_ex(ret, 'error getting parent info for image %s' % (self.name,))
1592 return (decode_cstr(pool), decode_cstr(name), decode_cstr(snapname))
1598 def parent_id(self):
1600 Get image id of a cloned image's parent (if any)
1602 :returns: str - the parent id
1603 :raises: :class:`ImageNotFound` if the image doesn't have a parent
1606 int ret = -errno.ERANGE
1608 char *parent_id = NULL
1610 while ret == -errno.ERANGE and size <= 4096:
1611 parent_id = <char *>realloc_chk(parent_id, size)
1613 ret = rbd_get_parent_info2(self.image, NULL, 0, NULL, 0,
1614 parent_id, size, NULL, 0)
1615 if ret == -errno.ERANGE:
1619 raise make_ex(ret, 'error getting parent id for image %s' % (self.name,))
1620 return decode_cstr(parent_id)
1624 def old_format(self):
1626 Find out whether the image uses the old RBD format.
1628 :returns: bool - whether the image uses the old RBD format
1632 ret = rbd_get_old_format(self.image, &old)
1634 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
1639 Get the size of the image. If open to a snapshot, returns the
1640 size of that snapshot.
1642 :returns: the size of the image in bytes
1644 cdef uint64_t image_size
1646 ret = rbd_get_size(self.image, &image_size)
1648 raise make_ex(ret, 'error getting size for image %s' % (self.name))
1653 Get the features bitmask of the image.
1655 :returns: int - the features bitmask of the image
1657 cdef uint64_t features
1659 ret = rbd_get_features(self.image, &features)
1661 raise make_ex(ret, 'error getting features for image %s' % (self.name))
1664 def update_features(self, features, enabled):
1666 Update the features bitmask of the image by enabling/disabling
1667 a single feature. The feature must support the ability to be
1668 dynamically enabled/disabled.
1670 :param features: feature bitmask to enable/disable
1672 :param enabled: whether to enable/disable the feature
1674 :raises: :class:`InvalidArgument`
1677 uint64_t _features = features
1678 uint8_t _enabled = bool(enabled)
1680 ret = rbd_update_features(self.image, _features, _enabled)
1682 raise make_ex(ret, 'error updating features for image %s' %
1687 Get the number of overlapping bytes between the image and its parent
1688 image. If open to a snapshot, returns the overlap between the snapshot
1689 and the parent image.
1691 :returns: int - the overlap in bytes
1692 :raises: :class:`ImageNotFound` if the image doesn't have a parent
1694 cdef uint64_t overlap
1696 ret = rbd_get_overlap(self.image, &overlap)
1698 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
1703 Get the flags bitmask of the image.
1705 :returns: int - the flags bitmask of the image
1709 ret = rbd_get_flags(self.image, &flags)
1711 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
1714 def is_exclusive_lock_owner(self):
1716 Get the status of the image exclusive lock.
1718 :returns: bool - true if the image is exclusively locked
1722 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
1724 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
1727 def copy(self, dest_ioctx, dest_name, features=None, order=None,
1728 stripe_unit=None, stripe_count=None, data_pool=None):
1730 Copy the image to another location.
1732 :param dest_ioctx: determines which pool to copy into
1733 :type dest_ioctx: :class:`rados.Ioctx`
1734 :param dest_name: the name of the copy
1735 :type dest_name: str
1736 :param features: bitmask of features to enable; if set, must include layering
1738 :param order: the image is split into (2**order) byte objects
1740 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1741 :type stripe_unit: int
1742 :param stripe_count: objects to stripe over before looping
1743 :type stripe_count: int
1744 :param data_pool: optional separate pool for data blocks
1745 :type data_pool: str
1746 :raises: :class:`TypeError`
1747 :raises: :class:`InvalidArgument`
1748 :raises: :class:`ImageExists`
1749 :raises: :class:`FunctionNotSupported`
1750 :raises: :class:`ArgumentOutOfRange`
1752 dest_name = cstr(dest_name, 'dest_name')
1753 data_pool = cstr(data_pool, 'data_pool', opt=True)
1755 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1756 char *_dest_name = dest_name
1757 rbd_image_options_t opts
1759 rbd_image_options_create(&opts)
1761 if features is not None:
1762 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1764 if order is not None:
1765 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1767 if stripe_unit is not None:
1768 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1770 if stripe_count is not None:
1771 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1773 if data_pool is not None:
1774 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1777 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
1779 rbd_image_options_destroy(opts)
1781 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
1783 def list_snaps(self):
1785 Iterate over the snapshots of an image.
1787 :returns: :class:`SnapIterator`
1789 return SnapIterator(self)
1791 def create_snap(self, name):
1793 Create a snapshot of the image.
1795 :param name: the name of the snapshot
1797 :raises: :class:`ImageExists`
1799 name = cstr(name, 'name')
1800 cdef char *_name = name
1802 ret = rbd_snap_create(self.image, _name)
1804 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
1806 def rename_snap(self, srcname, dstname):
1808 rename a snapshot of the image.
1810 :param srcname: the src name of the snapshot
1812 :param dstname: the dst name of the snapshot
1814 :raises: :class:`ImageExists`
1816 srcname = cstr(srcname, 'srcname')
1817 dstname = cstr(dstname, 'dstname')
1819 char *_srcname = srcname
1820 char *_dstname = dstname
1822 ret = rbd_snap_rename(self.image, _srcname, _dstname)
1824 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
1826 def remove_snap(self, name):
1828 Delete a snapshot of the image.
1830 :param name: the name of the snapshot
1832 :raises: :class:`IOError`, :class:`ImageBusy`
1834 name = cstr(name, 'name')
1835 cdef char *_name = name
1837 ret = rbd_snap_remove(self.image, _name)
1839 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
1841 def remove_snap2(self, name, flags):
1843 Delete a snapshot of the image.
1845 :param name: the name of the snapshot
1846 :param flags: the flags for removal
1848 :raises: :class:`IOError`, :class:`ImageBusy`
1850 name = cstr(name, 'name')
1853 uint32_t _flags = flags
1854 librbd_progress_fn_t prog_cb = &no_op_progress_callback
1856 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
1858 raise make_ex(ret, 'error removing snapshot %s from %s with flags %llx' % (name, self.name, flags))
1860 def rollback_to_snap(self, name):
1862 Revert the image to its contents at a snapshot. This is a
1863 potentially expensive operation, since it rolls back each
1864 object individually.
1866 :param name: the snapshot to rollback to
1868 :raises: :class:`IOError`
1870 name = cstr(name, 'name')
1871 cdef char *_name = name
1873 ret = rbd_snap_rollback(self.image, _name)
1875 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
1877 def protect_snap(self, name):
1879 Mark a snapshot as protected. This means it can't be deleted
1880 until it is unprotected.
1882 :param name: the snapshot to protect
1884 :raises: :class:`IOError`, :class:`ImageNotFound`
1886 name = cstr(name, 'name')
1887 cdef char *_name = name
1889 ret = rbd_snap_protect(self.image, _name)
1891 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
1893 def unprotect_snap(self, name):
1895 Mark a snapshot unprotected. This allows it to be deleted if
1898 :param name: the snapshot to unprotect
1900 :raises: :class:`IOError`, :class:`ImageNotFound`
1902 name = cstr(name, 'name')
1903 cdef char *_name = name
1905 ret = rbd_snap_unprotect(self.image, _name)
1907 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
1909 def is_protected_snap(self, name):
1911 Find out whether a snapshot is protected from deletion.
1913 :param name: the snapshot to check
1915 :returns: bool - whether the snapshot is protected
1916 :raises: :class:`IOError`, :class:`ImageNotFound`
1918 name = cstr(name, 'name')
1923 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
1925 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
1926 return is_protected == 1
1928 def get_snap_limit(self):
1930 Get the snapshot limit for an image.
1936 ret = rbd_snap_get_limit(self.image, &limit)
1938 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
1941 def set_snap_limit(self, limit):
1943 Set the snapshot limit for an image.
1945 :param limit: the new limit to set
1949 uint64_t _limit = limit
1951 ret = rbd_snap_set_limit(self.image, _limit)
1953 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
1956 def get_snap_timestamp(self, snap_id):
1958 Get the snapshot timestamp for an image.
1959 :param snap_id: the snapshot id of a snap shot
1963 uint64_t _snap_id = snap_id
1965 ret = rbd_snap_get_timestamp(self.image, _snap_id, ×tamp)
1967 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
1968 return datetime.utcfromtimestamp(timestamp.tv_sec)
1970 def remove_snap_limit(self):
1972 Remove the snapshot limit for an image, essentially setting
1973 the limit to the maximum size allowed by the implementation.
1976 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
1978 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
1981 def set_snap(self, name):
1983 Set the snapshot to read from. Writes will raise ReadOnlyImage
1984 while a snapshot is set. Pass None to unset the snapshot
1985 (reads come from the current image) , and allow writing again.
1987 :param name: the snapshot to read from, or None to unset the snapshot
1988 :type name: str or None
1990 name = cstr(name, 'name', opt=True)
1991 cdef char *_name = opt_str(name)
1993 ret = rbd_snap_set(self.image, _name)
1995 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
1997 def read(self, offset, length, fadvise_flags=0):
1999 Read data from the image. Raises :class:`InvalidArgument` if
2000 part of the range specified is outside the image.
2002 :param offset: the offset to start reading at
2004 :param length: how many bytes to read
2006 :param fadvise_flags: fadvise flags for this read
2007 :type fadvise_flags: int
2008 :returns: str - the data read
2009 :raises: :class:`InvalidArgument`, :class:`IOError`
2012 # This usage of the Python API allows us to construct a string
2013 # that librbd directly reads into, avoiding an extra copy. Although
2014 # strings are normally immutable, this usage is explicitly supported
2015 # for freshly created string objects.
2018 uint64_t _offset = offset
2019 size_t _length = length
2020 int _fadvise_flags = fadvise_flags
2021 PyObject* ret_s = NULL
2022 ret_s = PyBytes_FromStringAndSize(NULL, length)
2024 ret_buf = PyBytes_AsString(ret_s)
2026 ret = rbd_read2(self.image, _offset, _length, ret_buf,
2029 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
2031 if ret != <ssize_t>length:
2032 _PyBytes_Resize(&ret_s, ret)
2034 return <object>ret_s
2036 # We DECREF unconditionally: the cast to object above will have
2037 # INCREFed if necessary. This also takes care of exceptions,
2038 # including if _PyString_Resize fails (that will free the string
2039 # itself and set ret_s to NULL, hence XDECREF).
2040 ref.Py_XDECREF(ret_s)
2042 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
2043 include_parent = True, whole_object = False):
2045 Iterate over the changed extents of an image.
2047 This will call iterate_cb with three arguments:
2049 (offset, length, exists)
2051 where the changed extent starts at offset bytes, continues for
2052 length bytes, and is full of data (if exists is True) or zeroes
2053 (if exists is False).
2055 If from_snapshot is None, it is interpreted as the beginning
2056 of time and this generates all allocated extents.
2058 The end version is whatever is currently selected (via set_snap)
2061 iterate_cb may raise an exception, which will abort the diff and will be
2062 propagated to the caller.
2064 Raises :class:`InvalidArgument` if from_snapshot is after
2065 the currently set snapshot.
2067 Raises :class:`ImageNotFound` if from_snapshot is not the name
2068 of a snapshot of the image.
2070 :param offset: start offset in bytes
2072 :param length: size of region to report on, in bytes
2074 :param from_snapshot: starting snapshot name, or None
2075 :type from_snapshot: str or None
2076 :param iterate_cb: function to call for each extent
2077 :type iterate_cb: function acception arguments for offset,
2079 :param include_parent: True if full history diff should include parent
2080 :type include_parent: bool
2081 :param whole_object: True if diff extents should cover whole object
2082 :type whole_object: bool
2083 :raises: :class:`InvalidArgument`, :class:`IOError`,
2084 :class:`ImageNotFound`
2086 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
2088 char *_from_snapshot = opt_str(from_snapshot)
2089 uint64_t _offset = offset, _length = length
2090 uint8_t _include_parent = include_parent
2091 uint8_t _whole_object = whole_object
2093 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
2094 _length, _include_parent, _whole_object,
2095 &diff_iterate_cb, <void *>iterate_cb)
2097 msg = 'error generating diff from snapshot %s' % from_snapshot
2098 raise make_ex(ret, msg)
2100 def write(self, data, offset, fadvise_flags=0):
2102 Write data to the image. Raises :class:`InvalidArgument` if
2103 part of the write would fall outside the image.
2105 :param data: the data to be written
2107 :param offset: where to start writing data
2109 :param fadvise_flags: fadvise flags for this write
2110 :type fadvise_flags: int
2111 :returns: int - the number of bytes written
2112 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
2113 :class:`InvalidArgument`, :class:`IOError`
2115 if not isinstance(data, bytes):
2116 raise TypeError('data must be a byte string')
2118 uint64_t _offset = offset, length = len(data)
2120 int _fadvise_flags = fadvise_flags
2122 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
2124 if ret == <ssize_t>length:
2127 raise make_ex(ret, "error writing to %s" % (self.name,))
2128 elif ret < <ssize_t>length:
2129 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
2131 raise LogicError("logic error: rbd_write(%s) \
2132 returned %d, but %d was the maximum number of bytes it could have \
2133 written." % (self.name, ret, length))
2135 def discard(self, offset, length):
2137 Trim the range from the image. It will be logically filled
2140 cdef uint64_t _offset = offset, _length = length
2142 ret = rbd_discard(self.image, _offset, _length)
2144 msg = 'error discarding region %d~%d' % (offset, length)
2145 raise make_ex(ret, msg)
2149 Block until all writes are fully flushed if caching is enabled.
2152 ret = rbd_flush(self.image)
2154 raise make_ex(ret, 'error flushing image')
2156 def invalidate_cache(self):
2158 Drop any cached data for the image.
2161 ret = rbd_invalidate_cache(self.image)
2163 raise make_ex(ret, 'error invalidating cache')
2165 def stripe_unit(self):
2167 Return the stripe unit used for the image.
2169 cdef uint64_t stripe_unit
2171 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
2173 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
2176 def stripe_count(self):
2178 Return the stripe count used for the image.
2180 cdef uint64_t stripe_count
2182 ret = rbd_get_stripe_count(self.image, &stripe_count)
2184 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
2187 def create_timestamp(self):
2189 Return the create timestamp for the image.
2194 ret = rbd_get_create_timestamp(self.image, ×tamp)
2196 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
2197 return datetime.utcfromtimestamp(timestamp.tv_sec)
2201 Flatten clone image (copy all blocks from parent to child)
2204 ret = rbd_flatten(self.image)
2206 raise make_ex(ret, "error flattening %s" % self.name)
2208 def rebuild_object_map(self):
2210 Rebuild the object map for the image HEAD or currently set snapshot
2212 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
2214 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
2216 raise make_ex(ret, "error rebuilding object map %s" % self.name)
2218 def list_children(self):
2220 List children of the currently set snapshot (set via set_snap()).
2222 :returns: list - a list of (pool name, image name) tuples
2225 size_t pools_size = 512, images_size = 512
2226 char *c_pools = NULL
2227 char *c_images = NULL
2230 c_pools = <char *>realloc_chk(c_pools, pools_size)
2231 c_images = <char *>realloc_chk(c_images, images_size)
2233 ret = rbd_list_children(self.image, c_pools, &pools_size,
2234 c_images, &images_size)
2237 elif ret != -errno.ERANGE:
2238 raise make_ex(ret, 'error listing images')
2241 pools = map(decode_cstr, c_pools[:pools_size - 1].split(b'\0'))
2242 images = map(decode_cstr, c_images[:images_size - 1].split(b'\0'))
2243 return list(zip(pools, images))
2248 def list_lockers(self):
2250 List clients that have locked the image and information
2253 :returns: dict - contains the following keys:
2255 * ``tag`` - the tag associated with the lock (every
2256 additional locker must use the same tag)
2257 * ``exclusive`` - boolean indicating whether the
2258 lock is exclusive or shared
2259 * ``lockers`` - a list of (client, cookie, address)
2263 size_t clients_size = 512, cookies_size = 512
2264 size_t addrs_size = 512, tag_size = 512
2266 char *c_clients = NULL
2267 char *c_cookies = NULL
2268 char *c_addrs = NULL
2273 c_clients = <char *>realloc_chk(c_clients, clients_size)
2274 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
2275 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
2276 c_tag = <char *>realloc_chk(c_tag, tag_size)
2278 ret = rbd_list_lockers(self.image, &exclusive,
2280 c_clients, &clients_size,
2281 c_cookies, &cookies_size,
2282 c_addrs, &addrs_size)
2285 elif ret != -errno.ERANGE:
2286 raise make_ex(ret, 'error listing images')
2289 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
2290 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
2291 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
2293 'tag' : decode_cstr(c_tag),
2294 'exclusive' : exclusive == 1,
2295 'lockers' : list(zip(clients, cookies, addrs)),
2303 def lock_acquire(self, lock_mode):
2305 Acquire a managed lock on the image.
2307 :param lock_mode: lock mode to set
2308 :type lock_mode: int
2309 :raises: :class:`ImageBusy` if the lock could not be acquired
2312 rbd_lock_mode_t _lock_mode = lock_mode
2314 ret = rbd_lock_acquire(self.image, _lock_mode)
2316 raise make_ex(ret, 'error acquiring lock on image')
2318 def lock_release(self):
2320 Release a managed lock on the image that was previously acquired.
2323 ret = rbd_lock_release(self.image)
2325 raise make_ex(ret, 'error releasing lock on image')
2327 def lock_get_owners(self):
2329 Iterate over the lock owners of an image.
2331 :returns: :class:`LockOwnerIterator`
2333 return LockOwnerIterator(self)
2335 def lock_break(self, lock_mode, lock_owner):
2337 Break the image lock held by a another client.
2339 :param lock_owner: the owner of the lock to break
2340 :type lock_owner: str
2342 lock_owner = cstr(lock_owner, 'lock_owner')
2344 rbd_lock_mode_t _lock_mode = lock_mode
2345 char *_lock_owner = lock_owner
2347 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
2349 raise make_ex(ret, 'error breaking lock on image')
2351 def lock_exclusive(self, cookie):
2353 Take an exclusive lock on the image.
2355 :raises: :class:`ImageBusy` if a different client or cookie locked it
2356 :class:`ImageExists` if the same client and cookie locked it
2358 cookie = cstr(cookie, 'cookie')
2359 cdef char *_cookie = cookie
2361 ret = rbd_lock_exclusive(self.image, _cookie)
2363 raise make_ex(ret, 'error acquiring exclusive lock on image')
2365 def lock_shared(self, cookie, tag):
2367 Take a shared lock on the image. The tag must match
2368 that of the existing lockers, if any.
2370 :raises: :class:`ImageBusy` if a different client or cookie locked it
2371 :class:`ImageExists` if the same client and cookie locked it
2373 cookie = cstr(cookie, 'cookie')
2374 tag = cstr(tag, 'tag')
2376 char *_cookie = cookie
2379 ret = rbd_lock_shared(self.image, _cookie, _tag)
2381 raise make_ex(ret, 'error acquiring shared lock on image')
2383 def unlock(self, cookie):
2385 Release a lock on the image that was locked by this rados client.
2387 cookie = cstr(cookie, 'cookie')
2388 cdef char *_cookie = cookie
2390 ret = rbd_unlock(self.image, _cookie)
2392 raise make_ex(ret, 'error unlocking image')
2394 def break_lock(self, client, cookie):
2396 Release a lock held by another rados client.
2398 client = cstr(client, 'client')
2399 cookie = cstr(cookie, 'cookie')
2401 char *_client = client
2402 char *_cookie = cookie
2404 ret = rbd_break_lock(self.image, _client, _cookie)
2406 raise make_ex(ret, 'error unlocking image')
2408 def mirror_image_enable(self):
2410 Enable mirroring for the image.
2413 ret = rbd_mirror_image_enable(self.image)
2415 raise make_ex(ret, 'error enabling mirroring for image %s'
2418 def mirror_image_disable(self, force):
2420 Disable mirroring for the image.
2422 :param force: force disabling
2425 cdef bint c_force = force
2427 ret = rbd_mirror_image_disable(self.image, c_force)
2429 raise make_ex(ret, 'error disabling mirroring for image %s' %
2432 def mirror_image_promote(self, force):
2434 Promote the image to primary for mirroring.
2436 :param force: force promoting
2439 cdef bint c_force = force
2441 ret = rbd_mirror_image_promote(self.image, c_force)
2443 raise make_ex(ret, 'error promoting image %s to primary' %
2446 def mirror_image_demote(self):
2448 Demote the image to secondary for mirroring.
2451 ret = rbd_mirror_image_demote(self.image)
2453 raise make_ex(ret, 'error demoting image %s to secondary' %
2456 def mirror_image_resync(self):
2458 Flag the image to resync.
2461 ret = rbd_mirror_image_resync(self.image)
2463 raise make_ex(ret, 'error to resync image %s' % (self.name,))
2465 def mirror_image_get_info(self):
2467 Get mirror info for the image.
2469 :returns: dict - contains the following keys:
2471 * ``global_id`` (str) - image global id
2473 * ``state`` (int) - mirror state
2475 * ``primary`` (bool) - is image primary
2477 cdef rbd_mirror_image_info_t c_info
2479 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
2481 raise make_ex(ret, 'error getting mirror info for image %s' %
2484 'global_id' : decode_cstr(c_info.global_id),
2485 'state' : int(c_info.state),
2486 'primary' : c_info.primary,
2488 free(c_info.global_id)
2491 def mirror_image_get_status(self):
2493 Get mirror status for the image.
2495 :returns: dict - contains the following keys:
2497 * ``name`` (str) - mirror image name
2499 * `info` (dict) - mirror image info
2501 * ``state`` (int) - status mirror state
2503 * ``description`` (str) - status description
2505 * ``last_update`` (datetime) - last status update time
2507 * ``up`` (bool) - is mirroring agent up
2509 cdef rbd_mirror_image_status_t c_status
2511 ret = rbd_mirror_image_get_status(self.image, &c_status,
2514 raise make_ex(ret, 'error getting mirror status for image %s' %
2517 'name' : decode_cstr(c_status.name),
2519 'global_id' : decode_cstr(c_status.info.global_id),
2520 'state' : int(c_status.info.state),
2521 'primary' : c_status.info.primary,
2523 'state' : c_status.state,
2524 'description' : decode_cstr(c_status.description),
2525 'last_update' : datetime.utcfromtimestamp(c_status.last_update),
2529 free(c_status.info.global_id)
2530 free(c_status.description)
2533 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
2535 Asynchronously read data from the image
2537 Raises :class:`InvalidArgument` if part of the range specified is
2540 oncomplete will be called with the returned read value as
2541 well as the completion:
2543 oncomplete(completion, data_read)
2545 :param offset: the offset to start reading at
2547 :param length: how many bytes to read
2549 :param oncomplete: what to do when the read is complete
2550 :type oncomplete: completion
2551 :param fadvise_flags: fadvise flags for this read
2552 :type fadvise_flags: int
2553 :returns: :class:`Completion` - the completion object
2554 :raises: :class:`InvalidArgument`, :class:`IOError`
2559 uint64_t _offset = offset
2560 size_t _length = length
2561 int _fadvise_flags = fadvise_flags
2562 Completion completion
2564 def oncomplete_(completion_v):
2565 cdef Completion _completion_v = completion_v
2566 return_value = _completion_v.get_return_value()
2567 if return_value > 0 and return_value != length:
2568 _PyBytes_Resize(&_completion_v.buf, return_value)
2569 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2571 completion = self.__get_completion(oncomplete_)
2572 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2573 ret_buf = PyBytes_AsString(completion.buf)
2575 completion.__persist()
2577 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
2578 completion.rbd_comp, _fadvise_flags)
2580 raise make_ex(ret, 'error reading %s %ld~%ld' %
2581 (self.name, offset, length))
2583 completion.__unpersist()
2588 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
2590 Asynchronously write data to the image
2592 Raises :class:`InvalidArgument` if part of the write would fall outside
2595 oncomplete will be called with the completion:
2597 oncomplete(completion)
2599 :param data: the data to be written
2601 :param offset: the offset to start writing at
2603 :param oncomplete: what to do when the write is complete
2604 :type oncomplete: completion
2605 :param fadvise_flags: fadvise flags for this write
2606 :type fadvise_flags: int
2607 :returns: :class:`Completion` - the completion object
2608 :raises: :class:`InvalidArgument`, :class:`IOError`
2612 uint64_t _offset = offset
2614 size_t _length = len(data)
2615 int _fadvise_flags = fadvise_flags
2616 Completion completion
2618 completion = self.__get_completion(oncomplete)
2620 completion.__persist()
2622 ret = rbd_aio_write2(self.image, _offset, _length, _data,
2623 completion.rbd_comp, _fadvise_flags)
2625 raise make_ex(ret, 'error writing %s %ld~%ld' %
2626 (self.name, offset, _length))
2628 completion.__unpersist()
2633 def aio_discard(self, offset, length, oncomplete):
2635 Asynchronously trim the range from the image. It will be logically
2640 uint64_t _offset = offset
2641 size_t _length = length
2642 Completion completion
2644 completion = self.__get_completion(oncomplete)
2646 completion.__persist()
2648 ret = rbd_aio_discard(self.image, _offset, _length,
2649 completion.rbd_comp)
2651 raise make_ex(ret, 'error discarding %s %ld~%ld' %
2652 (self.name, offset, _length))
2654 completion.__unpersist()
2659 def aio_flush(self, oncomplete):
2661 Asyncronously wait until all writes are fully flushed if caching is
2665 cdef Completion completion = self.__get_completion(oncomplete)
2667 completion.__persist()
2669 ret = rbd_aio_flush(self.image, completion.rbd_comp)
2671 raise make_ex(ret, 'error flushing')
2673 completion.__unpersist()
2678 def metadata_get(self, key):
2680 Get image metadata for the given key.
2682 :param key: metadata key
2684 :returns: str - image id
2686 key = cstr(key, 'key')
2694 value = <char *>realloc_chk(value, size)
2696 ret = rbd_metadata_get(self.image, _key, value, &size)
2697 if ret != -errno.ERANGE:
2699 if ret == -errno.ENOENT:
2700 raise KeyError('no metadata %s for image %s' % (key, self.name))
2702 raise make_ex(ret, 'error getting metadata %s for image %s' %
2704 return decode_cstr(value)
2708 def metadata_set(self, key, value):
2710 Set image metadata for the given key.
2712 :param key: metadata key
2714 :param value: metadata value
2717 key = cstr(key, 'key')
2718 value = cstr(value, 'value')
2721 char *_value = value
2723 ret = rbd_metadata_set(self.image, _key, _value)
2726 raise make_ex(ret, 'error setting metadata %s for image %s' %
2730 def metadata_remove(self, key):
2732 Remove image metadata for the given key.
2734 :param key: metadata key
2737 key = cstr(key, 'key')
2741 ret = rbd_metadata_remove(self.image, _key)
2743 if ret == -errno.ENOENT:
2744 raise KeyError('no metadata %s for image %s' % (key, self.name))
2746 raise make_ex(ret, 'error removing metadata %s for image %s' %
2749 def metadata_list(self):
2751 List image metadata.
2753 :returns: :class:`MetadataIterator`
2755 return MetadataIterator(self)
2757 cdef class LockOwnerIterator(object):
2759 Iterator over managed lock owners for an image
2761 Yields a dictionary containing information about the image's lock
2765 * ``mode`` (int) - active lock mode
2767 * ``owner`` (str) - lock owner name
2771 rbd_lock_mode_t lock_mode
2773 size_t num_lock_owners
2776 def __init__(self, Image image):
2778 self.lock_owners = NULL
2779 self.num_lock_owners = 8
2781 self.lock_owners = <char**>realloc_chk(self.lock_owners,
2782 self.num_lock_owners *
2785 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
2787 &self.num_lock_owners)
2790 elif ret != -errno.ERANGE:
2791 raise make_ex(ret, 'error listing lock owners for image %s' % (image.name,))
2794 for i in range(self.num_lock_owners):
2796 'mode' : int(self.lock_mode),
2797 'owner' : decode_cstr(self.lock_owners[i]),
2800 def __dealloc__(self):
2801 if self.lock_owners:
2802 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
2803 free(self.lock_owners)
2805 cdef class MetadataIterator(object):
2807 Iterator over metadata list for an image.
2809 Yields ``(key, value)`` tuple.
2811 * ``key`` (str) - metadata key
2812 * ``value`` (str) - metadata value
2822 def __init__(self, Image image):
2823 self.image_name = image.name
2824 self.image = image.image
2825 self.last_read = strdup("")
2827 self.get_next_chunk()
2830 while len(self.next_chunk) > 0:
2831 for pair in self.next_chunk:
2833 if len(self.next_chunk) < self.max_read:
2835 self.get_next_chunk()
2837 def __dealloc__(self):
2839 free(self.last_read)
2841 def get_next_chunk(self):
2844 size_t keys_size = 4096
2846 size_t vals_size = 4096
2849 c_keys = <char *>realloc_chk(c_keys, keys_size)
2850 c_vals = <char *>realloc_chk(c_vals, vals_size)
2852 ret = rbd_metadata_list(self.image, self.last_read,
2853 self.max_read, c_keys, &keys_size,
2857 elif ret != -errno.ERANGE:
2858 raise make_ex(ret, 'error listing metadata for image %s' %
2860 keys = [decode_cstr(key) for key in
2861 c_keys[:keys_size].split(b'\0') if key]
2862 vals = [decode_cstr(val) for val in
2863 c_vals[:vals_size].split(b'\0') if val]
2865 free(self.last_read)
2866 self.last_read = strdup(keys[-1])
2867 self.next_chunk = zip(keys, vals)
2872 cdef class SnapIterator(object):
2874 Iterator over snapshot info for an image.
2876 Yields a dictionary containing information about a snapshot.
2880 * ``id`` (int) - numeric identifier of the snapshot
2882 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
2884 * ``name`` (str) - name of the snapshot
2887 cdef rbd_snap_info_t *snaps
2891 def __init__(self, Image image):
2896 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
2898 sizeof(rbd_snap_info_t))
2900 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
2902 self.num_snaps = ret
2904 elif ret != -errno.ERANGE:
2905 raise make_ex(ret, 'error listing snapshots for image %s' % (image.name,))
2908 for i in range(self.num_snaps):
2910 'id' : self.snaps[i].id,
2911 'size' : self.snaps[i].size,
2912 'name' : decode_cstr(self.snaps[i].name),
2915 def __dealloc__(self):
2917 rbd_snap_list_end(self.snaps)
2920 cdef class TrashIterator(object):
2922 Iterator over trash entries.
2924 Yields a dictionary containing trash info of an image.
2928 * `id` (str) - image id
2930 * `name` (str) - image name
2932 * `source` (str) - source of deletion
2934 * `deletion_time` (datetime) - time of deletion
2936 * `deferment_end_time` (datetime) - time that an image is allowed to be
2943 rbd_trash_image_info_t *entries
2945 def __init__(self, ioctx):
2946 self.ioctx = convert_ioctx(ioctx)
2947 self.num_entries = 1024
2950 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
2952 sizeof(rbd_trash_image_info_t))
2954 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
2956 self.num_entries = ret
2958 elif ret != -errno.ERANGE:
2959 raise make_ex(ret, 'error listing trash entries')
2961 __source_string = ['USER', 'MIRRORING']
2964 for i in range(self.num_entries):
2966 'id' : decode_cstr(self.entries[i].id),
2967 'name' : decode_cstr(self.entries[i].name),
2968 'source' : TrashIterator.__source_string[self.entries[i].source],
2969 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
2970 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
2973 def __dealloc__(self):
2974 rbd_trash_list_cleanup(self.entries, self.num_entries)