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
27 from collections.abc import Iterable
29 from collections import Iterable
30 from datetime import datetime
31 from itertools import chain
37 cdef extern from "Python.h":
38 # These are in cpython/string.pxd, but use "object" types instead of
39 # PyObject*, which invokes assumptions in cpython that we need to
40 # legitimately break to implement zero-copy string buffers in Image.read().
41 # This is valid use of the Python API and documented as a special case.
42 PyObject *PyBytes_FromStringAndSize(char *v, Py_ssize_t len) except NULL
43 char* PyBytes_AsString(PyObject *string) except NULL
44 int _PyBytes_Resize(PyObject **string, Py_ssize_t newsize) except -1
46 cdef extern from "time.h":
47 ctypedef long int time_t
52 cdef extern from "<errno.h>" nogil:
54 _ECANCELED "ECANCELED"
56 cdef extern from "rados/librados.h":
58 _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
60 cdef extern from "rbd/librbd.h":
61 ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
63 cdef extern from "rbd/librbd.h" nogil:
65 _RBD_FEATURE_LAYERING "RBD_FEATURE_LAYERING"
66 _RBD_FEATURE_STRIPINGV2 "RBD_FEATURE_STRIPINGV2"
67 _RBD_FEATURE_EXCLUSIVE_LOCK "RBD_FEATURE_EXCLUSIVE_LOCK"
68 _RBD_FEATURE_OBJECT_MAP "RBD_FEATURE_OBJECT_MAP"
69 _RBD_FEATURE_FAST_DIFF "RBD_FEATURE_FAST_DIFF"
70 _RBD_FEATURE_DEEP_FLATTEN "RBD_FEATURE_DEEP_FLATTEN"
71 _RBD_FEATURE_JOURNALING "RBD_FEATURE_JOURNALING"
72 _RBD_FEATURE_DATA_POOL "RBD_FEATURE_DATA_POOL"
73 _RBD_FEATURE_OPERATIONS "RBD_FEATURE_OPERATIONS"
74 _RBD_FEATURE_MIGRATING "RBD_FEATURE_MIGRATING"
76 _RBD_FEATURES_INCOMPATIBLE "RBD_FEATURES_INCOMPATIBLE"
77 _RBD_FEATURES_RW_INCOMPATIBLE "RBD_FEATURES_RW_INCOMPATIBLE"
78 _RBD_FEATURES_MUTABLE "RBD_FEATURES_MUTABLE"
79 _RBD_FEATURES_SINGLE_CLIENT "RBD_FEATURES_SINGLE_CLIENT"
80 _RBD_FEATURES_ALL "RBD_FEATURES_ALL"
82 _RBD_OPERATION_FEATURE_CLONE_PARENT "RBD_OPERATION_FEATURE_CLONE_PARENT"
83 _RBD_OPERATION_FEATURE_CLONE_CHILD "RBD_OPERATION_FEATURE_CLONE_CHILD"
84 _RBD_OPERATION_FEATURE_GROUP "RBD_OPERATION_FEATURE_GROUP"
85 _RBD_OPERATION_FEATURE_SNAP_TRASH "RBD_OPERATION_FEATURE_SNAP_TRASH"
87 _RBD_FLAG_OBJECT_MAP_INVALID "RBD_FLAG_OBJECT_MAP_INVALID"
88 _RBD_FLAG_FAST_DIFF_INVALID "RBD_FLAG_FAST_DIFF_INVALID"
90 _RBD_IMAGE_OPTION_FORMAT "RBD_IMAGE_OPTION_FORMAT"
91 _RBD_IMAGE_OPTION_FEATURES "RBD_IMAGE_OPTION_FEATURES"
92 _RBD_IMAGE_OPTION_ORDER "RBD_IMAGE_OPTION_ORDER"
93 _RBD_IMAGE_OPTION_STRIPE_UNIT "RBD_IMAGE_OPTION_STRIPE_UNIT"
94 _RBD_IMAGE_OPTION_STRIPE_COUNT "RBD_IMAGE_OPTION_STRIPE_COUNT"
95 _RBD_IMAGE_OPTION_DATA_POOL "RBD_IMAGE_OPTION_DATA_POOL"
97 RBD_MAX_BLOCK_NAME_SIZE
98 RBD_MAX_IMAGE_NAME_SIZE
100 ctypedef void* rados_ioctx_t
101 ctypedef void* rbd_image_t
102 ctypedef void* rbd_image_options_t
103 ctypedef void* rbd_pool_stats_t
104 ctypedef void *rbd_completion_t
106 ctypedef struct rbd_image_info_t:
111 char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]
113 char parent_name[RBD_MAX_IMAGE_NAME_SIZE]
115 ctypedef struct rbd_snap_info_t:
120 ctypedef struct rbd_snap_group_namespace_t:
123 char *group_snap_name
125 ctypedef struct rbd_group_info_t:
129 ctypedef struct rbd_image_spec_t:
133 ctypedef struct rbd_linked_image_spec_t:
141 ctypedef enum rbd_snap_namespace_type_t:
142 _RBD_SNAP_NAMESPACE_TYPE_USER "RBD_SNAP_NAMESPACE_TYPE_USER"
143 _RBD_SNAP_NAMESPACE_TYPE_GROUP "RBD_SNAP_NAMESPACE_TYPE_GROUP"
144 _RBD_SNAP_NAMESPACE_TYPE_TRASH "RBD_SNAP_NAMESPACE_TYPE_TRASH"
146 ctypedef struct rbd_snap_spec_t:
148 rbd_snap_namespace_type_t namespace_type
151 ctypedef enum rbd_mirror_mode_t:
152 _RBD_MIRROR_MODE_DISABLED "RBD_MIRROR_MODE_DISABLED"
153 _RBD_MIRROR_MODE_IMAGE "RBD_MIRROR_MODE_IMAGE"
154 _RBD_MIRROR_MODE_POOL "RBD_MIRROR_MODE_POOL"
156 ctypedef struct rbd_mirror_peer_t:
161 cdef char* _RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST "RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST"
162 cdef char* _RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY "RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY"
164 ctypedef enum rbd_mirror_image_state_t:
165 _RBD_MIRROR_IMAGE_DISABLING "RBD_MIRROR_IMAGE_DISABLING"
166 _RBD_MIRROR_IMAGE_ENABLED "RBD_MIRROR_IMAGE_ENABLED"
167 _RBD_MIRROR_IMAGE_DISABLED "RBD_MIRROR_IMAGE_DISABLED"
169 ctypedef struct rbd_mirror_image_info_t:
171 rbd_mirror_image_state_t state
174 ctypedef enum rbd_mirror_image_status_state_t:
175 _MIRROR_IMAGE_STATUS_STATE_UNKNOWN "MIRROR_IMAGE_STATUS_STATE_UNKNOWN"
176 _MIRROR_IMAGE_STATUS_STATE_ERROR "MIRROR_IMAGE_STATUS_STATE_ERROR"
177 _MIRROR_IMAGE_STATUS_STATE_SYNCING "MIRROR_IMAGE_STATUS_STATE_SYNCING"
178 _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY"
179 _MIRROR_IMAGE_STATUS_STATE_REPLAYING "MIRROR_IMAGE_STATUS_STATE_REPLAYING"
180 _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY"
181 _MIRROR_IMAGE_STATUS_STATE_STOPPED "MIRROR_IMAGE_STATUS_STATE_STOPPED"
183 ctypedef struct rbd_mirror_image_status_t:
185 rbd_mirror_image_info_t info
186 rbd_mirror_image_status_state_t state
191 ctypedef enum rbd_lock_mode_t:
192 _RBD_LOCK_MODE_EXCLUSIVE "RBD_LOCK_MODE_EXCLUSIVE"
193 _RBD_LOCK_MODE_SHARED "RBD_LOCK_MODE_SHARED"
195 ctypedef enum rbd_trash_image_source_t:
196 _RBD_TRASH_IMAGE_SOURCE_USER "RBD_TRASH_IMAGE_SOURCE_USER",
197 _RBD_TRASH_IMAGE_SOURCE_MIRRORING "RBD_TRASH_IMAGE_SOURCE_MIRRORING",
198 _RBD_TRASH_IMAGE_SOURCE_MIGRATION "RBD_TRASH_IMAGE_SOURCE_MIGRATION"
199 _RBD_TRASH_IMAGE_SOURCE_REMOVING "RBD_TRASH_IMAGE_SOURCE_REMOVING"
201 ctypedef struct rbd_trash_image_info_t:
204 rbd_trash_image_source_t source
206 time_t deferment_end_time
208 ctypedef struct rbd_image_watcher_t:
213 ctypedef enum rbd_group_image_state_t:
214 _RBD_GROUP_IMAGE_STATE_ATTACHED "RBD_GROUP_IMAGE_STATE_ATTACHED"
215 _RBD_GROUP_IMAGE_STATE_INCOMPLETE "RBD_GROUP_IMAGE_STATE_INCOMPLETE"
217 ctypedef struct rbd_group_image_info_t:
220 rbd_group_image_state_t state
222 ctypedef enum rbd_group_snap_state_t:
223 _RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
224 _RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
226 ctypedef struct rbd_group_snap_info_t:
228 rbd_group_snap_state_t state
230 ctypedef enum rbd_image_migration_state_t:
231 _RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
232 _RBD_IMAGE_MIGRATION_STATE_ERROR "RBD_IMAGE_MIGRATION_STATE_ERROR"
233 _RBD_IMAGE_MIGRATION_STATE_PREPARING "RBD_IMAGE_MIGRATION_STATE_PREPARING"
234 _RBD_IMAGE_MIGRATION_STATE_PREPARED "RBD_IMAGE_MIGRATION_STATE_PREPARED"
235 _RBD_IMAGE_MIGRATION_STATE_EXECUTING "RBD_IMAGE_MIGRATION_STATE_EXECUTING"
236 _RBD_IMAGE_MIGRATION_STATE_EXECUTED "RBD_IMAGE_MIGRATION_STATE_EXECUTED"
238 ctypedef struct rbd_image_migration_status_t:
239 int64_t source_pool_id
240 char *source_pool_namespace
241 char *source_image_name
242 char *source_image_id
244 char *dest_pool_namespace
245 char *dest_image_name
247 rbd_image_migration_state_t state
248 char *state_description
250 ctypedef enum rbd_config_source_t:
251 _RBD_CONFIG_SOURCE_CONFIG "RBD_CONFIG_SOURCE_CONFIG"
252 _RBD_CONFIG_SOURCE_POOL "RBD_CONFIG_SOURCE_POOL"
253 _RBD_CONFIG_SOURCE_IMAGE "RBD_CONFIG_SOURCE_IMAGE"
255 ctypedef struct rbd_config_option_t:
258 rbd_config_source_t source
260 ctypedef enum rbd_pool_stat_option_t:
261 _RBD_POOL_STAT_OPTION_IMAGES "RBD_POOL_STAT_OPTION_IMAGES"
262 _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES"
263 _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES"
264 _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS "RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS"
265 _RBD_POOL_STAT_OPTION_TRASH_IMAGES "RBD_POOL_STAT_OPTION_TRASH_IMAGES"
266 _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES"
267 _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES"
268 _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
270 ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
272 void rbd_version(int *major, int *minor, int *extra)
274 void rbd_image_spec_list_cleanup(rbd_image_spec_t *image, size_t num_images)
275 void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
276 void rbd_linked_image_spec_list_cleanup(rbd_linked_image_spec_t *images,
278 void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
280 void rbd_image_options_create(rbd_image_options_t* opts)
281 void rbd_image_options_destroy(rbd_image_options_t opts)
282 int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
284 int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
286 int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
287 char* optval, size_t maxlen)
288 int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
290 int rbd_image_options_unset(rbd_image_options_t opts, int optname)
291 void rbd_image_options_clear(rbd_image_options_t opts)
292 int rbd_image_options_is_empty(rbd_image_options_t opts)
294 int rbd_list(rados_ioctx_t io, char *names, size_t *size)
295 int rbd_list2(rados_ioctx_t io, rbd_image_spec_t *images,
297 int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
299 int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
300 rbd_image_options_t opts)
301 int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
302 const char *p_snapname, rados_ioctx_t c_ioctx,
303 const char *c_name, rbd_image_options_t c_opts)
304 int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
305 librbd_progress_fn_t cb, void *cbdata)
306 int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
307 const char *destname)
309 int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay)
310 int rbd_trash_get(rados_ioctx_t io, const char *id,
311 rbd_trash_image_info_t *info)
312 void rbd_trash_get_cleanup(rbd_trash_image_info_t *info)
313 int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries,
315 void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
317 int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, float threshold)
318 int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
319 int force, librbd_progress_fn_t cb,
321 int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
323 int rbd_migration_prepare(rados_ioctx_t io_ctx, const char *image_name,
324 rados_ioctx_t dest_io_ctx,
325 const char *dest_image_name,
326 rbd_image_options_t opts)
327 int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
328 const char *image_name,
329 librbd_progress_fn_t cb,
331 int rbd_migration_commit_with_progress(rados_ioctx_t io_ctx,
332 const char *image_name,
333 librbd_progress_fn_t cb,
335 int rbd_migration_abort_with_progress(rados_ioctx_t io_ctx,
336 const char *image_name,
337 librbd_progress_fn_t cb, void *cbdata)
338 int rbd_migration_status(rados_ioctx_t io_ctx, const char *image_name,
339 rbd_image_migration_status_t *status,
341 void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
343 int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
344 int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
345 int rbd_mirror_peer_add(rados_ioctx_t io, char *uuid,
346 size_t uuid_max_length, const char *cluster_name,
347 const char *client_name)
348 int rbd_mirror_peer_remove(rados_ioctx_t io, const char *uuid)
349 int rbd_mirror_peer_list(rados_ioctx_t io_ctx, rbd_mirror_peer_t *peers,
351 void rbd_mirror_peer_list_cleanup(rbd_mirror_peer_t *peers, int max_peers)
352 int rbd_mirror_peer_set_client(rados_ioctx_t io, const char *uuid,
353 const char *client_name)
354 int rbd_mirror_peer_set_cluster(rados_ioctx_t io_ctx, const char *uuid,
355 const char *cluster_name)
356 int rbd_mirror_peer_get_attributes(rados_ioctx_t io_ctx, const char *uuid,
357 char *keys, size_t *max_key_len,
358 char *values, size_t *max_val_length,
359 size_t *key_value_count)
360 int rbd_mirror_peer_set_attributes(rados_ioctx_t io_ctx, const char *uuid,
361 const char *keys, const char *values,
364 int rbd_mirror_image_status_list(rados_ioctx_t io, const char *start_id,
365 size_t max, char **image_ids,
366 rbd_mirror_image_status_t *images,
368 void rbd_mirror_image_status_list_cleanup(char **image_ids,
369 rbd_mirror_image_status_t *images,
371 int rbd_mirror_image_status_summary(rados_ioctx_t io,
372 rbd_mirror_image_status_state_t *states,
373 int *counts, size_t *maxlen)
374 int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx,
375 const char *start_id,
376 size_t max, char **image_ids,
379 void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
383 int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
384 char *value, size_t *val_len)
385 int rbd_pool_metadata_set(rados_ioctx_t io_ctx, const char *key,
387 int rbd_pool_metadata_remove(rados_ioctx_t io_ctx, const char *key)
388 int rbd_pool_metadata_list(rados_ioctx_t io_ctx, const char *start,
389 uint64_t max, char *keys, size_t *key_len,
390 char *values, size_t *vals_len)
392 int rbd_config_pool_list(rados_ioctx_t io_ctx, rbd_config_option_t *options,
394 void rbd_config_pool_list_cleanup(rbd_config_option_t *options,
397 int rbd_open(rados_ioctx_t io, const char *name,
398 rbd_image_t *image, const char *snap_name)
399 int rbd_open_by_id(rados_ioctx_t io, const char *image_id,
400 rbd_image_t *image, const char *snap_name)
401 int rbd_open_read_only(rados_ioctx_t io, const char *name,
402 rbd_image_t *image, const char *snap_name)
403 int rbd_open_by_id_read_only(rados_ioctx_t io, const char *image_id,
404 rbd_image_t *image, const char *snap_name)
405 int rbd_close(rbd_image_t image)
406 int rbd_resize2(rbd_image_t image, uint64_t size, bint allow_shrink,
407 librbd_progress_fn_t cb, void *cbdata)
408 int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
409 int rbd_get_old_format(rbd_image_t image, uint8_t *old)
410 int rbd_get_size(rbd_image_t image, uint64_t *size)
411 int rbd_get_features(rbd_image_t image, uint64_t *features)
412 int rbd_update_features(rbd_image_t image, uint64_t features,
414 int rbd_get_op_features(rbd_image_t image, uint64_t *op_features)
415 int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
416 int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
417 int rbd_get_create_timestamp(rbd_image_t image, timespec *timestamp)
418 int rbd_get_access_timestamp(rbd_image_t image, timespec *timestamp)
419 int rbd_get_modify_timestamp(rbd_image_t image, timespec *timestamp)
420 int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
421 int rbd_get_name(rbd_image_t image, char *name, size_t *name_len)
422 int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
423 int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
425 int64_t rbd_get_data_pool_id(rbd_image_t image)
426 int rbd_get_parent(rbd_image_t image,
427 rbd_linked_image_spec_t *parent_image,
428 rbd_snap_spec_t *parent_snap)
429 int rbd_get_flags(rbd_image_t image, uint64_t *flags)
430 int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
431 size_t group_info_size)
433 ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
434 char *buf, int op_flags)
435 ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
436 const char *buf, int op_flags)
437 int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
438 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
439 const char *destname, rbd_image_options_t dest_opts)
440 int rbd_deep_copy(rbd_image_t src, rados_ioctx_t dest_io_ctx,
441 const char *destname, rbd_image_options_t dest_opts)
442 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
444 void rbd_snap_list_end(rbd_snap_info_t *snaps)
445 int rbd_snap_create(rbd_image_t image, const char *snapname)
446 int rbd_snap_remove(rbd_image_t image, const char *snapname)
447 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
448 librbd_progress_fn_t cb, void *cbdata)
449 int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
450 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
451 int rbd_snap_rename(rbd_image_t image, const char *snapname,
452 const char* dstsnapsname)
453 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
454 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
455 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
457 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
458 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
459 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
460 int rbd_snap_set(rbd_image_t image, const char *snapname)
461 int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
462 int rbd_snap_get_namespace_type(rbd_image_t image,
464 rbd_snap_namespace_type_t *namespace_type)
465 int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
466 rbd_snap_group_namespace_t *group_info,
467 size_t snap_group_namespace_size)
468 void rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_spec,
469 size_t snap_group_namespace_size)
470 int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
471 char *original_name, size_t max_length)
473 int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
475 int rbd_sparsify(rbd_image_t image, size_t sparse_size)
476 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
478 int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
479 size_t *max_children)
480 int rbd_list_descendants(rbd_image_t image,
481 rbd_linked_image_spec_t *descendants,
482 size_t *max_descendants)
484 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
485 char *tag, size_t *tag_len,
486 char *clients, size_t *clients_len,
487 char *cookies, size_t *cookies_len,
488 char *addrs, size_t *addrs_len)
489 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
490 int rbd_lock_shared(rbd_image_t image, const char *cookie,
492 int rbd_unlock(rbd_image_t image, const char *cookie)
493 int rbd_break_lock(rbd_image_t image, const char *client,
496 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
497 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
498 int rbd_lock_release(rbd_image_t image)
499 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
500 char **lock_owners, size_t *max_lock_owners)
501 void rbd_lock_get_owners_cleanup(char **lock_owners,
502 size_t lock_owner_count)
503 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
506 # We use -9000 to propagate Python exceptions. We use except? to make sure
507 # things still work as intended if -9000 happens to be a valid errno value
509 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
510 uint64_t ofs, uint64_t len,
511 uint8_t include_parent, uint8_t whole_object,
512 int (*cb)(uint64_t, size_t, int, void *)
514 void *arg) except? -9000
516 int rbd_flush(rbd_image_t image)
517 int rbd_invalidate_cache(rbd_image_t image)
519 int rbd_mirror_image_enable(rbd_image_t image)
520 int rbd_mirror_image_disable(rbd_image_t image, bint force)
521 int rbd_mirror_image_promote(rbd_image_t image, bint force)
522 int rbd_mirror_image_demote(rbd_image_t image)
523 int rbd_mirror_image_resync(rbd_image_t image)
524 int rbd_mirror_image_get_info(rbd_image_t image,
525 rbd_mirror_image_info_t *mirror_image_info,
527 int rbd_mirror_image_get_status(rbd_image_t image,
528 rbd_mirror_image_status_t *mirror_image_status,
530 int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id,
531 size_t *id_max_length)
533 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
534 const char *buf, rbd_completion_t c, int op_flags)
535 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
536 char *buf, rbd_completion_t c, int op_flags)
537 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
540 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
542 int rbd_aio_is_complete(rbd_completion_t c)
543 int rbd_aio_wait_for_complete(rbd_completion_t c)
544 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
545 void rbd_aio_release(rbd_completion_t c)
546 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
548 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
550 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
551 int rbd_metadata_remove(rbd_image_t image, const char *key)
552 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
553 char *keys, size_t *key_len, char *values,
555 int rbd_group_create(rados_ioctx_t p, const char *name)
556 int rbd_group_remove(rados_ioctx_t p, const char *name)
557 int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
558 int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest)
559 void rbd_group_info_cleanup(rbd_group_info_t *group_info,
560 size_t group_info_size)
561 int rbd_group_image_add(rados_ioctx_t group_p, const char *group_name,
562 rados_ioctx_t image_p, const char *image_name)
563 int rbd_group_image_remove(rados_ioctx_t group_p, const char *group_name,
564 rados_ioctx_t image_p, const char *image_name)
566 int rbd_group_image_list(rados_ioctx_t group_p,
567 const char *group_name,
568 rbd_group_image_info_t *images,
569 size_t group_image_info_size,
571 void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
572 size_t group_image_info_size, size_t len)
574 int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
575 const char *snap_name)
577 int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
578 const char *snap_name)
580 int rbd_group_snap_rename(rados_ioctx_t group_p, const char *group_name,
581 const char *old_snap_name,
582 const char *new_snap_name)
584 int rbd_group_snap_list(rados_ioctx_t group_p,
585 const char *group_name,
586 rbd_group_snap_info_t *snaps,
587 size_t group_snap_info_size,
590 void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
591 size_t group_snap_info_size, size_t len)
592 int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
593 const char *snap_name)
595 int rbd_watchers_list(rbd_image_t image, rbd_image_watcher_t *watchers,
596 size_t *max_watchers)
597 void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
600 int rbd_config_image_list(rbd_image_t image, rbd_config_option_t *options,
602 void rbd_config_image_list_cleanup(rbd_config_option_t *options,
605 int rbd_namespace_create(rados_ioctx_t io, const char *namespace_name)
606 int rbd_namespace_remove(rados_ioctx_t io, const char *namespace_name)
607 int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
609 int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
612 int rbd_pool_init(rados_ioctx_t, bint force)
614 void rbd_pool_stats_create(rbd_pool_stats_t *stats)
615 void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
616 int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
617 int stat_option, uint64_t* stat_val)
618 int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
620 ECANCELED = _ECANCELED
622 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
623 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
624 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
625 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
626 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
627 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
628 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
629 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
630 RBD_FEATURE_OPERATIONS = _RBD_FEATURE_OPERATIONS
631 RBD_FEATURE_MIGRATING = _RBD_FEATURE_MIGRATING
633 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
634 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
635 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
636 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
637 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
639 RBD_OPERATION_FEATURE_CLONE_PARENT = _RBD_OPERATION_FEATURE_CLONE_PARENT
640 RBD_OPERATION_FEATURE_CLONE_CHILD = _RBD_OPERATION_FEATURE_CLONE_CHILD
641 RBD_OPERATION_FEATURE_GROUP = _RBD_OPERATION_FEATURE_GROUP
642 RBD_OPERATION_FEATURE_SNAP_TRASH = _RBD_OPERATION_FEATURE_SNAP_TRASH
644 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
645 RBD_FLAG_FAST_DIFF_INVALID = _RBD_FLAG_FAST_DIFF_INVALID
647 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
648 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
649 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
651 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
652 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
653 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
655 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
656 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
657 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
658 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
659 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
660 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
661 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
663 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
664 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
666 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
667 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
668 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
669 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
670 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
671 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
673 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
674 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
675 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
677 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
678 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
680 RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
681 RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
683 RBD_IMAGE_MIGRATION_STATE_UNKNOWN = _RBD_IMAGE_MIGRATION_STATE_UNKNOWN
684 RBD_IMAGE_MIGRATION_STATE_ERROR = _RBD_IMAGE_MIGRATION_STATE_ERROR
685 RBD_IMAGE_MIGRATION_STATE_PREPARING = _RBD_IMAGE_MIGRATION_STATE_PREPARING
686 RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
687 RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
688 RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
690 RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
691 RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
692 RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
694 RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
695 RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
696 RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
697 RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
698 RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
699 RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
700 RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
701 RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
704 class Error(Exception):
708 class OSError(Error):
709 """ `OSError` class, derived from `Error` """
710 def __init__(self, message, errno=None):
711 super(OSError, self).__init__(message)
715 msg = super(OSError, self).__str__()
716 if self.errno is None:
718 return '[errno {0}] {1}'.format(self.errno, msg)
720 def __reduce__(self):
721 return (self.__class__, (self.message, self.errno))
723 class PermissionError(OSError):
727 class ImageNotFound(OSError):
730 class ObjectNotFound(OSError):
733 class ImageExists(OSError):
736 class ObjectExists(OSError):
740 class IOError(OSError):
744 class NoSpace(OSError):
748 class IncompleteWriteError(OSError):
752 class InvalidArgument(OSError):
756 class LogicError(Error):
760 class ReadOnlyImage(OSError):
764 class ImageBusy(OSError):
768 class ImageHasSnapshots(OSError):
772 class FunctionNotSupported(OSError):
776 class ArgumentOutOfRange(OSError):
780 class ConnectionShutdown(OSError):
784 class Timeout(OSError):
787 class DiskQuotaExceeded(OSError):
790 class OperationNotSupported(OSError):
791 def __init__(self, message, errno=None):
792 super(OperationNotSupported, self).__init__(
793 "RBD operation not supported (%s)" % message, errno)
795 class OperationCanceled(OSError):
796 def __init__(self, message, errno=None):
797 super(OperationCanceled, self).__init__(
798 "RBD operation canceled (%s)" % message, errno)
800 cdef errno_to_exception = {
801 errno.EPERM : PermissionError,
802 errno.ENOENT : ImageNotFound,
804 errno.ENOSPC : NoSpace,
805 errno.EEXIST : ImageExists,
806 errno.EINVAL : InvalidArgument,
807 errno.EROFS : ReadOnlyImage,
808 errno.EBUSY : ImageBusy,
809 errno.ENOTEMPTY : ImageHasSnapshots,
810 errno.ENOSYS : FunctionNotSupported,
811 errno.EDOM : ArgumentOutOfRange,
812 errno.ESHUTDOWN : ConnectionShutdown,
813 errno.ETIMEDOUT : Timeout,
814 errno.EDQUOT : DiskQuotaExceeded,
815 errno.EOPNOTSUPP : OperationNotSupported,
816 ECANCELED : OperationCanceled,
819 cdef group_errno_to_exception = {
820 errno.EPERM : PermissionError,
821 errno.ENOENT : ObjectNotFound,
823 errno.ENOSPC : NoSpace,
824 errno.EEXIST : ObjectExists,
825 errno.EINVAL : InvalidArgument,
826 errno.EROFS : ReadOnlyImage,
827 errno.EBUSY : ImageBusy,
828 errno.ENOTEMPTY : ImageHasSnapshots,
829 errno.ENOSYS : FunctionNotSupported,
830 errno.EDOM : ArgumentOutOfRange,
831 errno.ESHUTDOWN : ConnectionShutdown,
832 errno.ETIMEDOUT : Timeout,
833 errno.EDQUOT : DiskQuotaExceeded,
834 errno.EOPNOTSUPP : OperationNotSupported,
835 ECANCELED : OperationCanceled,
838 cdef make_ex(ret, msg, exception_map=errno_to_exception):
840 Translate a librbd return code into an exception.
842 :param ret: the return code
844 :param msg: the error message to use
846 :returns: a subclass of :class:`Error`
849 if ret in exception_map:
850 return exception_map[ret](msg, errno=ret)
852 return OSError(msg, errno=ret)
855 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
856 return <rados_ioctx_t>ioctx.io
858 cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
859 return (<object>ptr)(offset, total)
861 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
864 def cstr(val, name, encoding="utf-8", opt=False):
866 Create a byte string from a Python string
868 :param basestring val: Python string
869 :param str name: Name of the string parameter, for exceptions
870 :param str encoding: Encoding to use
871 :param bool opt: If True, None is allowed
873 :raises: :class:`InvalidArgument`
875 if opt and val is None:
877 if isinstance(val, bytes):
879 elif isinstance(val, str):
880 return val.encode(encoding)
881 elif sys.version_info < (3, 0) and isinstance(val, unicode):
882 return val.encode(encoding)
884 raise InvalidArgument('%s must be a string' % name)
886 def decode_cstr(val, encoding="utf-8"):
888 Decode a byte string into a Python string.
890 :param bytes val: byte string
891 :rtype: unicode or None
896 return val.decode(encoding)
899 cdef char* opt_str(s) except? NULL:
904 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
905 cdef void *ret = realloc(ptr, size)
907 raise MemoryError("realloc failed")
910 RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST)
911 RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY)
913 cdef class Completion
915 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
917 Callback to oncomplete() for asynchronous operations
919 cdef Completion cb = <Completion>args
923 cdef class Completion(object):
924 """completion object"""
929 rbd_completion_t rbd_comp
934 def __cinit__(self, image, object oncomplete):
935 self.oncomplete = oncomplete
937 self.persisted = False
939 def is_complete(self):
941 Has an asynchronous operation completed?
943 This does not imply that the callback has finished.
945 :returns: True if the operation is completed
948 ret = rbd_aio_is_complete(self.rbd_comp)
951 def wait_for_complete_and_cb(self):
953 Wait for an asynchronous operation to complete
955 This method waits for the callback to execute, if one was provided.
956 It will also re-raise any exceptions raised by the callback. You
957 should call this to "reap" asynchronous completions and ensure that
958 any exceptions in the callbacks are handled, as an exception internal
959 to this module may have occurred.
962 rbd_aio_wait_for_complete(self.rbd_comp)
965 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
967 def get_return_value(self):
969 Get the return value of an asychronous operation
971 The return value is set when the operation is complete.
973 :returns: int - return value of the operation
976 ret = rbd_aio_get_return_value(self.rbd_comp)
979 def __dealloc__(self):
983 This is automatically called when the completion object is freed.
985 ref.Py_XDECREF(self.buf)
987 if self.rbd_comp != NULL:
989 rbd_aio_release(self.rbd_comp)
992 cdef void _complete(self):
996 self.oncomplete(self)
997 # In the event that something raises an exception during the next 2
998 # lines of code, we will not be able to catch it, and this may result
999 # in the app not noticing a failed callback. However, this should only
1000 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
1001 # should not be a problem because the callback thread from librbd
1002 # ought to have SIGINT blocked.
1004 self.exc_info = sys.exc_info()
1006 cdef __persist(self):
1007 if self.oncomplete is not None and not self.persisted:
1008 # Increment our own reference count to make sure the completion
1009 # is not freed until the callback is called. The completion is
1010 # allowed to be freed if there is no callback.
1012 self.persisted = True
1014 cdef __unpersist(self):
1017 self.persisted = False
1022 This class wraps librbd CRUD functions.
1026 Get the version number of the ``librbd`` C library.
1028 :returns: a tuple of ``(major, minor, extra)`` components of the
1034 rbd_version(&major, &minor, &extra)
1035 return (major, minor, extra)
1037 def create(self, ioctx, name, size, order=None, old_format=True,
1038 features=None, stripe_unit=None, stripe_count=None,
1041 Create an rbd image.
1043 :param ioctx: the context in which to create the image
1044 :type ioctx: :class:`rados.Ioctx`
1045 :param name: what the image is called
1047 :param size: how big the image is in bytes
1049 :param order: the image is split into (2**order) byte objects
1051 :param old_format: whether to create an old-style image that
1052 is accessible by old clients, but can't
1053 use more advanced features like layering.
1054 :type old_format: bool
1055 :param features: bitmask of features to enable
1057 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1058 :type stripe_unit: int
1059 :param stripe_count: objects to stripe over before looping
1060 :type stripe_count: int
1061 :param data_pool: optional separate pool for data blocks
1062 :type data_pool: str
1063 :raises: :class:`ImageExists`
1064 :raises: :class:`TypeError`
1065 :raises: :class:`InvalidArgument`
1066 :raises: :class:`FunctionNotSupported`
1068 name = cstr(name, 'name')
1069 data_pool = cstr(data_pool, 'data_pool', opt=True)
1071 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1073 uint64_t _size = size
1075 rbd_image_options_t opts
1076 if order is not None:
1080 ((stripe_unit is not None) and stripe_unit != 0) or
1081 ((stripe_count is not None) and stripe_count != 0) or
1083 raise InvalidArgument('format 1 images do not support feature '
1084 'masks, non-default striping, nor data '
1087 ret = rbd_create(_ioctx, _name, _size, &_order)
1089 rbd_image_options_create(&opts)
1091 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
1092 1 if old_format else 2)
1093 if features is not None:
1094 rbd_image_options_set_uint64(opts,
1095 RBD_IMAGE_OPTION_FEATURES,
1097 if order is not None:
1098 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1100 if stripe_unit is not None:
1101 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1103 if stripe_count is not None:
1104 rbd_image_options_set_uint64(opts,
1105 RBD_IMAGE_OPTION_STRIPE_COUNT,
1107 if data_pool is not None:
1108 rbd_image_options_set_string(opts,
1109 RBD_IMAGE_OPTION_DATA_POOL,
1112 ret = rbd_create4(_ioctx, _name, _size, opts)
1114 rbd_image_options_destroy(opts)
1116 raise make_ex(ret, 'error creating image')
1118 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
1119 features=None, order=None, stripe_unit=None, stripe_count=None,
1122 Clone a parent rbd snapshot into a COW sparse child.
1124 :param p_ioctx: the parent context that represents the parent snap
1125 :type ioctx: :class:`rados.Ioctx`
1126 :param p_name: the parent image name
1128 :param p_snapname: the parent image snapshot name
1130 :param c_ioctx: the child context that represents the new clone
1131 :type ioctx: :class:`rados.Ioctx`
1132 :param c_name: the clone (child) name
1134 :param features: bitmask of features to enable; if set, must include layering
1136 :param order: the image is split into (2**order) byte objects
1138 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1139 :type stripe_unit: int
1140 :param stripe_count: objects to stripe over before looping
1141 :type stripe_count: int
1142 :param data_pool: optional separate pool for data blocks
1143 :type data_pool: str
1144 :raises: :class:`TypeError`
1145 :raises: :class:`InvalidArgument`
1146 :raises: :class:`ImageExists`
1147 :raises: :class:`FunctionNotSupported`
1148 :raises: :class:`ArgumentOutOfRange`
1150 p_snapname = cstr(p_snapname, 'p_snapname')
1151 p_name = cstr(p_name, 'p_name')
1152 c_name = cstr(c_name, 'c_name')
1153 data_pool = cstr(data_pool, 'data_pool', opt=True)
1155 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
1156 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
1157 char *_p_name = p_name
1158 char *_p_snapname = p_snapname
1159 char *_c_name = c_name
1160 rbd_image_options_t opts
1162 rbd_image_options_create(&opts)
1164 if features is not None:
1165 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1167 if order is not None:
1168 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1170 if stripe_unit is not None:
1171 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1173 if stripe_count is not None:
1174 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1176 if data_pool is not None:
1177 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1180 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
1181 _c_ioctx, _c_name, opts)
1183 rbd_image_options_destroy(opts)
1185 raise make_ex(ret, 'error creating clone')
1187 def list(self, ioctx):
1191 :param ioctx: determines which RADOS pool is read
1192 :type ioctx: :class:`rados.Ioctx`
1193 :returns: list -- a list of image names
1196 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1198 char *c_names = NULL
1201 c_names = <char *>realloc_chk(c_names, size)
1203 ret = rbd_list(_ioctx, c_names, &size)
1206 elif ret != -errno.ERANGE:
1207 raise make_ex(ret, 'error listing images')
1208 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
1213 def list2(self, ioctx):
1215 Iterate over the images in the pool.
1217 :param ioctx: determines which RADOS pool the image is in
1218 :type ioctx: :class:`rados.Ioctx`
1219 :returns: :class:`ImageIterator`
1221 return ImageIterator(ioctx)
1223 def remove(self, ioctx, name, on_progress=None):
1225 Delete an RBD image. This may take a long time, since it does
1226 not return until every object that comprises the image has
1227 been deleted. Note that all snapshots must be deleted before
1228 the image can be removed. If there are snapshots left,
1229 :class:`ImageHasSnapshots` is raised. If the image is still
1230 open, or the watch from a crashed client has not expired,
1231 :class:`ImageBusy` is raised.
1233 :param ioctx: determines which RADOS pool the image is in
1234 :type ioctx: :class:`rados.Ioctx`
1235 :param name: the name of the image to remove
1237 :param on_progress: optional progress callback function
1238 :type on_progress: callback function
1239 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
1240 :class:`ImageHasSnapshots`
1242 name = cstr(name, 'name')
1244 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1246 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1247 void *_prog_arg = NULL
1249 _prog_cb = &progress_callback
1250 _prog_arg = <void *>on_progress
1252 ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
1254 raise make_ex(ret, 'error removing image')
1256 def rename(self, ioctx, src, dest):
1258 Rename an RBD image.
1260 :param ioctx: determines which RADOS pool the image is in
1261 :type ioctx: :class:`rados.Ioctx`
1262 :param src: the current name of the image
1264 :param dest: the new name of the image
1266 :raises: :class:`ImageNotFound`, :class:`ImageExists`
1268 src = cstr(src, 'src')
1269 dest = cstr(dest, 'dest')
1271 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1275 ret = rbd_rename(_ioctx, _src, _dest)
1277 raise make_ex(ret, 'error renaming image')
1279 def trash_move(self, ioctx, name, delay=0):
1281 Move an RBD image to the trash.
1283 :param ioctx: determines which RADOS pool the image is in
1284 :type ioctx: :class:`rados.Ioctx`
1285 :param name: the name of the image to remove
1287 :param delay: time delay in seconds before the image can be deleted
1290 :raises: :class:`ImageNotFound`
1292 name = cstr(name, 'name')
1294 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1296 uint64_t _delay = delay
1298 ret = rbd_trash_move(_ioctx, _name, _delay)
1300 raise make_ex(ret, 'error moving image to trash')
1302 def trash_purge(self, ioctx, expire_ts=None, threshold=-1):
1304 Delete RBD images from trash in bulk.
1306 By default it removes images with deferment end time less than now.
1308 The timestamp is configurable, e.g. delete images that have expired a
1311 If the threshold is used it deletes images until X% pool usage is met.
1313 :param ioctx: determines which RADOS pool the image is in
1314 :type ioctx: :class:`rados.Ioctx`
1315 :param expire_ts: timestamp for images to be considered as expired (UTC)
1316 :type expire_ts: datetime
1317 :param threshold: percentage of pool usage to be met (0 to 1)
1318 :type threshold: float
1321 expire_epoch_ts = time.mktime(expire_ts.timetuple())
1326 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1327 time_t _expire_ts = expire_epoch_ts
1328 float _threshold = threshold
1330 ret = rbd_trash_purge(_ioctx, _expire_ts, _threshold)
1332 raise make_ex(ret, 'error purging images from trash')
1334 def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
1336 Delete an RBD image from trash. If image deferment time has not
1337 expired :class:`PermissionError` is raised.
1339 :param ioctx: determines which RADOS pool the image is in
1340 :type ioctx: :class:`rados.Ioctx`
1341 :param image_id: the id of the image to remove
1343 :param force: force remove even if deferment time has not expired
1345 :param on_progress: optional progress callback function
1346 :type on_progress: callback function
1347 :raises: :class:`ImageNotFound`, :class:`PermissionError`
1349 image_id = cstr(image_id, 'image_id')
1351 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1352 char *_image_id = image_id
1354 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1355 void *_prog_arg = NULL
1357 _prog_cb = &progress_callback
1358 _prog_arg = <void *>on_progress
1360 ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
1361 _prog_cb, _prog_arg)
1363 raise make_ex(ret, 'error deleting image from trash')
1365 def trash_get(self, ioctx, image_id):
1367 Retrieve RBD image info from trash.
1369 :param ioctx: determines which RADOS pool the image is in
1370 :type ioctx: :class:`rados.Ioctx`
1371 :param image_id: the id of the image to restore
1373 :returns: dict - contains the following keys:
1375 * ``id`` (str) - image id
1377 * ``name`` (str) - image name
1379 * ``source`` (str) - source of deletion
1381 * ``deletion_time`` (datetime) - time of deletion
1383 * ``deferment_end_time`` (datetime) - time that an image is allowed
1384 to be removed from trash
1386 :raises: :class:`ImageNotFound`
1388 image_id = cstr(image_id, 'image_id')
1390 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1391 char *_image_id = image_id
1392 rbd_trash_image_info_t c_info
1394 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
1396 raise make_ex(ret, 'error retrieving image from trash')
1398 __source_string = ['USER', 'MIRRORING', 'MIGRATION', 'REMOVING']
1400 'id' : decode_cstr(c_info.id),
1401 'name' : decode_cstr(c_info.name),
1402 'source' : __source_string[c_info.source],
1403 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
1404 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
1406 rbd_trash_get_cleanup(&c_info)
1409 def trash_list(self, ioctx):
1411 List all entries from trash.
1413 :param ioctx: determines which RADOS pool the image is in
1414 :type ioctx: :class:`rados.Ioctx`
1415 :returns: :class:`TrashIterator`
1417 return TrashIterator(ioctx)
1419 def trash_restore(self, ioctx, image_id, name):
1421 Restore an RBD image from trash.
1423 :param ioctx: determines which RADOS pool the image is in
1424 :type ioctx: :class:`rados.Ioctx`
1425 :param image_id: the id of the image to restore
1427 :param name: the new name of the restored image
1429 :raises: :class:`ImageNotFound`
1431 image_id = cstr(image_id, 'image_id')
1432 name = cstr(name, 'name')
1434 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1435 char *_image_id = image_id
1438 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1440 raise make_ex(ret, 'error restoring image from trash')
1442 def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
1443 features=None, order=None, stripe_unit=None, stripe_count=None,
1446 Prepare an RBD image migration.
1448 :param ioctx: determines which RADOS pool the image is in
1449 :type ioctx: :class:`rados.Ioctx`
1450 :param image_name: the current name of the image
1452 :param dest_ioctx: determines which pool to migration into
1453 :type dest_ioctx: :class:`rados.Ioctx`
1454 :param dest_image_name: the name of the destination image (may be the same image)
1455 :type dest_image_name: str
1456 :param features: bitmask of features to enable; if set, must include layering
1458 :param order: the image is split into (2**order) byte objects
1460 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1461 :type stripe_unit: int
1462 :param stripe_count: objects to stripe over before looping
1463 :type stripe_count: int
1464 :param data_pool: optional separate pool for data blocks
1465 :type data_pool: str
1466 :raises: :class:`TypeError`
1467 :raises: :class:`InvalidArgument`
1468 :raises: :class:`ImageExists`
1469 :raises: :class:`FunctionNotSupported`
1470 :raises: :class:`ArgumentOutOfRange`
1472 image_name = cstr(image_name, 'image_name')
1473 dest_image_name = cstr(dest_image_name, 'dest_image_name')
1475 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1476 char *_image_name = image_name
1477 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1478 char *_dest_image_name = dest_image_name
1479 rbd_image_options_t opts
1481 rbd_image_options_create(&opts)
1483 if features is not None:
1484 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1486 if order is not None:
1487 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1489 if stripe_unit is not None:
1490 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1492 if stripe_count is not None:
1493 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1495 if data_pool is not None:
1496 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1499 ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
1500 _dest_image_name, opts)
1502 rbd_image_options_destroy(opts)
1504 raise make_ex(ret, 'error migrating image %s' % (image_name))
1506 def migration_execute(self, ioctx, image_name, on_progress=None):
1508 Execute a prepared RBD image migration.
1510 :param ioctx: determines which RADOS pool the image is in
1511 :type ioctx: :class:`rados.Ioctx`
1512 :param image_name: the name of the image
1513 :type image_name: str
1514 :param on_progress: optional progress callback function
1515 :type on_progress: callback function
1516 :raises: :class:`ImageNotFound`
1518 image_name = cstr(image_name, 'image_name')
1520 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1521 char *_image_name = image_name
1522 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1523 void *_prog_arg = NULL
1525 _prog_cb = &progress_callback
1526 _prog_arg = <void *>on_progress
1528 ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
1529 _prog_cb, _prog_arg)
1531 raise make_ex(ret, 'error aborting migration')
1533 def migration_commit(self, ioctx, image_name, on_progress=None):
1535 Commit an executed RBD image migration.
1537 :param ioctx: determines which RADOS pool the image is in
1538 :type ioctx: :class:`rados.Ioctx`
1539 :param image_name: the name of the image
1540 :type image_name: str
1541 :param on_progress: optional progress callback function
1542 :type on_progress: callback function
1543 :raises: :class:`ImageNotFound`
1545 image_name = cstr(image_name, 'image_name')
1547 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1548 char *_image_name = image_name
1549 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1550 void *_prog_arg = NULL
1552 _prog_cb = &progress_callback
1553 _prog_arg = <void *>on_progress
1555 ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
1556 _prog_cb, _prog_arg)
1558 raise make_ex(ret, 'error aborting migration')
1560 def migration_abort(self, ioctx, image_name, on_progress=None):
1562 Cancel a previously started but interrupted migration.
1564 :param ioctx: determines which RADOS pool the image is in
1565 :type ioctx: :class:`rados.Ioctx`
1566 :param image_name: the name of the image
1567 :type image_name: str
1568 :param on_progress: optional progress callback function
1569 :type on_progress: callback function
1570 :raises: :class:`ImageNotFound`
1572 image_name = cstr(image_name, 'image_name')
1574 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1575 char *_image_name = image_name
1576 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1577 void *_prog_arg = NULL
1579 _prog_cb = &progress_callback
1580 _prog_arg = <void *>on_progress
1582 ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
1583 _prog_cb, _prog_arg)
1585 raise make_ex(ret, 'error aborting migration')
1587 def migration_status(self, ioctx, image_name):
1589 Return RBD image migration status.
1591 :param ioctx: determines which RADOS pool the image is in
1592 :type ioctx: :class:`rados.Ioctx`
1593 :param image_name: the name of the image
1594 :type image_name: str
1595 :returns: dict - contains the following keys:
1597 * ``source_pool_id`` (int) - source image pool id
1599 * ``source_pool_namespace`` (str) - source image pool namespace
1601 * ``source_image_name`` (str) - source image name
1603 * ``source_image_id`` (str) - source image id
1605 * ``dest_pool_id`` (int) - destination image pool id
1607 * ``dest_pool_namespace`` (str) - destination image pool namespace
1609 * ``dest_image_name`` (str) - destination image name
1611 * ``dest_image_id`` (str) - destination image id
1613 * ``state`` (int) - current migration state
1615 * ``state_description`` (str) - migration state description
1617 :raises: :class:`ImageNotFound`
1619 image_name = cstr(image_name, 'image_name')
1621 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1622 char *_image_name = image_name
1623 rbd_image_migration_status_t c_status
1625 ret = rbd_migration_status(_ioctx, _image_name, &c_status,
1628 raise make_ex(ret, 'error getting migration status')
1631 'source_pool_id' : c_status.source_pool_id,
1632 'source_pool_namespace' : decode_cstr(c_status.source_pool_namespace),
1633 'source_image_name' : decode_cstr(c_status.source_image_name),
1634 'source_image_id' : decode_cstr(c_status.source_image_id),
1635 'dest_pool_id' : c_status.source_pool_id,
1636 'dest_pool_namespace' : decode_cstr(c_status.dest_pool_namespace),
1637 'dest_image_name' : decode_cstr(c_status.dest_image_name),
1638 'dest_image_id' : decode_cstr(c_status.dest_image_id),
1639 'state' : c_status.state,
1640 'state_description' : decode_cstr(c_status.state_description)
1643 rbd_migration_status_cleanup(&c_status)
1647 def mirror_mode_get(self, ioctx):
1649 Get pool mirror mode.
1651 :param ioctx: determines which RADOS pool is read
1652 :type ioctx: :class:`rados.Ioctx`
1653 :returns: int - pool mirror mode
1656 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1657 rbd_mirror_mode_t mirror_mode
1659 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1661 raise make_ex(ret, 'error getting mirror mode')
1664 def mirror_mode_set(self, ioctx, mirror_mode):
1666 Set pool mirror mode.
1668 :param ioctx: determines which RADOS pool is written
1669 :type ioctx: :class:`rados.Ioctx`
1670 :param mirror_mode: mirror mode to set
1671 :type mirror_mode: int
1674 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1675 rbd_mirror_mode_t _mirror_mode = mirror_mode
1677 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1679 raise make_ex(ret, 'error setting mirror mode')
1681 def mirror_peer_add(self, ioctx, cluster_name, client_name):
1685 :param ioctx: determines which RADOS pool is used
1686 :type ioctx: :class:`rados.Ioctx`
1687 :param cluster_name: mirror peer cluster name
1688 :type cluster_name: str
1689 :param client_name: mirror peer client name
1690 :type client_name: str
1691 :returns: str - peer uuid
1693 cluster_name = cstr(cluster_name, 'cluster_name')
1694 client_name = cstr(client_name, 'client_name')
1696 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1698 size_t _uuid_max_length = 512
1699 char *_cluster_name = cluster_name
1700 char *_client_name = client_name
1702 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1703 ret = rbd_mirror_peer_add(_ioctx, _uuid, _uuid_max_length,
1704 _cluster_name, _client_name)
1706 raise make_ex(ret, 'error adding mirror peer')
1707 return decode_cstr(_uuid)
1711 def mirror_peer_remove(self, ioctx, uuid):
1715 :param ioctx: determines which RADOS pool is used
1716 :type ioctx: :class:`rados.Ioctx`
1717 :param uuid: peer uuid
1720 uuid = cstr(uuid, 'uuid')
1722 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1725 ret = rbd_mirror_peer_remove(_ioctx, _uuid)
1727 raise make_ex(ret, 'error removing mirror peer')
1729 def mirror_peer_list(self, ioctx):
1731 Iterate over the peers of a pool.
1733 :param ioctx: determines which RADOS pool is read
1734 :type ioctx: :class:`rados.Ioctx`
1735 :returns: :class:`MirrorPeerIterator`
1737 return MirrorPeerIterator(ioctx)
1739 def mirror_peer_set_client(self, ioctx, uuid, client_name):
1741 Set mirror peer client name
1743 :param ioctx: determines which RADOS pool is written
1744 :type ioctx: :class:`rados.Ioctx`
1745 :param uuid: uuid of the mirror peer
1747 :param client_name: client name of the mirror peer to set
1748 :type client_name: str
1750 uuid = cstr(uuid, 'uuid')
1751 client_name = cstr(client_name, 'client_name')
1753 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1755 char *_client_name = client_name
1757 ret = rbd_mirror_peer_set_client(_ioctx, _uuid, _client_name)
1759 raise make_ex(ret, 'error setting mirror peer client')
1761 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
1763 Set mirror peer cluster name
1765 :param ioctx: determines which RADOS pool is written
1766 :type ioctx: :class:`rados.Ioctx`
1767 :param uuid: uuid of the mirror peer
1769 :param cluster_name: cluster name of the mirror peer to set
1770 :type cluster_name: str
1772 uuid = cstr(uuid, 'uuid')
1773 cluster_name = cstr(cluster_name, 'cluster_name')
1775 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1777 char *_cluster_name = cluster_name
1779 ret = rbd_mirror_peer_set_cluster(_ioctx, _uuid, _cluster_name)
1781 raise make_ex(ret, 'error setting mirror peer cluster')
1783 def mirror_peer_get_attributes(self, ioctx, uuid):
1785 Get optional mirror peer attributes
1787 :param ioctx: determines which RADOS pool is written
1788 :type ioctx: :class:`rados.Ioctx`
1789 :param uuid: uuid of the mirror peer
1792 :returns: dict - contains the following keys:
1794 * ``mon_host`` (str) - monitor addresses
1796 * ``key`` (str) - CephX key
1798 uuid = cstr(uuid, 'uuid')
1800 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1804 size_t _keys_size = 512
1805 size_t _vals_size = 512
1809 _keys = <char *>realloc_chk(_keys, _keys_size)
1810 _vals = <char *>realloc_chk(_vals, _vals_size)
1812 ret = rbd_mirror_peer_get_attributes(_ioctx, _uuid, _keys,
1814 &_vals_size, &_count)
1817 elif ret != -errno.ERANGE:
1818 raise make_ex(ret, 'error getting mirror peer attributes')
1819 keys = [decode_cstr(x) for x in _keys[:_keys_size].split(b'\0')[:-1]]
1820 vals = [decode_cstr(x) for x in _vals[:_vals_size].split(b'\0')[:-1]]
1821 return dict(zip(keys, vals))
1826 def mirror_peer_set_attributes(self, ioctx, uuid, attributes):
1828 Set optional mirror peer attributes
1830 :param ioctx: determines which RADOS pool is written
1831 :type ioctx: :class:`rados.Ioctx`
1832 :param uuid: uuid of the mirror peer
1834 :param attributes: 'mon_host' and 'key' attributes
1835 :type attributes: dict
1837 uuid = cstr(uuid, 'uuid')
1838 keys_str = b'\0'.join([cstr(x[0], 'key') for x in attributes.items()])
1839 vals_str = b'\0'.join([cstr(x[1], 'val') for x in attributes.items()])
1841 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1843 char *_keys = keys_str
1844 char *_vals = vals_str
1845 size_t _count = len(attributes)
1848 ret = rbd_mirror_peer_set_attributes(_ioctx, _uuid, _keys, _vals,
1851 raise make_ex(ret, 'error setting mirror peer attributes')
1853 def mirror_image_status_list(self, ioctx):
1855 Iterate over the mirror image statuses of a pool.
1857 :param ioctx: determines which RADOS pool is read
1858 :type ioctx: :class:`rados.Ioctx`
1859 :returns: :class:`MirrorImageStatusIterator`
1861 return MirrorImageStatusIterator(ioctx)
1863 def mirror_image_status_summary(self, ioctx):
1865 Get mirror image status summary of a pool.
1867 :param ioctx: determines which RADOS pool is read
1868 :type ioctx: :class:`rados.Ioctx`
1869 :returns: list - a list of (state, count) tuples
1872 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1873 rbd_mirror_image_status_state_t *states = NULL
1877 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
1878 sizeof(rbd_mirror_image_status_state_t) * maxlen)
1879 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
1881 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
1884 raise make_ex(ret, 'error getting mirror image status summary')
1885 return [(states[i], counts[i]) for i in range(maxlen)]
1890 def mirror_image_instance_id_list(self, ioctx):
1892 Iterate over the mirror image instance ids of a pool.
1894 :param ioctx: determines which RADOS pool is read
1895 :type ioctx: :class:`rados.Ioctx`
1896 :returns: :class:`MirrorImageInstanceIdIterator`
1898 return MirrorImageInstanceIdIterator(ioctx)
1900 def pool_metadata_get(self, ioctx, key):
1902 Get pool metadata for the given key.
1904 :param ioctx: determines which RADOS pool is read
1905 :type ioctx: :class:`rados.Ioctx`
1906 :param key: metadata key
1908 :returns: str - metadata value
1910 key = cstr(key, 'key')
1912 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1919 value = <char *>realloc_chk(value, size)
1921 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
1922 if ret != -errno.ERANGE:
1924 if ret == -errno.ENOENT:
1925 raise KeyError('no metadata %s' % (key))
1927 raise make_ex(ret, 'error getting metadata %s' % (key))
1928 return decode_cstr(value)
1932 def pool_metadata_set(self, ioctx, key, value):
1934 Set pool metadata for the given key.
1936 :param ioctx: determines which RADOS pool is read
1937 :type ioctx: :class:`rados.Ioctx`
1938 :param key: metadata key
1940 :param value: metadata value
1943 key = cstr(key, 'key')
1944 value = cstr(value, 'value')
1946 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1948 char *_value = value
1950 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
1953 raise make_ex(ret, 'error setting metadata %s' % (key))
1955 def pool_metadata_remove(self, ioctx, key):
1957 Remove pool metadata for the given key.
1959 :param ioctx: determines which RADOS pool is read
1960 :type ioctx: :class:`rados.Ioctx`
1961 :param key: metadata key
1963 :returns: str - metadata value
1965 key = cstr(key, 'key')
1967 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1970 ret = rbd_pool_metadata_remove(_ioctx, _key)
1972 if ret == -errno.ENOENT:
1973 raise KeyError('no metadata %s' % (key))
1975 raise make_ex(ret, 'error removing metadata %s' % (key))
1977 def pool_metadata_list(self, ioctx):
1981 :returns: :class:`PoolMetadataIterator`
1983 return PoolMetadataIterator(ioctx)
1985 def config_list(self, ioctx):
1987 List pool-level config overrides.
1989 :returns: :class:`ConfigPoolIterator`
1991 return ConfigPoolIterator(ioctx)
1993 def group_create(self, ioctx, name):
1997 :param ioctx: determines which RADOS pool is used
1998 :type ioctx: :class:`rados.Ioctx`
1999 :param name: the name of the group
2001 :raises: :class:`ObjectExists`
2002 :raises: :class:`InvalidArgument`
2003 :raises: :class:`FunctionNotSupported`
2005 name = cstr(name, 'name')
2008 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2010 ret = rbd_group_create(_ioctx, _name)
2012 raise make_ex(ret, 'error creating group %s' % name, group_errno_to_exception)
2014 def group_remove(self, ioctx, name):
2016 Delete an RBD group. This may take a long time, since it does
2017 not return until every image in the group has been removed
2020 :param ioctx: determines which RADOS pool the group is in
2021 :type ioctx: :class:`rados.Ioctx`
2022 :param name: the name of the group to remove
2024 :raises: :class:`ObjectNotFound`
2025 :raises: :class:`InvalidArgument`
2026 :raises: :class:`FunctionNotSupported`
2028 name = cstr(name, 'name')
2030 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2033 ret = rbd_group_remove(_ioctx, _name)
2035 raise make_ex(ret, 'error removing group', group_errno_to_exception)
2037 def group_list(self, ioctx):
2041 :param ioctx: determines which RADOS pool is read
2042 :type ioctx: :class:`rados.Ioctx`
2043 :returns: list -- a list of groups names
2044 :raises: :class:`FunctionNotSupported`
2047 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2049 char *c_names = NULL
2052 c_names = <char *>realloc_chk(c_names, size)
2054 ret = rbd_group_list(_ioctx, c_names, &size)
2057 elif ret != -errno.ERANGE:
2058 raise make_ex(ret, 'error listing groups', group_errno_to_exception)
2059 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
2064 def group_rename(self, ioctx, src, dest):
2066 Rename an RBD group.
2068 :param ioctx: determines which RADOS pool the group is in
2069 :type ioctx: :class:`rados.Ioctx`
2070 :param src: the current name of the group
2072 :param dest: the new name of the group
2074 :raises: :class:`ObjectExists`
2075 :raises: :class:`ObjectNotFound`
2076 :raises: :class:`InvalidArgument`
2077 :raises: :class:`FunctionNotSupported`
2079 src = cstr(src, 'src')
2080 dest = cstr(dest, 'dest')
2082 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2086 ret = rbd_group_rename(_ioctx, _src, _dest)
2088 raise make_ex(ret, 'error renaming group')
2090 def namespace_create(self, ioctx, name):
2092 Create an RBD namespace within a pool
2094 :param ioctx: determines which RADOS pool
2095 :type ioctx: :class:`rados.Ioctx`
2096 :param name: namespace name
2099 name = cstr(name, 'name')
2101 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2102 const char *_name = name
2104 ret = rbd_namespace_create(_ioctx, _name)
2106 raise make_ex(ret, 'error creating namespace')
2108 def namespace_remove(self, ioctx, name):
2110 Remove an RBD namespace from a pool
2112 :param ioctx: determines which RADOS pool
2113 :type ioctx: :class:`rados.Ioctx`
2114 :param name: namespace name
2117 name = cstr(name, 'name')
2119 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2120 const char *_name = name
2122 ret = rbd_namespace_remove(_ioctx, _name)
2124 raise make_ex(ret, 'error removing namespace')
2126 def namespace_exists(self, ioctx, name):
2128 Verifies if a namespace exists within a pool
2130 :param ioctx: determines which RADOS pool
2131 :type ioctx: :class:`rados.Ioctx`
2132 :param name: namespace name
2134 :returns: bool - true if namespace exists
2136 name = cstr(name, 'name')
2138 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2139 const char *_name = name
2140 bint _exists = False
2142 ret = rbd_namespace_exists(_ioctx, _name, &_exists)
2144 raise make_ex(ret, 'error verifying namespace')
2145 return bool(_exists != 0)
2147 def namespace_list(self, ioctx):
2149 List all namespaces within a pool
2151 :param ioctx: determines which RADOS pool
2152 :type ioctx: :class:`rados.Ioctx`
2153 :returns: list - collection of namespace names
2156 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2161 _names = <char *>realloc_chk(_names, _size)
2163 ret = rbd_namespace_list(_ioctx, _names, &_size)
2166 elif ret != -errno.ERANGE:
2167 raise make_ex(ret, 'error listing namespaces')
2168 return [decode_cstr(name) for name in _names[:_size].split(b'\0')
2173 def pool_init(self, ioctx, force):
2175 Initialize an RBD pool
2176 :param ioctx: determines which RADOS pool
2177 :type ioctx: :class:`rados.Ioctx`
2178 :param force: force init
2182 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2185 ret = rbd_pool_init(_ioctx, _force)
2187 raise make_ex(ret, 'error initializing pool')
2189 def pool_stats_get(self, ioctx):
2191 Return RBD pool stats
2193 :param ioctx: determines which RADOS pool
2194 :type ioctx: :class:`rados.Ioctx`
2195 :returns: dict - contains the following keys:
2197 * ``image_count`` (int) - image count
2199 * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
2201 * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
2203 * ``image_snap_count`` (int) - image snap count
2205 * ``trash_count`` (int) - trash image count
2207 * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
2209 * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
2211 * ``trash_snap_count`` (int) - trash snap count
2215 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2216 uint64_t _image_count = 0
2217 uint64_t _image_provisioned_bytes = 0
2218 uint64_t _image_max_provisioned_bytes = 0
2219 uint64_t _image_snap_count = 0
2220 uint64_t _trash_count = 0
2221 uint64_t _trash_provisioned_bytes = 0
2222 uint64_t _trash_max_provisioned_bytes = 0
2223 uint64_t _trash_snap_count = 0
2224 rbd_pool_stats_t _stats
2226 rbd_pool_stats_create(&_stats)
2227 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
2229 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
2230 &_image_provisioned_bytes)
2231 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
2232 &_image_max_provisioned_bytes)
2233 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
2235 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
2237 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
2238 &_trash_provisioned_bytes)
2239 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
2240 &_trash_max_provisioned_bytes)
2241 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
2245 ret = rbd_pool_stats_get(_ioctx, _stats)
2247 raise make_ex(ret, 'error retrieving pool stats')
2249 return {'image_count': _image_count,
2250 'image_provisioned_bytes': _image_provisioned_bytes,
2251 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
2252 'image_snap_count': _image_snap_count,
2253 'trash_count': _trash_count,
2254 'trash_provisioned_bytes': _trash_provisioned_bytes,
2255 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
2256 'trash_snap_count': _trash_snap_count}
2258 rbd_pool_stats_destroy(_stats)
2261 cdef class MirrorPeerIterator(object):
2263 Iterator over mirror peer info for a pool.
2265 Yields a dictionary containing information about a peer.
2269 * ``uuid`` (str) - uuid of the peer
2271 * ``cluster_name`` (str) - cluster name of the peer
2273 * ``client_name`` (str) - client name of the peer
2277 rbd_mirror_peer_t *peers
2280 def __init__(self, ioctx):
2282 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2286 self.peers = <rbd_mirror_peer_t *>realloc_chk(
2287 self.peers, self.num_peers * sizeof(rbd_mirror_peer_t))
2289 ret = rbd_mirror_peer_list(_ioctx, self.peers, &self.num_peers)
2291 if ret == -errno.ERANGE:
2294 raise make_ex(ret, 'error listing peers')
2298 for i in range(self.num_peers):
2300 'uuid' : decode_cstr(self.peers[i].uuid),
2301 'cluster_name' : decode_cstr(self.peers[i].cluster_name),
2302 'client_name' : decode_cstr(self.peers[i].client_name),
2305 def __dealloc__(self):
2307 rbd_mirror_peer_list_cleanup(self.peers, self.num_peers)
2310 cdef class MirrorImageStatusIterator(object):
2312 Iterator over mirror image status for a pool.
2314 Yields a dictionary containing mirror status of an image.
2318 * ``name`` (str) - mirror image name
2320 * ``id`` (str) - mirror image id
2322 * `info` (dict) - mirror image info
2324 * `state` (int) - mirror state
2326 * `description` (str) - status description
2328 * `last_update` (datetime) - last status update time
2330 * ``up`` (bool) - is mirroring agent up
2338 rbd_mirror_image_status_t *images
2341 def __init__(self, ioctx):
2342 self.ioctx = convert_ioctx(ioctx)
2343 self.max_read = 1024
2344 self.last_read = strdup("")
2345 self.image_ids = <char **>realloc_chk(NULL,
2346 sizeof(char *) * self.max_read)
2347 self.images = <rbd_mirror_image_status_t *>realloc_chk(NULL,
2348 sizeof(rbd_mirror_image_status_t) * self.max_read)
2350 self.get_next_chunk()
2353 while self.size > 0:
2354 for i in range(self.size):
2356 'name' : decode_cstr(self.images[i].name),
2357 'id' : decode_cstr(self.image_ids[i]),
2359 'global_id' : decode_cstr(self.images[i].info.global_id),
2360 'state' : self.images[i].info.state,
2362 'state' : self.images[i].state,
2363 'description' : decode_cstr(self.images[i].description),
2364 'last_update' : datetime.utcfromtimestamp(self.images[i].last_update),
2365 'up' : self.images[i].up,
2367 if self.size < self.max_read:
2369 self.get_next_chunk()
2371 def __dealloc__(self):
2372 rbd_mirror_image_status_list_cleanup(self.image_ids, self.images,
2375 free(self.last_read)
2377 free(self.image_ids)
2381 def get_next_chunk(self):
2383 rbd_mirror_image_status_list_cleanup(self.image_ids, self.images,
2387 ret = rbd_mirror_image_status_list(self.ioctx, self.last_read,
2388 self.max_read, self.image_ids,
2389 self.images, &self.size)
2391 raise make_ex(ret, 'error listing mirror images status')
2393 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2394 free(self.last_read)
2395 self.last_read = strdup(last_read)
2397 free(self.last_read)
2398 self.last_read = strdup("")
2400 cdef class MirrorImageInstanceIdIterator(object):
2402 Iterator over mirror image instance id for a pool.
2404 Yields ``(image_id, instance_id)`` tuple.
2415 def __init__(self, ioctx):
2416 self.ioctx = convert_ioctx(ioctx)
2417 self.max_read = 1024
2418 self.last_read = strdup("")
2419 self.image_ids = <char **>realloc_chk(NULL,
2420 sizeof(char *) * self.max_read)
2421 self.instance_ids = <char **>realloc_chk(NULL,
2422 sizeof(char *) * self.max_read)
2424 self.get_next_chunk()
2427 while self.size > 0:
2428 for i in range(self.size):
2429 yield (decode_cstr(self.image_ids[i]),
2430 decode_cstr(self.instance_ids[i]))
2431 if self.size < self.max_read:
2433 self.get_next_chunk()
2435 def __dealloc__(self):
2436 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2437 self.instance_ids, self.size)
2439 free(self.last_read)
2441 free(self.image_ids)
2442 if self.instance_ids:
2443 free(self.instance_ids)
2445 def get_next_chunk(self):
2447 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2452 ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read,
2458 raise make_ex(ret, 'error listing mirror images instance ids')
2460 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2461 free(self.last_read)
2462 self.last_read = strdup(last_read)
2464 free(self.last_read)
2465 self.last_read = strdup("")
2467 cdef class PoolMetadataIterator(object):
2469 Iterator over pool metadata list.
2471 Yields ``(key, value)`` tuple.
2473 * ``key`` (str) - metadata key
2474 * ``value`` (str) - metadata value
2483 def __init__(self, ioctx):
2484 self.ioctx = convert_ioctx(ioctx)
2485 self.last_read = strdup("")
2487 self.get_next_chunk()
2490 while len(self.next_chunk) > 0:
2491 for pair in self.next_chunk:
2493 if len(self.next_chunk) < self.max_read:
2495 self.get_next_chunk()
2497 def __dealloc__(self):
2499 free(self.last_read)
2501 def get_next_chunk(self):
2504 size_t keys_size = 4096
2506 size_t vals_size = 4096
2509 c_keys = <char *>realloc_chk(c_keys, keys_size)
2510 c_vals = <char *>realloc_chk(c_vals, vals_size)
2512 ret = rbd_pool_metadata_list(self.ioctx, self.last_read,
2513 self.max_read, c_keys,
2514 &keys_size, c_vals, &vals_size)
2517 elif ret != -errno.ERANGE:
2518 raise make_ex(ret, 'error listing metadata')
2519 keys = [decode_cstr(key) for key in
2520 c_keys[:keys_size].split(b'\0') if key]
2521 vals = [decode_cstr(val) for val in
2522 c_vals[:vals_size].split(b'\0') if val]
2524 last_read = cstr(keys[-1], 'last_read')
2525 free(self.last_read)
2526 self.last_read = strdup(last_read)
2527 self.next_chunk = list(zip(keys, vals))
2532 cdef class ConfigPoolIterator(object):
2534 Iterator over pool-level overrides for a pool.
2536 Yields a dictionary containing information about an override.
2540 * ``name`` (str) - override name
2542 * ``value`` (str) - override value
2544 * ``source`` (str) - override source
2548 rbd_config_option_t *options
2551 def __init__(self, ioctx):
2553 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2555 self.num_options = 32
2557 self.options = <rbd_config_option_t *>realloc_chk(
2558 self.options, self.num_options * sizeof(rbd_config_option_t))
2560 ret = rbd_config_pool_list(_ioctx, self.options, &self.num_options)
2562 if ret == -errno.ERANGE:
2564 self.num_options = 0
2565 raise make_ex(ret, 'error listing config options')
2569 for i in range(self.num_options):
2571 'name' : decode_cstr(self.options[i].name),
2572 'value' : decode_cstr(self.options[i].value),
2573 'source' : self.options[i].source,
2576 def __dealloc__(self):
2578 rbd_config_pool_list_cleanup(self.options, self.num_options)
2581 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
2582 except? -9000 with gil:
2583 # Make sure that if we wound up with an exception from a previous callback,
2584 # we stop calling back (just in case librbd ever fails to bail out on the
2585 # first negative return, as older versions did)
2586 if exc.PyErr_Occurred():
2588 ret = (<object>cb)(offset, length, bool(write))
2593 cdef class Group(object):
2595 This class represents an RBD group. It is used to interact with
2596 snapshots and images members.
2603 cdef rados_ioctx_t _ioctx
2605 def __init__(self, ioctx, name):
2606 name = cstr(name, 'name')
2609 self._ioctx = convert_ioctx(ioctx)
2612 def __enter__(self):
2615 def __exit__(self, type_, value, traceback):
2618 def add_image(self, image_ioctx, image_name):
2620 Add an image to a group.
2622 :param image_ioctx: determines which RADOS pool the image belongs to.
2623 :type ioctx: :class:`rados.Ioctx`
2624 :param name: the name of the image to add
2627 :raises: :class:`ObjectNotFound`
2628 :raises: :class:`ObjectExists`
2629 :raises: :class:`InvalidArgument`
2630 :raises: :class:`FunctionNotSupported`
2632 image_name = cstr(image_name, 'image_name')
2634 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
2635 char *_image_name = image_name
2637 ret = rbd_group_image_add(self._ioctx, self._name, _image_ioctx, _image_name)
2639 raise make_ex(ret, 'error adding image to group', group_errno_to_exception)
2641 def remove_image(self, image_ioctx, image_name):
2643 Remove an image from a group.
2645 :param image_ioctx: determines which RADOS pool the image belongs to.
2646 :type ioctx: :class:`rados.Ioctx`
2647 :param name: the name of the image to remove
2650 :raises: :class:`ObjectNotFound`
2651 :raises: :class:`InvalidArgument`
2652 :raises: :class:`FunctionNotSupported`
2654 image_name = cstr(image_name, 'image_name')
2656 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
2657 char *_image_name = image_name
2659 ret = rbd_group_image_remove(self._ioctx, self._name, _image_ioctx, _image_name)
2661 raise make_ex(ret, 'error removing image from group', group_errno_to_exception)
2664 def list_images(self):
2666 Iterate over the images of a group.
2668 :returns: :class:`GroupImageIterator`
2670 return GroupImageIterator(self)
2672 def create_snap(self, snap_name):
2674 Create a snapshot for the group.
2676 :param snap_name: the name of the snapshot to create
2679 :raises: :class:`ObjectNotFound`
2680 :raises: :class:`ObjectExists`
2681 :raises: :class:`InvalidArgument`
2682 :raises: :class:`FunctionNotSupported`
2684 snap_name = cstr(snap_name, 'snap_name')
2686 char *_snap_name = snap_name
2688 ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
2690 raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
2692 def remove_snap(self, snap_name):
2694 Remove a snapshot from the group.
2696 :param snap_name: the name of the snapshot to remove
2699 :raises: :class:`ObjectNotFound`
2700 :raises: :class:`InvalidArgument`
2701 :raises: :class:`FunctionNotSupported`
2703 snap_name = cstr(snap_name, 'snap_name')
2705 char *_snap_name = snap_name
2707 ret = rbd_group_snap_remove(self._ioctx, self._name, _snap_name)
2709 raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
2711 def rename_snap(self, old_snap_name, new_snap_name):
2713 Rename group's snapshot.
2715 :raises: :class:`ObjectNotFound`
2716 :raises: :class:`ObjectExists`
2717 :raises: :class:`InvalidArgument`
2718 :raises: :class:`FunctionNotSupported`
2721 old_snap_name = cstr(old_snap_name, 'old_snap_name')
2722 new_snap_name = cstr(new_snap_name, 'new_snap_name')
2724 char *_old_snap_name = old_snap_name
2725 char *_new_snap_name = new_snap_name
2727 ret = rbd_group_snap_rename(self._ioctx, self._name, _old_snap_name,
2730 raise make_ex(ret, 'error renaming group snapshot',
2731 group_errno_to_exception)
2733 def list_snaps(self):
2735 Iterate over the images of a group.
2737 :returns: :class:`GroupSnapIterator`
2739 return GroupSnapIterator(self)
2741 def rollback_to_snap(self, name):
2743 Rollback group to snapshot.
2745 :param name: the group snapshot to rollback to
2747 :raises: :class:`ObjectNotFound`
2748 :raises: :class:`IOError`
2750 name = cstr(name, 'name')
2751 cdef char *_name = name
2753 ret = rbd_group_snap_rollback(self._ioctx, self._name, _name)
2755 raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
2757 cdef class Image(object):
2759 This class represents an RBD image. It is used to perform I/O on
2760 the image and interact with snapshots.
2762 **Note**: Any method of this class may raise :class:`ImageNotFound`
2763 if the image has been deleted.
2765 cdef rbd_image_t image
2769 cdef rados_ioctx_t _ioctx
2771 def __init__(self, ioctx, name=None, snapshot=None,
2772 read_only=False, image_id=None):
2774 Open the image at the given snapshot.
2775 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
2777 If a snapshot is specified, the image will be read-only, unless
2778 :func:`Image.set_snap` is called later.
2780 If read-only mode is used, metadata for the :class:`Image`
2781 object (such as which snapshots exist) may become obsolete. See
2782 the C api for more details.
2784 To clean up from opening the image, :func:`Image.close` should
2785 be called. For ease of use, this is done automatically when
2786 an :class:`Image` is used as a context manager (see :pep:`343`).
2788 :param ioctx: determines which RADOS pool the image is in
2789 :type ioctx: :class:`rados.Ioctx`
2790 :param name: the name of the image
2792 :param snapshot: which snapshot to read from
2793 :type snaphshot: str
2794 :param read_only: whether to open the image in read-only mode
2795 :type read_only: bool
2796 :param image_id: the id of the image
2799 name = cstr(name, 'name', opt=True)
2800 image_id = cstr(image_id, 'image_id', opt=True)
2801 snapshot = cstr(snapshot, 'snapshot', opt=True)
2803 if name is not None and image_id is not None:
2804 raise InvalidArgument("only need to specify image name or image id")
2805 elif name is None and image_id is None:
2806 raise InvalidArgument("image name or image id was not specified")
2807 elif name is not None:
2810 self.name = image_id
2811 # Keep around a reference to the ioctx, so it won't get deleted
2814 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2815 char *_name = opt_str(name)
2816 char *_image_id = opt_str(image_id)
2817 char *_snapshot = opt_str(snapshot)
2820 if name is not None:
2821 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
2823 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
2826 if name is not None:
2827 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
2829 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
2831 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
2834 self.name = self.get_name()
2836 def __enter__(self):
2839 def __exit__(self, type_, value, traceback):
2841 Closes the image. See :func:`close`
2846 def __get_completion(self, oncomplete):
2848 Constructs a completion to use with asynchronous operations
2850 :param oncomplete: callback for the completion
2852 :raises: :class:`Error`
2853 :returns: completion object
2856 completion_obj = Completion(self, oncomplete)
2859 rbd_completion_t completion
2860 PyObject* p_completion_obj= <PyObject*>completion_obj
2863 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
2866 raise make_ex(ret, "error getting a completion")
2868 completion_obj.rbd_comp = completion
2869 return completion_obj
2873 Release the resources used by this image object.
2875 After this is called, this object should not be used.
2880 ret = rbd_close(self.image)
2882 raise make_ex(ret, 'error while closing image %s' % (
2885 def __dealloc__(self):
2889 return "rbd.Image(ioctx, %r)" % self.name
2891 def resize(self, size, allow_shrink=True):
2893 Change the size of the image, allow shrink.
2895 :param size: the new size of the image
2897 :param allow_shrink: permit shrinking
2898 :type allow_shrink: bool
2900 old_size = self.size()
2901 if old_size == size:
2903 if not allow_shrink and old_size > size:
2904 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
2906 uint64_t _size = size
2907 bint _allow_shrink = allow_shrink
2908 librbd_progress_fn_t prog_cb = &no_op_progress_callback
2910 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
2912 raise make_ex(ret, 'error resizing image %s' % self.name)
2916 Get information about the image. Currently parent pool and
2917 parent name are always -1 and ''.
2919 :returns: dict - contains the following keys:
2921 * ``size`` (int) - the size of the image in bytes
2923 * ``obj_size`` (int) - the size of each object that comprises the
2926 * ``num_objs`` (int) - the number of objects in the image
2928 * ``order`` (int) - log_2(object_size)
2930 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
2933 * ``parent_pool`` (int) - deprecated
2935 * ``parent_name`` (str) - deprecated
2937 See also :meth:`format` and :meth:`features`.
2940 cdef rbd_image_info_t info
2942 ret = rbd_stat(self.image, &info, sizeof(info))
2944 raise make_ex(ret, 'error getting info for image %s' % self.name)
2947 'obj_size' : info.obj_size,
2948 'num_objs' : info.num_objs,
2949 'order' : info.order,
2950 'block_name_prefix' : decode_cstr(info.block_name_prefix),
2951 'parent_pool' : info.parent_pool,
2952 'parent_name' : info.parent_name
2957 Get the RBD image name
2959 :returns: str - image name
2962 int ret = -errno.ERANGE
2964 char *image_name = NULL
2966 while ret == -errno.ERANGE:
2967 image_name = <char *>realloc_chk(image_name, size)
2969 ret = rbd_get_name(self.image, image_name, &size)
2972 raise make_ex(ret, 'error getting name for image %s' % self.name)
2973 return decode_cstr(image_name)
2979 Get the RBD v2 internal image id
2981 :returns: str - image id
2984 int ret = -errno.ERANGE
2986 char *image_id = NULL
2988 while ret == -errno.ERANGE and size <= 4096:
2989 image_id = <char *>realloc_chk(image_id, size)
2991 ret = rbd_get_id(self.image, image_id, size)
2992 if ret == -errno.ERANGE:
2996 raise make_ex(ret, 'error getting id for image %s' % self.name)
2997 return decode_cstr(image_id)
3001 def block_name_prefix(self):
3003 Get the RBD block name prefix
3005 :returns: str - block name prefix
3008 int ret = -errno.ERANGE
3012 while ret == -errno.ERANGE and size <= 4096:
3013 prefix = <char *>realloc_chk(prefix, size)
3015 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3016 if ret == -errno.ERANGE:
3020 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3021 return decode_cstr(prefix)
3025 def data_pool_id(self):
3027 Get the pool id of the pool where the data of this RBD image is stored.
3029 :returns: int - the pool id
3031 return rbd_get_data_pool_id(self.image)
3033 def parent_info(self):
3035 Get information about a cloned image's parent (if any)
3037 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3039 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3042 rbd_linked_image_spec_t parent_spec
3043 rbd_snap_spec_t snap_spec
3045 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3047 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3049 result = (decode_cstr(parent_spec.pool_name),
3050 decode_cstr(parent_spec.image_name),
3051 decode_cstr(snap_spec.name))
3053 rbd_linked_image_spec_cleanup(&parent_spec)
3054 rbd_snap_spec_cleanup(&snap_spec)
3057 def parent_id(self):
3059 Get image id of a cloned image's parent (if any)
3061 :returns: str - the parent id
3062 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3065 rbd_linked_image_spec_t parent_spec
3066 rbd_snap_spec_t snap_spec
3068 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3070 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3072 result = decode_cstr(parent_spec.image_id)
3074 rbd_linked_image_spec_cleanup(&parent_spec)
3075 rbd_snap_spec_cleanup(&snap_spec)
3078 def old_format(self):
3080 Find out whether the image uses the old RBD format.
3082 :returns: bool - whether the image uses the old RBD format
3086 ret = rbd_get_old_format(self.image, &old)
3088 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3093 Get the size of the image. If open to a snapshot, returns the
3094 size of that snapshot.
3096 :returns: int - the size of the image in bytes
3098 cdef uint64_t image_size
3100 ret = rbd_get_size(self.image, &image_size)
3102 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3107 Get the features bitmask of the image.
3109 :returns: int - the features bitmask of the image
3111 cdef uint64_t features
3113 ret = rbd_get_features(self.image, &features)
3115 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3118 def update_features(self, features, enabled):
3120 Update the features bitmask of the image by enabling/disabling
3121 a single feature. The feature must support the ability to be
3122 dynamically enabled/disabled.
3124 :param features: feature bitmask to enable/disable
3126 :param enabled: whether to enable/disable the feature
3128 :raises: :class:`InvalidArgument`
3131 uint64_t _features = features
3132 uint8_t _enabled = bool(enabled)
3134 ret = rbd_update_features(self.image, _features, _enabled)
3136 raise make_ex(ret, 'error updating features for image %s' %
3139 def op_features(self):
3141 Get the op features bitmask of the image.
3143 :returns: int - the op features bitmask of the image
3145 cdef uint64_t op_features
3147 ret = rbd_get_op_features(self.image, &op_features)
3149 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3154 Get the number of overlapping bytes between the image and its parent
3155 image. If open to a snapshot, returns the overlap between the snapshot
3156 and the parent image.
3158 :returns: int - the overlap in bytes
3159 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3161 cdef uint64_t overlap
3163 ret = rbd_get_overlap(self.image, &overlap)
3165 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3170 Get the flags bitmask of the image.
3172 :returns: int - the flags bitmask of the image
3176 ret = rbd_get_flags(self.image, &flags)
3178 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3183 Get information about the image's group.
3185 :returns: dict - contains the following keys:
3187 * ``pool`` (int) - id of the group pool
3189 * ``name`` (str) - name of the group
3192 cdef rbd_group_info_t info
3194 ret = rbd_get_group(self.image, &info, sizeof(info))
3196 raise make_ex(ret, 'error getting group for image %s' % self.name)
3199 'name' : decode_cstr(info.name)
3201 rbd_group_info_cleanup(&info, sizeof(info))
3204 def is_exclusive_lock_owner(self):
3206 Get the status of the image exclusive lock.
3208 :returns: bool - true if the image is exclusively locked
3212 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3214 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3217 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3218 stripe_unit=None, stripe_count=None, data_pool=None):
3220 Copy the image to another location.
3222 :param dest_ioctx: determines which pool to copy into
3223 :type dest_ioctx: :class:`rados.Ioctx`
3224 :param dest_name: the name of the copy
3225 :type dest_name: str
3226 :param features: bitmask of features to enable; if set, must include layering
3228 :param order: the image is split into (2**order) byte objects
3230 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3231 :type stripe_unit: int
3232 :param stripe_count: objects to stripe over before looping
3233 :type stripe_count: int
3234 :param data_pool: optional separate pool for data blocks
3235 :type data_pool: str
3236 :raises: :class:`TypeError`
3237 :raises: :class:`InvalidArgument`
3238 :raises: :class:`ImageExists`
3239 :raises: :class:`FunctionNotSupported`
3240 :raises: :class:`ArgumentOutOfRange`
3242 dest_name = cstr(dest_name, 'dest_name')
3243 data_pool = cstr(data_pool, 'data_pool', opt=True)
3245 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3246 char *_dest_name = dest_name
3247 rbd_image_options_t opts
3249 rbd_image_options_create(&opts)
3251 if features is not None:
3252 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3254 if order is not None:
3255 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3257 if stripe_unit is not None:
3258 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3260 if stripe_count is not None:
3261 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3263 if data_pool is not None:
3264 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3267 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3269 rbd_image_options_destroy(opts)
3271 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3273 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3274 stripe_unit=None, stripe_count=None, data_pool=None):
3276 Deep copy the image to another location.
3278 :param dest_ioctx: determines which pool to copy into
3279 :type dest_ioctx: :class:`rados.Ioctx`
3280 :param dest_name: the name of the copy
3281 :type dest_name: str
3282 :param features: bitmask of features to enable; if set, must include layering
3284 :param order: the image is split into (2**order) byte objects
3286 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3287 :type stripe_unit: int
3288 :param stripe_count: objects to stripe over before looping
3289 :type stripe_count: int
3290 :param data_pool: optional separate pool for data blocks
3291 :type data_pool: str
3292 :raises: :class:`TypeError`
3293 :raises: :class:`InvalidArgument`
3294 :raises: :class:`ImageExists`
3295 :raises: :class:`FunctionNotSupported`
3296 :raises: :class:`ArgumentOutOfRange`
3298 dest_name = cstr(dest_name, 'dest_name')
3299 data_pool = cstr(data_pool, 'data_pool', opt=True)
3301 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3302 char *_dest_name = dest_name
3303 rbd_image_options_t opts
3305 rbd_image_options_create(&opts)
3307 if features is not None:
3308 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3310 if order is not None:
3311 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3313 if stripe_unit is not None:
3314 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3316 if stripe_count is not None:
3317 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3319 if data_pool is not None:
3320 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3323 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3325 rbd_image_options_destroy(opts)
3327 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3329 def list_snaps(self):
3331 Iterate over the snapshots of an image.
3333 :returns: :class:`SnapIterator`
3335 return SnapIterator(self)
3337 def create_snap(self, name):
3339 Create a snapshot of the image.
3341 :param name: the name of the snapshot
3343 :raises: :class:`ImageExists`
3345 name = cstr(name, 'name')
3346 cdef char *_name = name
3348 ret = rbd_snap_create(self.image, _name)
3350 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3352 def rename_snap(self, srcname, dstname):
3354 rename a snapshot of the image.
3356 :param srcname: the src name of the snapshot
3358 :param dstname: the dst name of the snapshot
3360 :raises: :class:`ImageExists`
3362 srcname = cstr(srcname, 'srcname')
3363 dstname = cstr(dstname, 'dstname')
3365 char *_srcname = srcname
3366 char *_dstname = dstname
3368 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3370 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3372 def remove_snap(self, name):
3374 Delete a snapshot of the image.
3376 :param name: the name of the snapshot
3378 :raises: :class:`IOError`, :class:`ImageBusy`
3380 name = cstr(name, 'name')
3381 cdef char *_name = name
3383 ret = rbd_snap_remove(self.image, _name)
3385 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3387 def remove_snap2(self, name, flags):
3389 Delete a snapshot of the image.
3391 :param name: the name of the snapshot
3392 :param flags: the flags for removal
3394 :raises: :class:`IOError`, :class:`ImageBusy`
3396 name = cstr(name, 'name')
3399 uint32_t _flags = flags
3400 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3402 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
3404 raise make_ex(ret, 'error removing snapshot %s from %s with flags %llx' % (name, self.name, flags))
3406 def remove_snap_by_id(self, snap_id):
3408 Delete a snapshot of the image by its id.
3410 :param id: the id of the snapshot
3412 :raises: :class:`IOError`, :class:`ImageBusy`
3415 uint64_t _snap_id = snap_id
3417 ret = rbd_snap_remove_by_id(self.image, _snap_id)
3419 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
3421 def rollback_to_snap(self, name):
3423 Revert the image to its contents at a snapshot. This is a
3424 potentially expensive operation, since it rolls back each
3425 object individually.
3427 :param name: the snapshot to rollback to
3429 :raises: :class:`IOError`
3431 name = cstr(name, 'name')
3432 cdef char *_name = name
3434 ret = rbd_snap_rollback(self.image, _name)
3436 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
3438 def protect_snap(self, name):
3440 Mark a snapshot as protected. This means it can't be deleted
3441 until it is unprotected.
3443 :param name: the snapshot to protect
3445 :raises: :class:`IOError`, :class:`ImageNotFound`
3447 name = cstr(name, 'name')
3448 cdef char *_name = name
3450 ret = rbd_snap_protect(self.image, _name)
3452 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
3454 def unprotect_snap(self, name):
3456 Mark a snapshot unprotected. This allows it to be deleted if
3459 :param name: the snapshot to unprotect
3461 :raises: :class:`IOError`, :class:`ImageNotFound`
3463 name = cstr(name, 'name')
3464 cdef char *_name = name
3466 ret = rbd_snap_unprotect(self.image, _name)
3468 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
3470 def is_protected_snap(self, name):
3472 Find out whether a snapshot is protected from deletion.
3474 :param name: the snapshot to check
3476 :returns: bool - whether the snapshot is protected
3477 :raises: :class:`IOError`, :class:`ImageNotFound`
3479 name = cstr(name, 'name')
3484 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
3486 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
3487 return is_protected == 1
3489 def get_snap_limit(self):
3491 Get the snapshot limit for an image.
3493 :returns: int - the snapshot limit for an image
3499 ret = rbd_snap_get_limit(self.image, &limit)
3501 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
3504 def set_snap_limit(self, limit):
3506 Set the snapshot limit for an image.
3508 :param limit: the new limit to set
3512 uint64_t _limit = limit
3514 ret = rbd_snap_set_limit(self.image, _limit)
3516 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
3519 def get_snap_timestamp(self, snap_id):
3521 Get the snapshot timestamp for an image.
3522 :param snap_id: the snapshot id of a snap shot
3523 :returns: datetime - the snapshot timestamp for an image
3527 uint64_t _snap_id = snap_id
3529 ret = rbd_snap_get_timestamp(self.image, _snap_id, ×tamp)
3531 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
3532 return datetime.utcfromtimestamp(timestamp.tv_sec)
3534 def remove_snap_limit(self):
3536 Remove the snapshot limit for an image, essentially setting
3537 the limit to the maximum size allowed by the implementation.
3540 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
3542 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
3545 def set_snap(self, name):
3547 Set the snapshot to read from. Writes will raise ReadOnlyImage
3548 while a snapshot is set. Pass None to unset the snapshot
3549 (reads come from the current image) , and allow writing again.
3551 :param name: the snapshot to read from, or None to unset the snapshot
3552 :type name: str or None
3554 name = cstr(name, 'name', opt=True)
3555 cdef char *_name = opt_str(name)
3557 ret = rbd_snap_set(self.image, _name)
3559 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
3561 def set_snap_by_id(self, snap_id):
3563 Set the snapshot to read from. Writes will raise ReadOnlyImage
3564 while a snapshot is set. Pass None to unset the snapshot
3565 (reads come from the current image) , and allow writing again.
3567 :param snap_id: the snapshot to read from, or None to unset the snapshot
3571 snap_id = _LIBRADOS_SNAP_HEAD
3572 cdef int64_t _snap_id = snap_id
3574 ret = rbd_snap_set_by_id(self.image, _snap_id)
3576 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
3578 def read(self, offset, length, fadvise_flags=0):
3580 Read data from the image. Raises :class:`InvalidArgument` if
3581 part of the range specified is outside the image.
3583 :param offset: the offset to start reading at
3585 :param length: how many bytes to read
3587 :param fadvise_flags: fadvise flags for this read
3588 :type fadvise_flags: int
3589 :returns: str - the data read
3590 :raises: :class:`InvalidArgument`, :class:`IOError`
3593 # This usage of the Python API allows us to construct a string
3594 # that librbd directly reads into, avoiding an extra copy. Although
3595 # strings are normally immutable, this usage is explicitly supported
3596 # for freshly created string objects.
3599 uint64_t _offset = offset
3600 size_t _length = length
3601 int _fadvise_flags = fadvise_flags
3602 PyObject* ret_s = NULL
3603 ret_s = PyBytes_FromStringAndSize(NULL, length)
3605 ret_buf = PyBytes_AsString(ret_s)
3607 ret = rbd_read2(self.image, _offset, _length, ret_buf,
3610 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
3612 if ret != <ssize_t>length:
3613 _PyBytes_Resize(&ret_s, ret)
3615 return <object>ret_s
3617 # We DECREF unconditionally: the cast to object above will have
3618 # INCREFed if necessary. This also takes care of exceptions,
3619 # including if _PyString_Resize fails (that will free the string
3620 # itself and set ret_s to NULL, hence XDECREF).
3621 ref.Py_XDECREF(ret_s)
3623 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
3624 include_parent = True, whole_object = False):
3626 Iterate over the changed extents of an image.
3628 This will call iterate_cb with three arguments:
3630 (offset, length, exists)
3632 where the changed extent starts at offset bytes, continues for
3633 length bytes, and is full of data (if exists is True) or zeroes
3634 (if exists is False).
3636 If from_snapshot is None, it is interpreted as the beginning
3637 of time and this generates all allocated extents.
3639 The end version is whatever is currently selected (via set_snap)
3642 iterate_cb may raise an exception, which will abort the diff and will be
3643 propagated to the caller.
3645 Raises :class:`InvalidArgument` if from_snapshot is after
3646 the currently set snapshot.
3648 Raises :class:`ImageNotFound` if from_snapshot is not the name
3649 of a snapshot of the image.
3651 :param offset: start offset in bytes
3653 :param length: size of region to report on, in bytes
3655 :param from_snapshot: starting snapshot name, or None
3656 :type from_snapshot: str or None
3657 :param iterate_cb: function to call for each extent
3658 :type iterate_cb: function acception arguments for offset,
3660 :param include_parent: True if full history diff should include parent
3661 :type include_parent: bool
3662 :param whole_object: True if diff extents should cover whole object
3663 :type whole_object: bool
3664 :raises: :class:`InvalidArgument`, :class:`IOError`,
3665 :class:`ImageNotFound`
3667 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
3669 char *_from_snapshot = opt_str(from_snapshot)
3670 uint64_t _offset = offset, _length = length
3671 uint8_t _include_parent = include_parent
3672 uint8_t _whole_object = whole_object
3674 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
3675 _length, _include_parent, _whole_object,
3676 &diff_iterate_cb, <void *>iterate_cb)
3678 msg = 'error generating diff from snapshot %s' % from_snapshot
3679 raise make_ex(ret, msg)
3681 def write(self, data, offset, fadvise_flags=0):
3683 Write data to the image. Raises :class:`InvalidArgument` if
3684 part of the write would fall outside the image.
3686 :param data: the data to be written
3688 :param offset: where to start writing data
3690 :param fadvise_flags: fadvise flags for this write
3691 :type fadvise_flags: int
3692 :returns: int - the number of bytes written
3693 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
3694 :class:`InvalidArgument`, :class:`IOError`
3696 if not isinstance(data, bytes):
3697 raise TypeError('data must be a byte string')
3699 uint64_t _offset = offset, length = len(data)
3701 int _fadvise_flags = fadvise_flags
3703 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
3705 if ret == <ssize_t>length:
3708 raise make_ex(ret, "error writing to %s" % self.name)
3709 elif ret < <ssize_t>length:
3710 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
3712 raise LogicError("logic error: rbd_write(%s) \
3713 returned %d, but %d was the maximum number of bytes it could have \
3714 written." % (self.name, ret, length))
3716 def discard(self, offset, length):
3718 Trim the range from the image. It will be logically filled
3721 cdef uint64_t _offset = offset, _length = length
3723 ret = rbd_discard(self.image, _offset, _length)
3725 msg = 'error discarding region %d~%d' % (offset, length)
3726 raise make_ex(ret, msg)
3730 Block until all writes are fully flushed if caching is enabled.
3733 ret = rbd_flush(self.image)
3735 raise make_ex(ret, 'error flushing image')
3737 def invalidate_cache(self):
3739 Drop any cached data for the image.
3742 ret = rbd_invalidate_cache(self.image)
3744 raise make_ex(ret, 'error invalidating cache')
3746 def stripe_unit(self):
3748 Return the stripe unit used for the image.
3750 cdef uint64_t stripe_unit
3752 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
3754 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
3757 def stripe_count(self):
3759 Return the stripe count used for the image.
3761 cdef uint64_t stripe_count
3763 ret = rbd_get_stripe_count(self.image, &stripe_count)
3765 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
3768 def create_timestamp(self):
3770 Return the create timestamp for the image.
3775 ret = rbd_get_create_timestamp(self.image, ×tamp)
3777 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
3778 return datetime.utcfromtimestamp(timestamp.tv_sec)
3780 def access_timestamp(self):
3782 Return the access timestamp for the image.
3787 ret = rbd_get_access_timestamp(self.image, ×tamp)
3789 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
3790 return datetime.fromtimestamp(timestamp.tv_sec)
3792 def modify_timestamp(self):
3794 Return the modify timestamp for the image.
3799 ret = rbd_get_modify_timestamp(self.image, ×tamp)
3801 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
3802 return datetime.fromtimestamp(timestamp.tv_sec)
3804 def flatten(self, on_progress=None):
3806 Flatten clone image (copy all blocks from parent to child)
3807 :param on_progress: optional progress callback function
3808 :type on_progress: callback function
3811 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
3812 void *_prog_arg = NULL
3814 _prog_cb = &progress_callback
3815 _prog_arg = <void *>on_progress
3817 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
3819 raise make_ex(ret, "error flattening %s" % self.name)
3821 def sparsify(self, sparse_size):
3823 Reclaim space for zeroed image extents
3826 size_t _sparse_size = sparse_size
3828 ret = rbd_sparsify(self.image, _sparse_size)
3830 raise make_ex(ret, "error sparsifying %s" % self.name)
3832 def rebuild_object_map(self):
3834 Rebuild the object map for the image HEAD or currently set snapshot
3836 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
3838 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
3840 raise make_ex(ret, "error rebuilding object map %s" % self.name)
3842 def list_children(self):
3844 List children of the currently set snapshot (set via set_snap()).
3846 :returns: list - a list of (pool name, image name) tuples
3849 rbd_linked_image_spec_t *children = NULL
3850 size_t num_children = 10
3854 children = <rbd_linked_image_spec_t*>realloc_chk(
3855 children, num_children * sizeof(rbd_linked_image_spec_t))
3857 ret = rbd_list_children3(self.image, children,
3861 elif ret != -errno.ERANGE:
3862 raise make_ex(ret, 'error listing children.')
3864 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
3865 in children[:num_children] if not x.trash]
3868 rbd_linked_image_spec_list_cleanup(children, num_children)
3871 def list_children2(self):
3873 Iterate over the children of the image or its snapshot.
3875 :returns: :class:`ChildIterator`
3877 return ChildIterator(self)
3879 def list_descendants(self):
3881 Iterate over the descendants of the image.
3883 :returns: :class:`ChildIterator`
3885 return ChildIterator(self, True)
3887 def list_lockers(self):
3889 List clients that have locked the image and information
3892 :returns: dict - contains the following keys:
3894 * ``tag`` - the tag associated with the lock (every
3895 additional locker must use the same tag)
3896 * ``exclusive`` - boolean indicating whether the
3897 lock is exclusive or shared
3898 * ``lockers`` - a list of (client, cookie, address)
3902 size_t clients_size = 512, cookies_size = 512
3903 size_t addrs_size = 512, tag_size = 512
3905 char *c_clients = NULL
3906 char *c_cookies = NULL
3907 char *c_addrs = NULL
3912 c_clients = <char *>realloc_chk(c_clients, clients_size)
3913 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
3914 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
3915 c_tag = <char *>realloc_chk(c_tag, tag_size)
3917 ret = rbd_list_lockers(self.image, &exclusive,
3919 c_clients, &clients_size,
3920 c_cookies, &cookies_size,
3921 c_addrs, &addrs_size)
3924 elif ret != -errno.ERANGE:
3925 raise make_ex(ret, 'error listing images')
3928 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
3929 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
3930 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
3932 'tag' : decode_cstr(c_tag),
3933 'exclusive' : exclusive == 1,
3934 'lockers' : list(zip(clients, cookies, addrs)),
3942 def lock_acquire(self, lock_mode):
3944 Acquire a managed lock on the image.
3946 :param lock_mode: lock mode to set
3947 :type lock_mode: int
3948 :raises: :class:`ImageBusy` if the lock could not be acquired
3951 rbd_lock_mode_t _lock_mode = lock_mode
3953 ret = rbd_lock_acquire(self.image, _lock_mode)
3955 raise make_ex(ret, 'error acquiring lock on image')
3957 def lock_release(self):
3959 Release a managed lock on the image that was previously acquired.
3962 ret = rbd_lock_release(self.image)
3964 raise make_ex(ret, 'error releasing lock on image')
3966 def lock_get_owners(self):
3968 Iterate over the lock owners of an image.
3970 :returns: :class:`LockOwnerIterator`
3972 return LockOwnerIterator(self)
3974 def lock_break(self, lock_mode, lock_owner):
3976 Break the image lock held by a another client.
3978 :param lock_owner: the owner of the lock to break
3979 :type lock_owner: str
3981 lock_owner = cstr(lock_owner, 'lock_owner')
3983 rbd_lock_mode_t _lock_mode = lock_mode
3984 char *_lock_owner = lock_owner
3986 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
3988 raise make_ex(ret, 'error breaking lock on image')
3990 def lock_exclusive(self, cookie):
3992 Take an exclusive lock on the image.
3994 :raises: :class:`ImageBusy` if a different client or cookie locked it
3995 :class:`ImageExists` if the same client and cookie locked it
3997 cookie = cstr(cookie, 'cookie')
3998 cdef char *_cookie = cookie
4000 ret = rbd_lock_exclusive(self.image, _cookie)
4002 raise make_ex(ret, 'error acquiring exclusive lock on image')
4004 def lock_shared(self, cookie, tag):
4006 Take a shared lock on the image. The tag must match
4007 that of the existing lockers, if any.
4009 :raises: :class:`ImageBusy` if a different client or cookie locked it
4010 :class:`ImageExists` if the same client and cookie locked it
4012 cookie = cstr(cookie, 'cookie')
4013 tag = cstr(tag, 'tag')
4015 char *_cookie = cookie
4018 ret = rbd_lock_shared(self.image, _cookie, _tag)
4020 raise make_ex(ret, 'error acquiring shared lock on image')
4022 def unlock(self, cookie):
4024 Release a lock on the image that was locked by this rados client.
4026 cookie = cstr(cookie, 'cookie')
4027 cdef char *_cookie = cookie
4029 ret = rbd_unlock(self.image, _cookie)
4031 raise make_ex(ret, 'error unlocking image')
4033 def break_lock(self, client, cookie):
4035 Release a lock held by another rados client.
4037 client = cstr(client, 'client')
4038 cookie = cstr(cookie, 'cookie')
4040 char *_client = client
4041 char *_cookie = cookie
4043 ret = rbd_break_lock(self.image, _client, _cookie)
4045 raise make_ex(ret, 'error unlocking image')
4047 def mirror_image_enable(self):
4049 Enable mirroring for the image.
4052 ret = rbd_mirror_image_enable(self.image)
4054 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4056 def mirror_image_disable(self, force):
4058 Disable mirroring for the image.
4060 :param force: force disabling
4063 cdef bint c_force = force
4065 ret = rbd_mirror_image_disable(self.image, c_force)
4067 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4069 def mirror_image_promote(self, force):
4071 Promote the image to primary for mirroring.
4073 :param force: force promoting
4076 cdef bint c_force = force
4078 ret = rbd_mirror_image_promote(self.image, c_force)
4080 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4082 def mirror_image_demote(self):
4084 Demote the image to secondary for mirroring.
4087 ret = rbd_mirror_image_demote(self.image)
4089 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4091 def mirror_image_resync(self):
4093 Flag the image to resync.
4096 ret = rbd_mirror_image_resync(self.image)
4098 raise make_ex(ret, 'error to resync image %s' % self.name)
4100 def mirror_image_get_info(self):
4102 Get mirror info for the image.
4104 :returns: dict - contains the following keys:
4106 * ``global_id`` (str) - image global id
4108 * ``state`` (int) - mirror state
4110 * ``primary`` (bool) - is image primary
4112 cdef rbd_mirror_image_info_t c_info
4114 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4116 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4118 'global_id' : decode_cstr(c_info.global_id),
4119 'state' : int(c_info.state),
4120 'primary' : c_info.primary,
4122 free(c_info.global_id)
4125 def mirror_image_get_status(self):
4127 Get mirror status for the image.
4129 :returns: dict - contains the following keys:
4131 * ``name`` (str) - mirror image name
4133 * ``id`` (str) - mirror image id
4135 * `info` (dict) - mirror image info
4137 * ``state`` (int) - status mirror state
4139 * ``description`` (str) - status description
4141 * ``last_update`` (datetime) - last status update time
4143 * ``up`` (bool) - is mirroring agent up
4145 cdef rbd_mirror_image_status_t c_status
4147 ret = rbd_mirror_image_get_status(self.image, &c_status,
4150 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4152 'name' : decode_cstr(c_status.name),
4155 'global_id' : decode_cstr(c_status.info.global_id),
4156 'state' : int(c_status.info.state),
4157 'primary' : c_status.info.primary,
4159 'state' : c_status.state,
4160 'description' : decode_cstr(c_status.description),
4161 'last_update' : datetime.utcfromtimestamp(c_status.last_update),
4165 free(c_status.info.global_id)
4166 free(c_status.description)
4169 def mirror_image_get_instance_id(self):
4171 Get mirror instance id for the image.
4173 :returns: str - instance id
4176 int ret = -errno.ERANGE
4178 char *instance_id = NULL
4180 while ret == -errno.ERANGE and size <= 4096:
4181 instance_id = <char *>realloc_chk(instance_id, size)
4183 ret = rbd_mirror_image_get_instance_id(self.image,
4187 'error getting mirror instance id for image %s' %
4189 return decode_cstr(instance_id)
4193 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4195 Asynchronously read data from the image
4197 Raises :class:`InvalidArgument` if part of the range specified is
4200 oncomplete will be called with the returned read value as
4201 well as the completion:
4203 oncomplete(completion, data_read)
4205 :param offset: the offset to start reading at
4207 :param length: how many bytes to read
4209 :param oncomplete: what to do when the read is complete
4210 :type oncomplete: completion
4211 :param fadvise_flags: fadvise flags for this read
4212 :type fadvise_flags: int
4213 :returns: :class:`Completion` - the completion object
4214 :raises: :class:`InvalidArgument`, :class:`IOError`
4219 uint64_t _offset = offset
4220 size_t _length = length
4221 int _fadvise_flags = fadvise_flags
4222 Completion completion
4224 def oncomplete_(completion_v):
4225 cdef Completion _completion_v = completion_v
4226 return_value = _completion_v.get_return_value()
4227 if return_value > 0 and return_value != length:
4228 _PyBytes_Resize(&_completion_v.buf, return_value)
4229 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
4231 completion = self.__get_completion(oncomplete_)
4232 completion.buf = PyBytes_FromStringAndSize(NULL, length)
4233 ret_buf = PyBytes_AsString(completion.buf)
4235 completion.__persist()
4237 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
4238 completion.rbd_comp, _fadvise_flags)
4240 raise make_ex(ret, 'error reading %s %ld~%ld' %
4241 (self.name, offset, length))
4243 completion.__unpersist()
4248 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
4250 Asynchronously write data to the image
4252 Raises :class:`InvalidArgument` if part of the write would fall outside
4255 oncomplete will be called with the completion:
4257 oncomplete(completion)
4259 :param data: the data to be written
4261 :param offset: the offset to start writing at
4263 :param oncomplete: what to do when the write is complete
4264 :type oncomplete: completion
4265 :param fadvise_flags: fadvise flags for this write
4266 :type fadvise_flags: int
4267 :returns: :class:`Completion` - the completion object
4268 :raises: :class:`InvalidArgument`, :class:`IOError`
4272 uint64_t _offset = offset
4274 size_t _length = len(data)
4275 int _fadvise_flags = fadvise_flags
4276 Completion completion
4278 completion = self.__get_completion(oncomplete)
4280 completion.__persist()
4282 ret = rbd_aio_write2(self.image, _offset, _length, _data,
4283 completion.rbd_comp, _fadvise_flags)
4285 raise make_ex(ret, 'error writing %s %ld~%ld' %
4286 (self.name, offset, _length))
4288 completion.__unpersist()
4293 def aio_discard(self, offset, length, oncomplete):
4295 Asynchronously trim the range from the image. It will be logically
4300 uint64_t _offset = offset
4301 size_t _length = length
4302 Completion completion
4304 completion = self.__get_completion(oncomplete)
4306 completion.__persist()
4308 ret = rbd_aio_discard(self.image, _offset, _length,
4309 completion.rbd_comp)
4311 raise make_ex(ret, 'error discarding %s %ld~%ld' %
4312 (self.name, offset, _length))
4314 completion.__unpersist()
4319 def aio_flush(self, oncomplete):
4321 Asynchronously wait until all writes are fully flushed if caching is
4325 cdef Completion completion = self.__get_completion(oncomplete)
4327 completion.__persist()
4329 ret = rbd_aio_flush(self.image, completion.rbd_comp)
4331 raise make_ex(ret, 'error flushing')
4333 completion.__unpersist()
4338 def metadata_get(self, key):
4340 Get image metadata for the given key.
4342 :param key: metadata key
4344 :returns: str - metadata value
4346 key = cstr(key, 'key')
4354 value = <char *>realloc_chk(value, size)
4356 ret = rbd_metadata_get(self.image, _key, value, &size)
4357 if ret != -errno.ERANGE:
4359 if ret == -errno.ENOENT:
4360 raise KeyError('no metadata %s for image %s' % (key, self.name))
4362 raise make_ex(ret, 'error getting metadata %s for image %s' %
4364 return decode_cstr(value)
4368 def metadata_set(self, key, value):
4370 Set image metadata for the given key.
4372 :param key: metadata key
4374 :param value: metadata value
4377 key = cstr(key, 'key')
4378 value = cstr(value, 'value')
4381 char *_value = value
4383 ret = rbd_metadata_set(self.image, _key, _value)
4386 raise make_ex(ret, 'error setting metadata %s for image %s' %
4390 def metadata_remove(self, key):
4392 Remove image metadata for the given key.
4394 :param key: metadata key
4397 key = cstr(key, 'key')
4401 ret = rbd_metadata_remove(self.image, _key)
4403 if ret == -errno.ENOENT:
4404 raise KeyError('no metadata %s for image %s' % (key, self.name))
4406 raise make_ex(ret, 'error removing metadata %s for image %s' %
4409 def metadata_list(self):
4411 List image metadata.
4413 :returns: :class:`MetadataIterator`
4415 return MetadataIterator(self)
4417 def watchers_list(self):
4419 List image watchers.
4421 :returns: :class:`WatcherIterator`
4423 return WatcherIterator(self)
4425 def config_list(self):
4427 List image-level config overrides.
4429 :returns: :class:`ConfigPoolIterator`
4431 return ConfigImageIterator(self)
4433 def snap_get_namespace_type(self, snap_id):
4435 Get the snapshot namespace type.
4436 :param snap_id: the snapshot id of a snap shot
4440 rbd_snap_namespace_type_t namespace_type
4441 uint64_t _snap_id = snap_id
4443 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
4445 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
4447 return namespace_type
4449 def snap_get_group_namespace(self, snap_id):
4451 get the group namespace details.
4452 :param snap_id: the snapshot id of the group snapshot
4454 :returns: dict - contains the following keys:
4456 * ``pool`` (int) - pool id
4458 * ``name`` (str) - group name
4460 * ``snap_name`` (str) - group snap name
4463 rbd_snap_group_namespace_t group_namespace
4464 uint64_t _snap_id = snap_id
4466 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
4468 sizeof(rbd_snap_group_namespace_t))
4470 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
4473 'pool' : group_namespace.group_pool,
4474 'name' : decode_cstr(group_namespace.group_name),
4475 'snap_name' : decode_cstr(group_namespace.group_snap_name)
4477 rbd_snap_group_namespace_cleanup(&group_namespace,
4478 sizeof(rbd_snap_group_namespace_t))
4481 def snap_get_trash_namespace(self, snap_id):
4483 get the trash namespace details.
4484 :param snap_id: the snapshot id of the trash snapshot
4486 :returns: dict - contains the following keys:
4488 * ``original_name`` (str) - original snap name
4491 uint64_t _snap_id = snap_id
4496 _name = <char*>realloc_chk(_name, _size);
4498 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
4502 elif ret != -errno.ERANGE:
4503 raise make_ex(ret, 'error getting snapshot trash '
4504 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
4506 'original_name' : decode_cstr(_name)
4512 cdef class ImageIterator(object):
4514 Iterator over RBD images in a pool
4516 Yields a dictionary containing information about the images
4520 * ``id`` (str) - image id
4522 * ``name`` (str) - image name
4524 cdef rados_ioctx_t ioctx
4525 cdef rbd_image_spec_t *images
4526 cdef size_t num_images
4528 def __init__(self, ioctx):
4529 self.ioctx = convert_ioctx(ioctx)
4531 self.num_images = 1024
4533 self.images = <rbd_image_spec_t*>realloc_chk(
4534 self.images, self.num_images * sizeof(rbd_image_spec_t))
4536 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
4539 elif ret == -errno.ERANGE:
4540 self.num_images *= 2
4542 raise make_ex(ret, 'error listing images.')
4545 for i in range(self.num_images):
4547 'id' : decode_cstr(self.images[i].id),
4548 'name' : decode_cstr(self.images[i].name)
4551 def __dealloc__(self):
4553 rbd_image_spec_list_cleanup(self.images, self.num_images)
4557 cdef class LockOwnerIterator(object):
4559 Iterator over managed lock owners for an image
4561 Yields a dictionary containing information about the image's lock
4565 * ``mode`` (int) - active lock mode
4567 * ``owner`` (str) - lock owner name
4571 rbd_lock_mode_t lock_mode
4573 size_t num_lock_owners
4576 def __init__(self, Image image):
4578 self.lock_owners = NULL
4579 self.num_lock_owners = 8
4581 self.lock_owners = <char**>realloc_chk(self.lock_owners,
4582 self.num_lock_owners *
4585 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
4587 &self.num_lock_owners)
4590 elif ret != -errno.ERANGE:
4591 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
4594 for i in range(self.num_lock_owners):
4596 'mode' : int(self.lock_mode),
4597 'owner' : decode_cstr(self.lock_owners[i]),
4600 def __dealloc__(self):
4601 if self.lock_owners:
4602 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
4603 free(self.lock_owners)
4605 cdef class MetadataIterator(object):
4607 Iterator over metadata list for an image.
4609 Yields ``(key, value)`` tuple.
4611 * ``key`` (str) - metadata key
4612 * ``value`` (str) - metadata value
4622 def __init__(self, Image image):
4623 self.image_name = image.name
4624 self.image = image.image
4625 self.last_read = strdup("")
4627 self.get_next_chunk()
4630 while len(self.next_chunk) > 0:
4631 for pair in self.next_chunk:
4633 if len(self.next_chunk) < self.max_read:
4635 self.get_next_chunk()
4637 def __dealloc__(self):
4639 free(self.last_read)
4641 def get_next_chunk(self):
4644 size_t keys_size = 4096
4646 size_t vals_size = 4096
4649 c_keys = <char *>realloc_chk(c_keys, keys_size)
4650 c_vals = <char *>realloc_chk(c_vals, vals_size)
4652 ret = rbd_metadata_list(self.image, self.last_read,
4653 self.max_read, c_keys, &keys_size,
4657 elif ret != -errno.ERANGE:
4658 raise make_ex(ret, 'error listing metadata for image %s' %
4660 keys = [decode_cstr(key) for key in
4661 c_keys[:keys_size].split(b'\0') if key]
4662 vals = [decode_cstr(val) for val in
4663 c_vals[:vals_size].split(b'\0') if val]
4665 last_read = cstr(keys[-1], 'last_read')
4666 free(self.last_read)
4667 self.last_read = strdup(last_read)
4668 self.next_chunk = list(zip(keys, vals))
4673 cdef class SnapIterator(object):
4675 Iterator over snapshot info for an image.
4677 Yields a dictionary containing information about a snapshot.
4681 * ``id`` (int) - numeric identifier of the snapshot
4683 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
4685 * ``name`` (str) - name of the snapshot
4687 * ``namespace`` (int) - enum for snap namespace
4689 * ``group`` (dict) - optional for group namespace snapshots
4691 * ``trash`` (dict) - optional for trash namespace snapshots
4694 cdef rbd_snap_info_t *snaps
4698 def __init__(self, Image image):
4703 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
4705 sizeof(rbd_snap_info_t))
4707 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
4709 self.num_snaps = ret
4711 elif ret != -errno.ERANGE:
4712 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
4715 for i in range(self.num_snaps):
4717 'id' : self.snaps[i].id,
4718 'size' : self.snaps[i].size,
4719 'name' : decode_cstr(self.snaps[i].name),
4720 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
4722 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
4724 group = self.image.snap_get_group_namespace(self.snaps[i].id)
4728 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
4730 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
4736 def __dealloc__(self):
4738 rbd_snap_list_end(self.snaps)
4741 cdef class TrashIterator(object):
4743 Iterator over trash entries.
4745 Yields a dictionary containing trash info of an image.
4749 * `id` (str) - image id
4751 * `name` (str) - image name
4753 * `source` (str) - source of deletion
4755 * `deletion_time` (datetime) - time of deletion
4757 * `deferment_end_time` (datetime) - time that an image is allowed to be
4764 rbd_trash_image_info_t *entries
4766 def __init__(self, ioctx):
4767 self.ioctx = convert_ioctx(ioctx)
4768 self.num_entries = 1024
4771 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
4773 sizeof(rbd_trash_image_info_t))
4775 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
4777 self.num_entries = ret
4779 elif ret != -errno.ERANGE:
4780 raise make_ex(ret, 'error listing trash entries')
4782 __source_string = ['USER', 'MIRRORING']
4785 for i in range(self.num_entries):
4787 'id' : decode_cstr(self.entries[i].id),
4788 'name' : decode_cstr(self.entries[i].name),
4789 'source' : TrashIterator.__source_string[self.entries[i].source],
4790 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
4791 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
4794 def __dealloc__(self):
4795 rbd_trash_list_cleanup(self.entries, self.num_entries)
4799 cdef class ChildIterator(object):
4801 Iterator over child info for the image or its snapshot.
4803 Yields a dictionary containing information about a child.
4807 * ``pool`` (str) - name of the pool
4809 * ``pool_namespace`` (str) - namespace of the pool
4811 * ``image`` (str) - name of the child
4813 * ``id`` (str) - id of the child
4815 * ``trash`` (bool) - True if child is in trash bin
4818 cdef rbd_linked_image_spec_t *children
4819 cdef size_t num_children
4822 def __init__(self, Image image, descendants=False):
4824 self.children = NULL
4825 self.num_children = 10
4827 self.children = <rbd_linked_image_spec_t*>realloc_chk(
4828 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
4831 ret = rbd_list_descendants(image.image, self.children,
4835 ret = rbd_list_children3(image.image, self.children,
4839 elif ret != -errno.ERANGE:
4840 raise make_ex(ret, 'error listing children.')
4843 for i in range(self.num_children):
4845 'pool' : decode_cstr(self.children[i].pool_name),
4846 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
4847 'image' : decode_cstr(self.children[i].image_name),
4848 'id' : decode_cstr(self.children[i].image_id),
4849 'trash' : self.children[i].trash
4852 def __dealloc__(self):
4854 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
4857 cdef class WatcherIterator(object):
4859 Iterator over watchers of an image.
4861 Yields a dictionary containing information about a watcher.
4865 * ``addr`` (str) - address of the watcher
4867 * ``id`` (int) - id of the watcher
4869 * ``cookie`` (int) - the watcher's cookie
4872 cdef rbd_image_watcher_t *watchers
4873 cdef size_t num_watchers
4876 def __init__(self, Image image):
4878 self.watchers = NULL
4879 self.num_watchers = 10
4881 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
4883 sizeof(rbd_image_watcher_t))
4885 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
4888 elif ret != -errno.ERANGE:
4889 raise make_ex(ret, 'error listing watchers.')
4892 for i in range(self.num_watchers):
4894 'addr' : decode_cstr(self.watchers[i].addr),
4895 'id' : self.watchers[i].id,
4896 'cookie' : self.watchers[i].cookie
4899 def __dealloc__(self):
4901 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
4904 cdef class ConfigImageIterator(object):
4906 Iterator over image-level overrides for an image.
4908 Yields a dictionary containing information about an override.
4912 * ``name`` (str) - override name
4914 * ``value`` (str) - override value
4916 * ``source`` (str) - override source
4920 rbd_config_option_t *options
4923 def __init__(self, Image image):
4925 self.num_options = 32
4927 self.options = <rbd_config_option_t *>realloc_chk(
4928 self.options, self.num_options * sizeof(rbd_config_option_t))
4930 ret = rbd_config_image_list(image.image, self.options,
4933 if ret == -errno.ERANGE:
4935 self.num_options = 0
4936 raise make_ex(ret, 'error listing config options')
4940 for i in range(self.num_options):
4942 'name' : decode_cstr(self.options[i].name),
4943 'value' : decode_cstr(self.options[i].value),
4944 'source' : self.options[i].source,
4947 def __dealloc__(self):
4949 rbd_config_image_list_cleanup(self.options, self.num_options)
4952 cdef class GroupImageIterator(object):
4954 Iterator over image info for a group.
4956 Yields a dictionary containing information about an image.
4960 * ``name`` (str) - name of the image
4962 * ``pool`` (int) - id of the pool this image belongs to
4964 * ``state`` (int) - state of the image
4967 cdef rbd_group_image_info_t *images
4968 cdef size_t num_images
4971 def __init__(self, Group group):
4974 self.num_images = 10
4976 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
4978 sizeof(rbd_group_image_info_t))
4980 ret = rbd_group_image_list(group._ioctx, group._name,
4982 sizeof(rbd_group_image_info_t),
4987 elif ret != -errno.ERANGE:
4988 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
4991 for i in range(self.num_images):
4993 'name' : decode_cstr(self.images[i].name),
4994 'pool' : self.images[i].pool,
4995 'state' : self.images[i].state,
4998 def __dealloc__(self):
5000 rbd_group_image_list_cleanup(self.images,
5001 sizeof(rbd_group_image_info_t),
5005 cdef class GroupSnapIterator(object):
5007 Iterator over snaps specs for a group.
5009 Yields a dictionary containing information about a snapshot.
5013 * ``name`` (str) - name of the snapshot
5015 * ``state`` (int) - state of the snapshot
5018 cdef rbd_group_snap_info_t *snaps
5019 cdef size_t num_snaps
5022 def __init__(self, Group group):
5027 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
5029 sizeof(rbd_group_snap_info_t))
5031 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
5032 sizeof(rbd_group_snap_info_t),
5037 elif ret != -errno.ERANGE:
5038 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
5041 for i in range(self.num_snaps):
5043 'name' : decode_cstr(self.snaps[i].name),
5044 'state' : self.snaps[i].state,
5047 def __dealloc__(self):
5049 rbd_group_snap_list_cleanup(self.snaps,
5050 sizeof(rbd_group_snap_info_t),