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"
75 _RBD_FEATURE_NON_PRIMARY "RBD_FEATURE_NON_PRIMARY"
77 _RBD_FEATURES_INCOMPATIBLE "RBD_FEATURES_INCOMPATIBLE"
78 _RBD_FEATURES_RW_INCOMPATIBLE "RBD_FEATURES_RW_INCOMPATIBLE"
79 _RBD_FEATURES_MUTABLE "RBD_FEATURES_MUTABLE"
80 _RBD_FEATURES_SINGLE_CLIENT "RBD_FEATURES_SINGLE_CLIENT"
81 _RBD_FEATURES_ALL "RBD_FEATURES_ALL"
83 _RBD_OPERATION_FEATURE_CLONE_PARENT "RBD_OPERATION_FEATURE_CLONE_PARENT"
84 _RBD_OPERATION_FEATURE_CLONE_CHILD "RBD_OPERATION_FEATURE_CLONE_CHILD"
85 _RBD_OPERATION_FEATURE_GROUP "RBD_OPERATION_FEATURE_GROUP"
86 _RBD_OPERATION_FEATURE_SNAP_TRASH "RBD_OPERATION_FEATURE_SNAP_TRASH"
88 _RBD_FLAG_OBJECT_MAP_INVALID "RBD_FLAG_OBJECT_MAP_INVALID"
89 _RBD_FLAG_FAST_DIFF_INVALID "RBD_FLAG_FAST_DIFF_INVALID"
91 _RBD_IMAGE_OPTION_FORMAT "RBD_IMAGE_OPTION_FORMAT"
92 _RBD_IMAGE_OPTION_FEATURES "RBD_IMAGE_OPTION_FEATURES"
93 _RBD_IMAGE_OPTION_ORDER "RBD_IMAGE_OPTION_ORDER"
94 _RBD_IMAGE_OPTION_STRIPE_UNIT "RBD_IMAGE_OPTION_STRIPE_UNIT"
95 _RBD_IMAGE_OPTION_STRIPE_COUNT "RBD_IMAGE_OPTION_STRIPE_COUNT"
96 _RBD_IMAGE_OPTION_DATA_POOL "RBD_IMAGE_OPTION_DATA_POOL"
98 RBD_MAX_BLOCK_NAME_SIZE
99 RBD_MAX_IMAGE_NAME_SIZE
101 _RBD_SNAP_REMOVE_UNPROTECT "RBD_SNAP_REMOVE_UNPROTECT"
102 _RBD_SNAP_REMOVE_FLATTEN "RBD_SNAP_REMOVE_FLATTEN"
103 _RBD_SNAP_REMOVE_FORCE "RBD_SNAP_REMOVE_FORCE"
105 ctypedef void* rados_t
106 ctypedef void* rados_ioctx_t
107 ctypedef void* rbd_image_t
108 ctypedef void* rbd_image_options_t
109 ctypedef void* rbd_pool_stats_t
110 ctypedef void *rbd_completion_t
112 ctypedef struct rbd_image_info_t:
117 char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]
119 char parent_name[RBD_MAX_IMAGE_NAME_SIZE]
121 ctypedef struct rbd_snap_info_t:
126 ctypedef struct rbd_snap_group_namespace_t:
129 char *group_snap_name
131 ctypedef enum rbd_snap_mirror_state_t:
132 _RBD_SNAP_MIRROR_STATE_PRIMARY "RBD_SNAP_MIRROR_STATE_PRIMARY"
133 _RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED "RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED"
134 _RBD_SNAP_MIRROR_STATE_NON_PRIMARY "RBD_SNAP_MIRROR_STATE_NON_PRIMARY"
135 _RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED "RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED"
137 ctypedef struct rbd_snap_mirror_namespace_t:
138 rbd_snap_mirror_state_t state
139 size_t mirror_peer_uuids_count
140 char *mirror_peer_uuids
142 char *primary_mirror_uuid
143 uint64_t primary_snap_id
144 uint64_t last_copied_object_number
146 ctypedef struct rbd_group_info_t:
150 ctypedef struct rbd_image_spec_t:
154 ctypedef struct rbd_linked_image_spec_t:
162 ctypedef enum rbd_snap_namespace_type_t:
163 _RBD_SNAP_NAMESPACE_TYPE_USER "RBD_SNAP_NAMESPACE_TYPE_USER"
164 _RBD_SNAP_NAMESPACE_TYPE_GROUP "RBD_SNAP_NAMESPACE_TYPE_GROUP"
165 _RBD_SNAP_NAMESPACE_TYPE_TRASH "RBD_SNAP_NAMESPACE_TYPE_TRASH"
166 _RBD_SNAP_NAMESPACE_TYPE_MIRROR "RBD_SNAP_NAMESPACE_TYPE_MIRROR"
168 ctypedef struct rbd_snap_spec_t:
170 rbd_snap_namespace_type_t namespace_type
173 ctypedef enum rbd_mirror_mode_t:
174 _RBD_MIRROR_MODE_DISABLED "RBD_MIRROR_MODE_DISABLED"
175 _RBD_MIRROR_MODE_IMAGE "RBD_MIRROR_MODE_IMAGE"
176 _RBD_MIRROR_MODE_POOL "RBD_MIRROR_MODE_POOL"
178 ctypedef enum rbd_mirror_peer_direction_t:
179 _RBD_MIRROR_PEER_DIRECTION_RX "RBD_MIRROR_PEER_DIRECTION_RX"
180 _RBD_MIRROR_PEER_DIRECTION_TX "RBD_MIRROR_PEER_DIRECTION_TX"
181 _RBD_MIRROR_PEER_DIRECTION_RX_TX "RBD_MIRROR_PEER_DIRECTION_RX_TX"
183 ctypedef struct rbd_mirror_peer_site_t:
185 rbd_mirror_peer_direction_t direction
191 cdef char* _RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST "RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST"
192 cdef char* _RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY "RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY"
194 ctypedef enum rbd_mirror_image_mode_t:
195 _RBD_MIRROR_IMAGE_MODE_JOURNAL "RBD_MIRROR_IMAGE_MODE_JOURNAL"
196 _RBD_MIRROR_IMAGE_MODE_SNAPSHOT "RBD_MIRROR_IMAGE_MODE_SNAPSHOT"
198 ctypedef enum rbd_mirror_image_state_t:
199 _RBD_MIRROR_IMAGE_DISABLING "RBD_MIRROR_IMAGE_DISABLING"
200 _RBD_MIRROR_IMAGE_ENABLED "RBD_MIRROR_IMAGE_ENABLED"
201 _RBD_MIRROR_IMAGE_DISABLED "RBD_MIRROR_IMAGE_DISABLED"
203 ctypedef struct rbd_mirror_image_info_t:
205 rbd_mirror_image_state_t state
208 ctypedef enum rbd_mirror_image_status_state_t:
209 _MIRROR_IMAGE_STATUS_STATE_UNKNOWN "MIRROR_IMAGE_STATUS_STATE_UNKNOWN"
210 _MIRROR_IMAGE_STATUS_STATE_ERROR "MIRROR_IMAGE_STATUS_STATE_ERROR"
211 _MIRROR_IMAGE_STATUS_STATE_SYNCING "MIRROR_IMAGE_STATUS_STATE_SYNCING"
212 _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY"
213 _MIRROR_IMAGE_STATUS_STATE_REPLAYING "MIRROR_IMAGE_STATUS_STATE_REPLAYING"
214 _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY "MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY"
215 _MIRROR_IMAGE_STATUS_STATE_STOPPED "MIRROR_IMAGE_STATUS_STATE_STOPPED"
217 ctypedef struct rbd_mirror_image_site_status_t:
219 rbd_mirror_image_status_state_t state
224 ctypedef struct rbd_mirror_image_global_status_t:
226 rbd_mirror_image_info_t info
227 uint32_t site_statuses_count
228 rbd_mirror_image_site_status_t *site_statuses
230 ctypedef enum rbd_lock_mode_t:
231 _RBD_LOCK_MODE_EXCLUSIVE "RBD_LOCK_MODE_EXCLUSIVE"
232 _RBD_LOCK_MODE_SHARED "RBD_LOCK_MODE_SHARED"
234 ctypedef enum rbd_trash_image_source_t:
235 _RBD_TRASH_IMAGE_SOURCE_USER "RBD_TRASH_IMAGE_SOURCE_USER",
236 _RBD_TRASH_IMAGE_SOURCE_MIRRORING "RBD_TRASH_IMAGE_SOURCE_MIRRORING",
237 _RBD_TRASH_IMAGE_SOURCE_MIGRATION "RBD_TRASH_IMAGE_SOURCE_MIGRATION"
238 _RBD_TRASH_IMAGE_SOURCE_REMOVING "RBD_TRASH_IMAGE_SOURCE_REMOVING"
240 ctypedef struct rbd_trash_image_info_t:
243 rbd_trash_image_source_t source
245 time_t deferment_end_time
247 ctypedef struct rbd_image_watcher_t:
252 ctypedef enum rbd_group_image_state_t:
253 _RBD_GROUP_IMAGE_STATE_ATTACHED "RBD_GROUP_IMAGE_STATE_ATTACHED"
254 _RBD_GROUP_IMAGE_STATE_INCOMPLETE "RBD_GROUP_IMAGE_STATE_INCOMPLETE"
256 ctypedef struct rbd_group_image_info_t:
259 rbd_group_image_state_t state
261 ctypedef enum rbd_group_snap_state_t:
262 _RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
263 _RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
265 ctypedef struct rbd_group_snap_info_t:
267 rbd_group_snap_state_t state
269 ctypedef enum rbd_image_migration_state_t:
270 _RBD_IMAGE_MIGRATION_STATE_UNKNOWN "RBD_IMAGE_MIGRATION_STATE_UNKNOWN"
271 _RBD_IMAGE_MIGRATION_STATE_ERROR "RBD_IMAGE_MIGRATION_STATE_ERROR"
272 _RBD_IMAGE_MIGRATION_STATE_PREPARING "RBD_IMAGE_MIGRATION_STATE_PREPARING"
273 _RBD_IMAGE_MIGRATION_STATE_PREPARED "RBD_IMAGE_MIGRATION_STATE_PREPARED"
274 _RBD_IMAGE_MIGRATION_STATE_EXECUTING "RBD_IMAGE_MIGRATION_STATE_EXECUTING"
275 _RBD_IMAGE_MIGRATION_STATE_EXECUTED "RBD_IMAGE_MIGRATION_STATE_EXECUTED"
277 ctypedef struct rbd_image_migration_status_t:
278 int64_t source_pool_id
279 char *source_pool_namespace
280 char *source_image_name
281 char *source_image_id
283 char *dest_pool_namespace
284 char *dest_image_name
286 rbd_image_migration_state_t state
287 char *state_description
289 ctypedef enum rbd_config_source_t:
290 _RBD_CONFIG_SOURCE_CONFIG "RBD_CONFIG_SOURCE_CONFIG"
291 _RBD_CONFIG_SOURCE_POOL "RBD_CONFIG_SOURCE_POOL"
292 _RBD_CONFIG_SOURCE_IMAGE "RBD_CONFIG_SOURCE_IMAGE"
294 ctypedef struct rbd_config_option_t:
297 rbd_config_source_t source
299 ctypedef enum rbd_pool_stat_option_t:
300 _RBD_POOL_STAT_OPTION_IMAGES "RBD_POOL_STAT_OPTION_IMAGES"
301 _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES"
302 _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES"
303 _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS "RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS"
304 _RBD_POOL_STAT_OPTION_TRASH_IMAGES "RBD_POOL_STAT_OPTION_TRASH_IMAGES"
305 _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES"
306 _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES"
307 _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
309 ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
311 void rbd_version(int *major, int *minor, int *extra)
313 void rbd_image_spec_list_cleanup(rbd_image_spec_t *image, size_t num_images)
314 void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
315 void rbd_linked_image_spec_list_cleanup(rbd_linked_image_spec_t *images,
317 void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
319 void rbd_image_options_create(rbd_image_options_t* opts)
320 void rbd_image_options_destroy(rbd_image_options_t opts)
321 int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
323 int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
325 int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
326 char* optval, size_t maxlen)
327 int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
329 int rbd_image_options_unset(rbd_image_options_t opts, int optname)
330 void rbd_image_options_clear(rbd_image_options_t opts)
331 int rbd_image_options_is_empty(rbd_image_options_t opts)
333 int rbd_list(rados_ioctx_t io, char *names, size_t *size)
334 int rbd_list2(rados_ioctx_t io, rbd_image_spec_t *images,
336 int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
338 int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
339 rbd_image_options_t opts)
340 int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
341 const char *p_snapname, rados_ioctx_t c_ioctx,
342 const char *c_name, rbd_image_options_t c_opts)
343 int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
344 librbd_progress_fn_t cb, void *cbdata)
345 int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
346 const char *destname)
348 int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay)
349 int rbd_trash_get(rados_ioctx_t io, const char *id,
350 rbd_trash_image_info_t *info)
351 void rbd_trash_get_cleanup(rbd_trash_image_info_t *info)
352 int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries,
354 void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
356 int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, float threshold)
357 int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
358 int force, librbd_progress_fn_t cb,
360 int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
362 int rbd_migration_prepare(rados_ioctx_t io_ctx, const char *image_name,
363 rados_ioctx_t dest_io_ctx,
364 const char *dest_image_name,
365 rbd_image_options_t opts)
366 int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
367 const char *image_name,
368 librbd_progress_fn_t cb,
370 int rbd_migration_commit_with_progress(rados_ioctx_t io_ctx,
371 const char *image_name,
372 librbd_progress_fn_t cb,
374 int rbd_migration_abort_with_progress(rados_ioctx_t io_ctx,
375 const char *image_name,
376 librbd_progress_fn_t cb, void *cbdata)
377 int rbd_migration_status(rados_ioctx_t io_ctx, const char *image_name,
378 rbd_image_migration_status_t *status,
380 void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
382 int rbd_mirror_site_name_get(rados_t cluster, char *name, size_t *max_len)
383 int rbd_mirror_site_name_set(rados_t cluster, const char *name)
385 int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
386 int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
388 int rbd_mirror_uuid_get(rados_ioctx_t io_ctx, char *mirror_uuid,
391 int rbd_mirror_peer_bootstrap_create(rados_ioctx_t io_ctx, char *token,
393 int rbd_mirror_peer_bootstrap_import(
394 rados_ioctx_t io_ctx, rbd_mirror_peer_direction_t direction,
397 int rbd_mirror_peer_site_add(
398 rados_ioctx_t io, char *uuid, size_t uuid_max_length,
399 rbd_mirror_peer_direction_t direction, const char *site_name,
400 const char *client_name)
401 int rbd_mirror_peer_site_remove(rados_ioctx_t io, const char *uuid)
402 int rbd_mirror_peer_site_list(
403 rados_ioctx_t io_ctx, rbd_mirror_peer_site_t *peers,int *max_peers)
404 void rbd_mirror_peer_site_list_cleanup(
405 rbd_mirror_peer_site_t *peers, int max_peers)
407 int rbd_mirror_peer_site_set_name(
408 rados_ioctx_t io_ctx, const char *uuid, const char *site_name)
409 int rbd_mirror_peer_site_set_client_name(
410 rados_ioctx_t io_ctx, const char *uuid, const char *client_name)
412 int rbd_mirror_peer_site_get_attributes(
413 rados_ioctx_t io_ctx, const char *uuid, char *keys, size_t *max_key_len,
414 char *values, size_t *max_val_length, size_t *key_value_count)
415 int rbd_mirror_peer_site_set_attributes(
416 rados_ioctx_t io_ctx, const char *uuid, const char *keys,
417 const char *values, size_t count)
419 int rbd_mirror_image_global_status_list(
420 rados_ioctx_t io, const char *start_id, size_t max, char **image_ids,
421 rbd_mirror_image_global_status_t *images, size_t *len)
422 void rbd_mirror_image_global_status_list_cleanup(
423 char **image_ids, rbd_mirror_image_global_status_t *images, size_t len)
424 int rbd_mirror_image_status_summary(rados_ioctx_t io,
425 rbd_mirror_image_status_state_t *states,
426 int *counts, size_t *maxlen)
427 int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx,
428 const char *start_id,
429 size_t max, char **image_ids,
432 void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
435 int rbd_mirror_image_info_list(rados_ioctx_t io_ctx,
436 rbd_mirror_image_mode_t *mode_filter,
437 const char *start_id, size_t max,
439 rbd_mirror_image_mode_t *mode_entries,
440 rbd_mirror_image_info_t *info_entries,
442 void rbd_mirror_image_info_list_cleanup(char **image_ids,
443 rbd_mirror_image_info_t *info_entries,
446 int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
447 char *value, size_t *val_len)
448 int rbd_pool_metadata_set(rados_ioctx_t io_ctx, const char *key,
450 int rbd_pool_metadata_remove(rados_ioctx_t io_ctx, const char *key)
451 int rbd_pool_metadata_list(rados_ioctx_t io_ctx, const char *start,
452 uint64_t max, char *keys, size_t *key_len,
453 char *values, size_t *vals_len)
455 int rbd_config_pool_list(rados_ioctx_t io_ctx, rbd_config_option_t *options,
457 void rbd_config_pool_list_cleanup(rbd_config_option_t *options,
460 int rbd_open(rados_ioctx_t io, const char *name,
461 rbd_image_t *image, const char *snap_name)
462 int rbd_open_by_id(rados_ioctx_t io, const char *image_id,
463 rbd_image_t *image, const char *snap_name)
464 int rbd_open_read_only(rados_ioctx_t io, const char *name,
465 rbd_image_t *image, const char *snap_name)
466 int rbd_open_by_id_read_only(rados_ioctx_t io, const char *image_id,
467 rbd_image_t *image, const char *snap_name)
468 int rbd_features_to_string(uint64_t features, char *str_features, size_t *size)
469 int rbd_features_from_string(const char *str_features, uint64_t *features)
470 int rbd_close(rbd_image_t image)
471 int rbd_resize2(rbd_image_t image, uint64_t size, bint allow_shrink,
472 librbd_progress_fn_t cb, void *cbdata)
473 int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
474 int rbd_get_old_format(rbd_image_t image, uint8_t *old)
475 int rbd_get_size(rbd_image_t image, uint64_t *size)
476 int rbd_get_features(rbd_image_t image, uint64_t *features)
477 int rbd_update_features(rbd_image_t image, uint64_t features,
479 int rbd_get_op_features(rbd_image_t image, uint64_t *op_features)
480 int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
481 int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
482 int rbd_get_create_timestamp(rbd_image_t image, timespec *timestamp)
483 int rbd_get_access_timestamp(rbd_image_t image, timespec *timestamp)
484 int rbd_get_modify_timestamp(rbd_image_t image, timespec *timestamp)
485 int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
486 int rbd_get_name(rbd_image_t image, char *name, size_t *name_len)
487 int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
488 int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
490 int64_t rbd_get_data_pool_id(rbd_image_t image)
491 int rbd_get_parent(rbd_image_t image,
492 rbd_linked_image_spec_t *parent_image,
493 rbd_snap_spec_t *parent_snap)
494 int rbd_get_flags(rbd_image_t image, uint64_t *flags)
495 int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
496 size_t group_info_size)
498 ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
499 char *buf, int op_flags)
500 ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
501 const char *buf, int op_flags)
502 int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
503 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
504 const char *destname, rbd_image_options_t dest_opts)
505 int rbd_deep_copy(rbd_image_t src, rados_ioctx_t dest_io_ctx,
506 const char *destname, rbd_image_options_t dest_opts)
507 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
509 void rbd_snap_list_end(rbd_snap_info_t *snaps)
510 int rbd_snap_create(rbd_image_t image, const char *snapname)
511 int rbd_snap_remove(rbd_image_t image, const char *snapname)
512 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
513 librbd_progress_fn_t cb, void *cbdata)
514 int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
515 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
516 int rbd_snap_rename(rbd_image_t image, const char *snapname,
517 const char* dstsnapsname)
518 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
519 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
520 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
522 int rbd_snap_exists(rbd_image_t image, const char *snapname, bint *exists)
523 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
524 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
525 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
526 int rbd_snap_set(rbd_image_t image, const char *snapname)
527 int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
528 int rbd_snap_get_name(rbd_image_t image, uint64_t snap_id,
529 char *snapname, size_t *name_len)
530 int rbd_snap_get_id(rbd_image_t image, const char *snapname,
532 int rbd_snap_get_namespace_type(rbd_image_t image,
534 rbd_snap_namespace_type_t *namespace_type)
535 int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
536 rbd_snap_group_namespace_t *group_info,
537 size_t snap_group_namespace_size)
538 void rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_spec,
539 size_t snap_group_namespace_size)
540 int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
541 char *original_name, size_t max_length)
542 int rbd_snap_get_mirror_namespace(
543 rbd_image_t image, uint64_t snap_id,
544 rbd_snap_mirror_namespace_t *mirror_ns,
545 size_t snap_mirror_namespace_size)
546 void rbd_snap_mirror_namespace_cleanup(
547 rbd_snap_mirror_namespace_t *mirror_ns,
548 size_t snap_mirror_namespace_size)
550 int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
552 int rbd_sparsify(rbd_image_t image, size_t sparse_size)
553 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
555 int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
556 size_t *max_children)
557 int rbd_list_descendants(rbd_image_t image,
558 rbd_linked_image_spec_t *descendants,
559 size_t *max_descendants)
561 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
562 char *tag, size_t *tag_len,
563 char *clients, size_t *clients_len,
564 char *cookies, size_t *cookies_len,
565 char *addrs, size_t *addrs_len)
566 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
567 int rbd_lock_shared(rbd_image_t image, const char *cookie,
569 int rbd_unlock(rbd_image_t image, const char *cookie)
570 int rbd_break_lock(rbd_image_t image, const char *client,
573 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
574 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
575 int rbd_lock_release(rbd_image_t image)
576 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
577 char **lock_owners, size_t *max_lock_owners)
578 void rbd_lock_get_owners_cleanup(char **lock_owners,
579 size_t lock_owner_count)
580 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
583 # We use -9000 to propagate Python exceptions. We use except? to make sure
584 # things still work as intended if -9000 happens to be a valid errno value
586 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
587 uint64_t ofs, uint64_t len,
588 uint8_t include_parent, uint8_t whole_object,
589 int (*cb)(uint64_t, size_t, int, void *)
591 void *arg) except? -9000
593 int rbd_flush(rbd_image_t image)
594 int rbd_invalidate_cache(rbd_image_t image)
596 int rbd_mirror_image_enable2(rbd_image_t image,
597 rbd_mirror_image_mode_t mode)
598 int rbd_mirror_image_disable(rbd_image_t image, bint force)
599 int rbd_mirror_image_promote(rbd_image_t image, bint force)
600 int rbd_mirror_image_demote(rbd_image_t image)
601 int rbd_mirror_image_resync(rbd_image_t image)
602 int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id)
603 int rbd_mirror_image_get_info(rbd_image_t image,
604 rbd_mirror_image_info_t *mirror_image_info,
606 void rbd_mirror_image_get_info_cleanup(
607 rbd_mirror_image_info_t *mirror_image_info)
608 int rbd_mirror_image_get_mode(rbd_image_t image,
609 rbd_mirror_image_mode_t *mode)
610 int rbd_mirror_image_get_global_status(
612 rbd_mirror_image_global_status_t *mirror_image_global_status,
614 void rbd_mirror_image_global_status_cleanup(
615 rbd_mirror_image_global_status_t *mirror_image_global_status)
616 int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id,
617 size_t *id_max_length)
619 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
620 const char *buf, rbd_completion_t c, int op_flags)
621 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
622 char *buf, rbd_completion_t c, int op_flags)
623 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
626 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
628 int rbd_aio_is_complete(rbd_completion_t c)
629 int rbd_aio_wait_for_complete(rbd_completion_t c)
630 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
631 void rbd_aio_release(rbd_completion_t c)
632 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
634 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
636 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
637 int rbd_metadata_remove(rbd_image_t image, const char *key)
638 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
639 char *keys, size_t *key_len, char *values,
641 int rbd_group_create(rados_ioctx_t p, const char *name)
642 int rbd_group_remove(rados_ioctx_t p, const char *name)
643 int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
644 int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest)
645 void rbd_group_info_cleanup(rbd_group_info_t *group_info,
646 size_t group_info_size)
647 int rbd_group_image_add(rados_ioctx_t group_p, const char *group_name,
648 rados_ioctx_t image_p, const char *image_name)
649 int rbd_group_image_remove(rados_ioctx_t group_p, const char *group_name,
650 rados_ioctx_t image_p, const char *image_name)
652 int rbd_group_image_list(rados_ioctx_t group_p,
653 const char *group_name,
654 rbd_group_image_info_t *images,
655 size_t group_image_info_size,
657 void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
658 size_t group_image_info_size, size_t len)
660 int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
661 const char *snap_name)
663 int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
664 const char *snap_name)
666 int rbd_group_snap_rename(rados_ioctx_t group_p, const char *group_name,
667 const char *old_snap_name,
668 const char *new_snap_name)
670 int rbd_group_snap_list(rados_ioctx_t group_p,
671 const char *group_name,
672 rbd_group_snap_info_t *snaps,
673 size_t group_snap_info_size,
676 void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
677 size_t group_snap_info_size, size_t len)
678 int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
679 const char *snap_name)
681 int rbd_watchers_list(rbd_image_t image, rbd_image_watcher_t *watchers,
682 size_t *max_watchers)
683 void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
686 int rbd_config_image_list(rbd_image_t image, rbd_config_option_t *options,
688 void rbd_config_image_list_cleanup(rbd_config_option_t *options,
691 int rbd_namespace_create(rados_ioctx_t io, const char *namespace_name)
692 int rbd_namespace_remove(rados_ioctx_t io, const char *namespace_name)
693 int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
695 int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
698 int rbd_pool_init(rados_ioctx_t, bint force)
700 void rbd_pool_stats_create(rbd_pool_stats_t *stats)
701 void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
702 int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
703 int stat_option, uint64_t* stat_val)
704 int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
706 ECANCELED = _ECANCELED
708 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
709 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
710 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
711 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
712 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
713 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
714 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
715 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
716 RBD_FEATURE_OPERATIONS = _RBD_FEATURE_OPERATIONS
717 RBD_FEATURE_MIGRATING = _RBD_FEATURE_MIGRATING
718 RBD_FEATURE_NON_PRIMARY = _RBD_FEATURE_NON_PRIMARY
720 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
721 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
722 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
723 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
724 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
726 RBD_OPERATION_FEATURE_CLONE_PARENT = _RBD_OPERATION_FEATURE_CLONE_PARENT
727 RBD_OPERATION_FEATURE_CLONE_CHILD = _RBD_OPERATION_FEATURE_CLONE_CHILD
728 RBD_OPERATION_FEATURE_GROUP = _RBD_OPERATION_FEATURE_GROUP
729 RBD_OPERATION_FEATURE_SNAP_TRASH = _RBD_OPERATION_FEATURE_SNAP_TRASH
731 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
732 RBD_FLAG_FAST_DIFF_INVALID = _RBD_FLAG_FAST_DIFF_INVALID
734 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
735 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
736 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
738 RBD_MIRROR_PEER_DIRECTION_RX = _RBD_MIRROR_PEER_DIRECTION_RX
739 RBD_MIRROR_PEER_DIRECTION_TX = _RBD_MIRROR_PEER_DIRECTION_TX
740 RBD_MIRROR_PEER_DIRECTION_RX_TX = _RBD_MIRROR_PEER_DIRECTION_RX_TX
742 RBD_MIRROR_IMAGE_MODE_JOURNAL = _RBD_MIRROR_IMAGE_MODE_JOURNAL
743 RBD_MIRROR_IMAGE_MODE_SNAPSHOT = _RBD_MIRROR_IMAGE_MODE_SNAPSHOT
745 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
746 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
747 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
749 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
750 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
751 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
752 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
753 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
754 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
755 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
757 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
758 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
760 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
761 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
762 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
763 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
764 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
765 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
767 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
768 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
769 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
770 RBD_SNAP_NAMESPACE_TYPE_MIRROR = _RBD_SNAP_NAMESPACE_TYPE_MIRROR
772 RBD_SNAP_MIRROR_STATE_PRIMARY = _RBD_SNAP_MIRROR_STATE_PRIMARY
773 RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED
774 RBD_SNAP_MIRROR_STATE_NON_PRIMARY = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY
775 RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
777 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
778 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
780 RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
781 RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
783 RBD_IMAGE_MIGRATION_STATE_UNKNOWN = _RBD_IMAGE_MIGRATION_STATE_UNKNOWN
784 RBD_IMAGE_MIGRATION_STATE_ERROR = _RBD_IMAGE_MIGRATION_STATE_ERROR
785 RBD_IMAGE_MIGRATION_STATE_PREPARING = _RBD_IMAGE_MIGRATION_STATE_PREPARING
786 RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
787 RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
788 RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
790 RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
791 RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
792 RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
794 RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
795 RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
796 RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
797 RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
798 RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
799 RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
800 RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
801 RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
803 RBD_SNAP_REMOVE_UNPROTECT = _RBD_SNAP_REMOVE_UNPROTECT
804 RBD_SNAP_REMOVE_FLATTEN = _RBD_SNAP_REMOVE_FLATTEN
805 RBD_SNAP_REMOVE_FORCE = _RBD_SNAP_REMOVE_FORCE
807 class Error(Exception):
811 class OSError(Error):
812 """ `OSError` class, derived from `Error` """
813 def __init__(self, message, errno=None):
814 super(OSError, self).__init__(message)
818 msg = super(OSError, self).__str__()
819 if self.errno is None:
821 return '[errno {0}] {1}'.format(self.errno, msg)
823 def __reduce__(self):
824 return (self.__class__, (self.message, self.errno))
826 class PermissionError(OSError):
827 def __init__(self, message, errno=None):
828 super(PermissionError, self).__init__(
829 "RBD permission error (%s)" % message, errno)
832 class ImageNotFound(OSError):
833 def __init__(self, message, errno=None):
834 super(ImageNotFound, self).__init__(
835 "RBD image not found (%s)" % message, errno)
838 class ObjectNotFound(OSError):
839 def __init__(self, message, errno=None):
840 super(ObjectNotFound, self).__init__(
841 "RBD object not found (%s)" % message, errno)
844 class ImageExists(OSError):
845 def __init__(self, message, errno=None):
846 super(ImageExists, self).__init__(
847 "RBD image already exists (%s)" % message, errno)
850 class ObjectExists(OSError):
851 def __init__(self, message, errno=None):
852 super(ObjectExists, self).__init__(
853 "RBD object already exists (%s)" % message, errno)
856 class IOError(OSError):
857 def __init__(self, message, errno=None):
858 super(IOError, self).__init__(
859 "RBD I/O error (%s)" % message, errno)
862 class NoSpace(OSError):
863 def __init__(self, message, errno=None):
864 super(NoSpace, self).__init__(
865 "RBD insufficient space available (%s)" % message, errno)
868 class IncompleteWriteError(OSError):
869 def __init__(self, message, errno=None):
870 super(IncompleteWriteError, self).__init__(
871 "RBD incomplete write (%s)" % message, errno)
874 class InvalidArgument(OSError):
875 def __init__(self, message, errno=None):
876 super(InvalidArgument, self).__init__(
877 "RBD invalid argument (%s)" % message, errno)
880 class LogicError(OSError):
881 def __init__(self, message, errno=None):
882 super(LogicError, self).__init__(
883 "RBD logic error (%s)" % message, errno)
886 class ReadOnlyImage(OSError):
887 def __init__(self, message, errno=None):
888 super(ReadOnlyImage, self).__init__(
889 "RBD read-only image (%s)" % message, errno)
892 class ImageBusy(OSError):
893 def __init__(self, message, errno=None):
894 super(ImageBusy, self).__init__(
895 "RBD image is busy (%s)" % message, errno)
898 class ImageHasSnapshots(OSError):
899 def __init__(self, message, errno=None):
900 super(ImageHasSnapshots, self).__init__(
901 "RBD image has snapshots (%s)" % message, errno)
904 class FunctionNotSupported(OSError):
905 def __init__(self, message, errno=None):
906 super(FunctionNotSupported, self).__init__(
907 "RBD function not supported (%s)" % message, errno)
910 class ArgumentOutOfRange(OSError):
911 def __init__(self, message, errno=None):
912 super(ArgumentOutOfRange, self).__init__(
913 "RBD arguments out of range (%s)" % message, errno)
916 class ConnectionShutdown(OSError):
917 def __init__(self, message, errno=None):
918 super(ConnectionShutdown, self).__init__(
919 "RBD connection was shutdown (%s)" % message, errno)
922 class Timeout(OSError):
923 def __init__(self, message, errno=None):
924 super(Timeout, self).__init__(
925 "RBD operation timeout (%s)" % message, errno)
928 class DiskQuotaExceeded(OSError):
929 def __init__(self, message, errno=None):
930 super(DiskQuotaExceeded, self).__init__(
931 "RBD disk quota exceeded (%s)" % message, errno)
933 class OperationNotSupported(OSError):
934 def __init__(self, message, errno=None):
935 super(OperationNotSupported, self).__init__(
936 "RBD operation not supported (%s)" % message, errno)
938 class OperationCanceled(OSError):
939 def __init__(self, message, errno=None):
940 super(OperationCanceled, self).__init__(
941 "RBD operation canceled (%s)" % message, errno)
943 cdef errno_to_exception = {
944 errno.EPERM : PermissionError,
945 errno.ENOENT : ImageNotFound,
947 errno.ENOSPC : NoSpace,
948 errno.EEXIST : ImageExists,
949 errno.EINVAL : InvalidArgument,
950 errno.EROFS : ReadOnlyImage,
951 errno.EBUSY : ImageBusy,
952 errno.ENOTEMPTY : ImageHasSnapshots,
953 errno.ENOSYS : FunctionNotSupported,
954 errno.EDOM : ArgumentOutOfRange,
955 errno.ESHUTDOWN : ConnectionShutdown,
956 errno.ETIMEDOUT : Timeout,
957 errno.EDQUOT : DiskQuotaExceeded,
958 errno.EOPNOTSUPP : OperationNotSupported,
959 ECANCELED : OperationCanceled,
962 cdef group_errno_to_exception = {
963 errno.EPERM : PermissionError,
964 errno.ENOENT : ObjectNotFound,
966 errno.ENOSPC : NoSpace,
967 errno.EEXIST : ObjectExists,
968 errno.EINVAL : InvalidArgument,
969 errno.EROFS : ReadOnlyImage,
970 errno.EBUSY : ImageBusy,
971 errno.ENOTEMPTY : ImageHasSnapshots,
972 errno.ENOSYS : FunctionNotSupported,
973 errno.EDOM : ArgumentOutOfRange,
974 errno.ESHUTDOWN : ConnectionShutdown,
975 errno.ETIMEDOUT : Timeout,
976 errno.EDQUOT : DiskQuotaExceeded,
977 errno.EOPNOTSUPP : OperationNotSupported,
978 ECANCELED : OperationCanceled,
981 cdef make_ex(ret, msg, exception_map=errno_to_exception):
983 Translate a librbd return code into an exception.
985 :param ret: the return code
987 :param msg: the error message to use
989 :returns: a subclass of :class:`Error`
992 if ret in exception_map:
993 return exception_map[ret](msg, errno=ret)
995 return OSError(msg, errno=ret)
998 cdef rados_t convert_rados(rados.Rados rados) except? NULL:
999 return <rados_t>rados.cluster
1001 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
1002 return <rados_ioctx_t>ioctx.io
1004 cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
1005 return (<object>ptr)(offset, total)
1007 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
1010 def cstr(val, name, encoding="utf-8", opt=False):
1012 Create a byte string from a Python string
1014 :param basestring val: Python string
1015 :param str name: Name of the string parameter, for exceptions
1016 :param str encoding: Encoding to use
1017 :param bool opt: If True, None is allowed
1019 :raises: :class:`InvalidArgument`
1021 if opt and val is None:
1023 if isinstance(val, bytes):
1025 elif isinstance(val, str):
1026 return val.encode(encoding)
1027 elif sys.version_info < (3, 0) and isinstance(val, unicode):
1028 return val.encode(encoding)
1030 raise InvalidArgument('%s must be a string' % name)
1032 def decode_cstr(val, encoding="utf-8"):
1034 Decode a byte string into a Python string.
1036 :param bytes val: byte string
1037 :rtype: unicode or None
1042 return val.decode(encoding)
1045 cdef char* opt_str(s) except? NULL:
1050 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
1051 cdef void *ret = realloc(ptr, size)
1053 raise MemoryError("realloc failed")
1056 RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST)
1057 RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY)
1059 cdef class Completion
1061 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
1063 Callback to oncomplete() for asynchronous operations
1065 cdef Completion cb = <Completion>args
1069 cdef class Completion(object):
1070 """completion object"""
1075 rbd_completion_t rbd_comp
1080 def __cinit__(self, image, object oncomplete):
1081 self.oncomplete = oncomplete
1083 self.persisted = False
1085 def is_complete(self):
1087 Has an asynchronous operation completed?
1089 This does not imply that the callback has finished.
1091 :returns: True if the operation is completed
1094 ret = rbd_aio_is_complete(self.rbd_comp)
1097 def wait_for_complete_and_cb(self):
1099 Wait for an asynchronous operation to complete
1101 This method waits for the callback to execute, if one was provided.
1102 It will also re-raise any exceptions raised by the callback. You
1103 should call this to "reap" asynchronous completions and ensure that
1104 any exceptions in the callbacks are handled, as an exception internal
1105 to this module may have occurred.
1108 rbd_aio_wait_for_complete(self.rbd_comp)
1111 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
1113 def get_return_value(self):
1115 Get the return value of an asychronous operation
1117 The return value is set when the operation is complete.
1119 :returns: int - return value of the operation
1122 ret = rbd_aio_get_return_value(self.rbd_comp)
1125 def __dealloc__(self):
1127 Release a completion
1129 This is automatically called when the completion object is freed.
1131 ref.Py_XDECREF(self.buf)
1133 if self.rbd_comp != NULL:
1135 rbd_aio_release(self.rbd_comp)
1136 self.rbd_comp = NULL
1138 cdef void _complete(self):
1142 self.oncomplete(self)
1143 # In the event that something raises an exception during the next 2
1144 # lines of code, we will not be able to catch it, and this may result
1145 # in the app not noticing a failed callback. However, this should only
1146 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
1147 # should not be a problem because the callback thread from librbd
1148 # ought to have SIGINT blocked.
1150 self.exc_info = sys.exc_info()
1152 cdef __persist(self):
1153 if self.oncomplete is not None and not self.persisted:
1154 # Increment our own reference count to make sure the completion
1155 # is not freed until the callback is called. The completion is
1156 # allowed to be freed if there is no callback.
1158 self.persisted = True
1160 cdef __unpersist(self):
1163 self.persisted = False
1168 This class wraps librbd CRUD functions.
1172 Get the version number of the ``librbd`` C library.
1174 :returns: a tuple of ``(major, minor, extra)`` components of the
1180 rbd_version(&major, &minor, &extra)
1181 return (major, minor, extra)
1183 def create(self, ioctx, name, size, order=None, old_format=False,
1184 features=None, stripe_unit=None, stripe_count=None,
1187 Create an rbd image.
1189 :param ioctx: the context in which to create the image
1190 :type ioctx: :class:`rados.Ioctx`
1191 :param name: what the image is called
1193 :param size: how big the image is in bytes
1195 :param order: the image is split into (2**order) byte objects
1197 :param old_format: whether to create an old-style image that
1198 is accessible by old clients, but can't
1199 use more advanced features like layering.
1200 :type old_format: bool
1201 :param features: bitmask of features to enable
1203 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1204 :type stripe_unit: int
1205 :param stripe_count: objects to stripe over before looping
1206 :type stripe_count: int
1207 :param data_pool: optional separate pool for data blocks
1208 :type data_pool: str
1209 :raises: :class:`ImageExists`
1210 :raises: :class:`TypeError`
1211 :raises: :class:`InvalidArgument`
1212 :raises: :class:`FunctionNotSupported`
1214 name = cstr(name, 'name')
1215 data_pool = cstr(data_pool, 'data_pool', opt=True)
1217 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1219 uint64_t _size = size
1221 rbd_image_options_t opts
1222 if order is not None:
1226 ((stripe_unit is not None) and stripe_unit != 0) or
1227 ((stripe_count is not None) and stripe_count != 0) or
1229 raise InvalidArgument('format 1 images do not support feature '
1230 'masks, non-default striping, nor data '
1233 ret = rbd_create(_ioctx, _name, _size, &_order)
1235 rbd_image_options_create(&opts)
1237 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
1238 1 if old_format else 2)
1239 if features is not None:
1240 rbd_image_options_set_uint64(opts,
1241 RBD_IMAGE_OPTION_FEATURES,
1243 if order is not None:
1244 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1246 if stripe_unit is not None:
1247 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1249 if stripe_count is not None:
1250 rbd_image_options_set_uint64(opts,
1251 RBD_IMAGE_OPTION_STRIPE_COUNT,
1253 if data_pool is not None:
1254 rbd_image_options_set_string(opts,
1255 RBD_IMAGE_OPTION_DATA_POOL,
1258 ret = rbd_create4(_ioctx, _name, _size, opts)
1260 rbd_image_options_destroy(opts)
1262 raise make_ex(ret, 'error creating image')
1264 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
1265 features=None, order=None, stripe_unit=None, stripe_count=None,
1268 Clone a parent rbd snapshot into a COW sparse child.
1270 :param p_ioctx: the parent context that represents the parent snap
1271 :type ioctx: :class:`rados.Ioctx`
1272 :param p_name: the parent image name
1274 :param p_snapname: the parent image snapshot name
1276 :param c_ioctx: the child context that represents the new clone
1277 :type ioctx: :class:`rados.Ioctx`
1278 :param c_name: the clone (child) name
1280 :param features: bitmask of features to enable; if set, must include layering
1282 :param order: the image is split into (2**order) byte objects
1284 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1285 :type stripe_unit: int
1286 :param stripe_count: objects to stripe over before looping
1287 :type stripe_count: int
1288 :param data_pool: optional separate pool for data blocks
1289 :type data_pool: str
1290 :raises: :class:`TypeError`
1291 :raises: :class:`InvalidArgument`
1292 :raises: :class:`ImageExists`
1293 :raises: :class:`FunctionNotSupported`
1294 :raises: :class:`ArgumentOutOfRange`
1296 p_snapname = cstr(p_snapname, 'p_snapname')
1297 p_name = cstr(p_name, 'p_name')
1298 c_name = cstr(c_name, 'c_name')
1299 data_pool = cstr(data_pool, 'data_pool', opt=True)
1301 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
1302 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
1303 char *_p_name = p_name
1304 char *_p_snapname = p_snapname
1305 char *_c_name = c_name
1306 rbd_image_options_t opts
1308 rbd_image_options_create(&opts)
1310 if features is not None:
1311 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1313 if order is not None:
1314 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1316 if stripe_unit is not None:
1317 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1319 if stripe_count is not None:
1320 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1322 if data_pool is not None:
1323 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1326 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
1327 _c_ioctx, _c_name, opts)
1329 rbd_image_options_destroy(opts)
1331 raise make_ex(ret, 'error creating clone')
1333 def list(self, ioctx):
1337 :param ioctx: determines which RADOS pool is read
1338 :type ioctx: :class:`rados.Ioctx`
1339 :returns: list -- a list of image names
1342 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1344 char *c_names = NULL
1347 c_names = <char *>realloc_chk(c_names, size)
1349 ret = rbd_list(_ioctx, c_names, &size)
1352 elif ret != -errno.ERANGE:
1353 raise make_ex(ret, 'error listing images')
1354 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
1359 def list2(self, ioctx):
1361 Iterate over the images in the pool.
1363 :param ioctx: determines which RADOS pool the image is in
1364 :type ioctx: :class:`rados.Ioctx`
1365 :returns: :class:`ImageIterator`
1367 return ImageIterator(ioctx)
1369 def remove(self, ioctx, name, on_progress=None):
1371 Delete an RBD image. This may take a long time, since it does
1372 not return until every object that comprises the image has
1373 been deleted. Note that all snapshots must be deleted before
1374 the image can be removed. If there are snapshots left,
1375 :class:`ImageHasSnapshots` is raised. If the image is still
1376 open, or the watch from a crashed client has not expired,
1377 :class:`ImageBusy` is raised.
1379 :param ioctx: determines which RADOS pool the image is in
1380 :type ioctx: :class:`rados.Ioctx`
1381 :param name: the name of the image to remove
1383 :param on_progress: optional progress callback function
1384 :type on_progress: callback function
1385 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
1386 :class:`ImageHasSnapshots`
1388 name = cstr(name, 'name')
1390 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1392 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1393 void *_prog_arg = NULL
1395 _prog_cb = &progress_callback
1396 _prog_arg = <void *>on_progress
1398 ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
1400 raise make_ex(ret, 'error removing image')
1402 def rename(self, ioctx, src, dest):
1404 Rename an RBD image.
1406 :param ioctx: determines which RADOS pool the image is in
1407 :type ioctx: :class:`rados.Ioctx`
1408 :param src: the current name of the image
1410 :param dest: the new name of the image
1412 :raises: :class:`ImageNotFound`, :class:`ImageExists`
1414 src = cstr(src, 'src')
1415 dest = cstr(dest, 'dest')
1417 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1421 ret = rbd_rename(_ioctx, _src, _dest)
1423 raise make_ex(ret, 'error renaming image')
1425 def trash_move(self, ioctx, name, delay=0):
1427 Move an RBD image to the trash.
1429 :param ioctx: determines which RADOS pool the image is in
1430 :type ioctx: :class:`rados.Ioctx`
1431 :param name: the name of the image to remove
1433 :param delay: time delay in seconds before the image can be deleted
1436 :raises: :class:`ImageNotFound`
1438 name = cstr(name, 'name')
1440 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1442 uint64_t _delay = delay
1444 ret = rbd_trash_move(_ioctx, _name, _delay)
1446 raise make_ex(ret, 'error moving image to trash')
1448 def trash_purge(self, ioctx, expire_ts=None, threshold=-1):
1450 Delete RBD images from trash in bulk.
1452 By default it removes images with deferment end time less than now.
1454 The timestamp is configurable, e.g. delete images that have expired a
1457 If the threshold is used it deletes images until X% pool usage is met.
1459 :param ioctx: determines which RADOS pool the image is in
1460 :type ioctx: :class:`rados.Ioctx`
1461 :param expire_ts: timestamp for images to be considered as expired (UTC)
1462 :type expire_ts: datetime
1463 :param threshold: percentage of pool usage to be met (0 to 1)
1464 :type threshold: float
1467 expire_epoch_ts = time.mktime(expire_ts.timetuple())
1472 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1473 time_t _expire_ts = expire_epoch_ts
1474 float _threshold = threshold
1476 ret = rbd_trash_purge(_ioctx, _expire_ts, _threshold)
1478 raise make_ex(ret, 'error purging images from trash')
1480 def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
1482 Delete an RBD image from trash. If image deferment time has not
1483 expired :class:`PermissionError` is raised.
1485 :param ioctx: determines which RADOS pool the image is in
1486 :type ioctx: :class:`rados.Ioctx`
1487 :param image_id: the id of the image to remove
1489 :param force: force remove even if deferment time has not expired
1491 :param on_progress: optional progress callback function
1492 :type on_progress: callback function
1493 :raises: :class:`ImageNotFound`, :class:`PermissionError`
1495 image_id = cstr(image_id, 'image_id')
1497 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1498 char *_image_id = image_id
1500 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1501 void *_prog_arg = NULL
1503 _prog_cb = &progress_callback
1504 _prog_arg = <void *>on_progress
1506 ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
1507 _prog_cb, _prog_arg)
1509 raise make_ex(ret, 'error deleting image from trash')
1511 def trash_get(self, ioctx, image_id):
1513 Retrieve RBD image info from trash.
1515 :param ioctx: determines which RADOS pool the image is in
1516 :type ioctx: :class:`rados.Ioctx`
1517 :param image_id: the id of the image to restore
1519 :returns: dict - contains the following keys:
1521 * ``id`` (str) - image id
1523 * ``name`` (str) - image name
1525 * ``source`` (str) - source of deletion
1527 * ``deletion_time`` (datetime) - time of deletion
1529 * ``deferment_end_time`` (datetime) - time that an image is allowed
1530 to be removed from trash
1532 :raises: :class:`ImageNotFound`
1534 image_id = cstr(image_id, 'image_id')
1536 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1537 char *_image_id = image_id
1538 rbd_trash_image_info_t c_info
1540 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
1542 raise make_ex(ret, 'error retrieving image from trash')
1544 __source_string = ['USER', 'MIRRORING', 'MIGRATION', 'REMOVING']
1546 'id' : decode_cstr(c_info.id),
1547 'name' : decode_cstr(c_info.name),
1548 'source' : __source_string[c_info.source],
1549 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
1550 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
1552 rbd_trash_get_cleanup(&c_info)
1555 def trash_list(self, ioctx):
1557 List all entries from trash.
1559 :param ioctx: determines which RADOS pool the image is in
1560 :type ioctx: :class:`rados.Ioctx`
1561 :returns: :class:`TrashIterator`
1563 return TrashIterator(ioctx)
1565 def trash_restore(self, ioctx, image_id, name):
1567 Restore an RBD image from trash.
1569 :param ioctx: determines which RADOS pool the image is in
1570 :type ioctx: :class:`rados.Ioctx`
1571 :param image_id: the id of the image to restore
1573 :param name: the new name of the restored image
1575 :raises: :class:`ImageNotFound`
1577 image_id = cstr(image_id, 'image_id')
1578 name = cstr(name, 'name')
1580 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1581 char *_image_id = image_id
1584 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1586 raise make_ex(ret, 'error restoring image from trash')
1588 def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
1589 features=None, order=None, stripe_unit=None, stripe_count=None,
1592 Prepare an RBD image migration.
1594 :param ioctx: determines which RADOS pool the image is in
1595 :type ioctx: :class:`rados.Ioctx`
1596 :param image_name: the current name of the image
1598 :param dest_ioctx: determines which pool to migration into
1599 :type dest_ioctx: :class:`rados.Ioctx`
1600 :param dest_image_name: the name of the destination image (may be the same image)
1601 :type dest_image_name: str
1602 :param features: bitmask of features to enable; if set, must include layering
1604 :param order: the image is split into (2**order) byte objects
1606 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1607 :type stripe_unit: int
1608 :param stripe_count: objects to stripe over before looping
1609 :type stripe_count: int
1610 :param data_pool: optional separate pool for data blocks
1611 :type data_pool: str
1612 :raises: :class:`TypeError`
1613 :raises: :class:`InvalidArgument`
1614 :raises: :class:`ImageExists`
1615 :raises: :class:`FunctionNotSupported`
1616 :raises: :class:`ArgumentOutOfRange`
1618 image_name = cstr(image_name, 'image_name')
1619 dest_image_name = cstr(dest_image_name, 'dest_image_name')
1621 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1622 char *_image_name = image_name
1623 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1624 char *_dest_image_name = dest_image_name
1625 rbd_image_options_t opts
1627 rbd_image_options_create(&opts)
1629 if features is not None:
1630 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1632 if order is not None:
1633 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1635 if stripe_unit is not None:
1636 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1638 if stripe_count is not None:
1639 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1641 if data_pool is not None:
1642 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1645 ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
1646 _dest_image_name, opts)
1648 rbd_image_options_destroy(opts)
1650 raise make_ex(ret, 'error migrating image %s' % (image_name))
1652 def migration_execute(self, ioctx, image_name, on_progress=None):
1654 Execute a prepared RBD image migration.
1656 :param ioctx: determines which RADOS pool the image is in
1657 :type ioctx: :class:`rados.Ioctx`
1658 :param image_name: the name of the image
1659 :type image_name: str
1660 :param on_progress: optional progress callback function
1661 :type on_progress: callback function
1662 :raises: :class:`ImageNotFound`
1664 image_name = cstr(image_name, 'image_name')
1666 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1667 char *_image_name = image_name
1668 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1669 void *_prog_arg = NULL
1671 _prog_cb = &progress_callback
1672 _prog_arg = <void *>on_progress
1674 ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
1675 _prog_cb, _prog_arg)
1677 raise make_ex(ret, 'error aborting migration')
1679 def migration_commit(self, ioctx, image_name, on_progress=None):
1681 Commit an executed RBD image migration.
1683 :param ioctx: determines which RADOS pool the image is in
1684 :type ioctx: :class:`rados.Ioctx`
1685 :param image_name: the name of the image
1686 :type image_name: str
1687 :param on_progress: optional progress callback function
1688 :type on_progress: callback function
1689 :raises: :class:`ImageNotFound`
1691 image_name = cstr(image_name, 'image_name')
1693 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1694 char *_image_name = image_name
1695 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1696 void *_prog_arg = NULL
1698 _prog_cb = &progress_callback
1699 _prog_arg = <void *>on_progress
1701 ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
1702 _prog_cb, _prog_arg)
1704 raise make_ex(ret, 'error aborting migration')
1706 def migration_abort(self, ioctx, image_name, on_progress=None):
1708 Cancel a previously started but interrupted migration.
1710 :param ioctx: determines which RADOS pool the image is in
1711 :type ioctx: :class:`rados.Ioctx`
1712 :param image_name: the name of the image
1713 :type image_name: str
1714 :param on_progress: optional progress callback function
1715 :type on_progress: callback function
1716 :raises: :class:`ImageNotFound`
1718 image_name = cstr(image_name, 'image_name')
1720 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1721 char *_image_name = image_name
1722 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1723 void *_prog_arg = NULL
1725 _prog_cb = &progress_callback
1726 _prog_arg = <void *>on_progress
1728 ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
1729 _prog_cb, _prog_arg)
1731 raise make_ex(ret, 'error aborting migration')
1733 def migration_status(self, ioctx, image_name):
1735 Return RBD image migration status.
1737 :param ioctx: determines which RADOS pool the image is in
1738 :type ioctx: :class:`rados.Ioctx`
1739 :param image_name: the name of the image
1740 :type image_name: str
1741 :returns: dict - contains the following keys:
1743 * ``source_pool_id`` (int) - source image pool id
1745 * ``source_pool_namespace`` (str) - source image pool namespace
1747 * ``source_image_name`` (str) - source image name
1749 * ``source_image_id`` (str) - source image id
1751 * ``dest_pool_id`` (int) - destination image pool id
1753 * ``dest_pool_namespace`` (str) - destination image pool namespace
1755 * ``dest_image_name`` (str) - destination image name
1757 * ``dest_image_id`` (str) - destination image id
1759 * ``state`` (int) - current migration state
1761 * ``state_description`` (str) - migration state description
1763 :raises: :class:`ImageNotFound`
1765 image_name = cstr(image_name, 'image_name')
1767 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1768 char *_image_name = image_name
1769 rbd_image_migration_status_t c_status
1771 ret = rbd_migration_status(_ioctx, _image_name, &c_status,
1774 raise make_ex(ret, 'error getting migration status')
1777 'source_pool_id' : c_status.source_pool_id,
1778 'source_pool_namespace' : decode_cstr(c_status.source_pool_namespace),
1779 'source_image_name' : decode_cstr(c_status.source_image_name),
1780 'source_image_id' : decode_cstr(c_status.source_image_id),
1781 'dest_pool_id' : c_status.source_pool_id,
1782 'dest_pool_namespace' : decode_cstr(c_status.dest_pool_namespace),
1783 'dest_image_name' : decode_cstr(c_status.dest_image_name),
1784 'dest_image_id' : decode_cstr(c_status.dest_image_id),
1785 'state' : c_status.state,
1786 'state_description' : decode_cstr(c_status.state_description)
1789 rbd_migration_status_cleanup(&c_status)
1793 def mirror_site_name_get(self, rados):
1795 Get the local cluster's friendly site name
1797 :param rados: cluster connection
1798 :type rados: :class: rados.Rados
1799 :returns: str - local site name
1802 rados_t _rados = convert_rados(rados)
1803 char *_site_name = NULL
1804 size_t _max_size = 512
1807 _site_name = <char *>realloc_chk(_site_name, _max_size)
1809 ret = rbd_mirror_site_name_get(_rados, _site_name,
1813 elif ret != -errno.ERANGE:
1814 raise make_ex(ret, 'error getting site name')
1815 return decode_cstr(_site_name)
1819 def mirror_site_name_set(self, rados, site_name):
1821 Set the local cluster's friendly site name
1823 :param rados: cluster connection
1824 :type rados: :class: rados.Rados
1825 :param site_name: friendly site name
1828 site_name = cstr(site_name, 'site_name')
1830 rados_t _rados = convert_rados(rados)
1831 char *_site_name = site_name
1833 ret = rbd_mirror_site_name_set(_rados, _site_name)
1835 raise make_ex(ret, 'error setting mirror site name')
1837 def mirror_mode_get(self, ioctx):
1839 Get pool mirror mode.
1841 :param ioctx: determines which RADOS pool is read
1842 :type ioctx: :class:`rados.Ioctx`
1843 :returns: int - pool mirror mode
1846 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1847 rbd_mirror_mode_t mirror_mode
1849 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1851 raise make_ex(ret, 'error getting mirror mode')
1854 def mirror_mode_set(self, ioctx, mirror_mode):
1856 Set pool mirror mode.
1858 :param ioctx: determines which RADOS pool is written
1859 :type ioctx: :class:`rados.Ioctx`
1860 :param mirror_mode: mirror mode to set
1861 :type mirror_mode: int
1864 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1865 rbd_mirror_mode_t _mirror_mode = mirror_mode
1867 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1869 raise make_ex(ret, 'error setting mirror mode')
1871 def mirror_uuid_get(self, ioctx):
1873 Get pool mirror uuid
1875 :param ioctx: determines which RADOS pool is read
1876 :type ioctx: :class:`rados.Ioctx`
1877 :returns: ste - pool mirror uuid
1880 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1882 size_t _max_size = 512
1885 _uuid = <char *>realloc_chk(_uuid, _max_size)
1887 ret = rbd_mirror_uuid_get(_ioctx, _uuid, &_max_size)
1890 elif ret != -errno.ERANGE:
1891 raise make_ex(ret, 'error retrieving mirror uuid')
1892 return decode_cstr(_uuid)
1896 def mirror_peer_bootstrap_create(self, ioctx):
1898 Creates a new RBD mirroring bootstrap token for an
1901 :param ioctx: determines which RADOS pool is written
1902 :type ioctx: :class:`rados.Ioctx`
1903 :returns: str - bootstrap token
1906 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1908 size_t _max_size = 512
1911 _token = <char *>realloc_chk(_token, _max_size)
1913 ret = rbd_mirror_peer_bootstrap_create(_ioctx, _token,
1917 elif ret != -errno.ERANGE:
1918 raise make_ex(ret, 'error creating bootstrap token')
1919 return decode_cstr(_token)
1923 def mirror_peer_bootstrap_import(self, ioctx, direction, token):
1925 Import a bootstrap token from an external cluster to
1926 auto-configure the mirror peer.
1928 :param ioctx: determines which RADOS pool is written
1929 :type ioctx: :class:`rados.Ioctx`
1930 :param direction: mirror peer direction
1931 :type direction: int
1932 :param token: bootstrap token
1935 token = cstr(token, 'token')
1937 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1938 rbd_mirror_peer_direction_t _direction = direction
1939 char *_token = token
1941 ret = rbd_mirror_peer_bootstrap_import(_ioctx, _direction, _token)
1943 raise make_ex(ret, 'error importing bootstrap token')
1945 def mirror_peer_add(self, ioctx, site_name, client_name,
1946 direction=RBD_MIRROR_PEER_DIRECTION_RX_TX):
1950 :param ioctx: determines which RADOS pool is used
1951 :type ioctx: :class:`rados.Ioctx`
1952 :param site_name: mirror peer site name
1953 :type site_name: str
1954 :param client_name: mirror peer client name
1955 :type client_name: str
1956 :param direction: the direction of the mirroring
1957 :type direction: int
1958 :returns: str - peer uuid
1960 site_name = cstr(site_name, 'site_name')
1961 client_name = cstr(client_name, 'client_name')
1963 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1965 size_t _uuid_max_length = 512
1966 rbd_mirror_peer_direction_t _direction = direction
1967 char *_site_name = site_name
1968 char *_client_name = client_name
1970 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1971 ret = rbd_mirror_peer_site_add(_ioctx, _uuid, _uuid_max_length,
1972 _direction, _site_name, _client_name)
1974 raise make_ex(ret, 'error adding mirror peer')
1975 return decode_cstr(_uuid)
1979 def mirror_peer_remove(self, ioctx, uuid):
1983 :param ioctx: determines which RADOS pool is used
1984 :type ioctx: :class:`rados.Ioctx`
1985 :param uuid: peer uuid
1988 uuid = cstr(uuid, 'uuid')
1990 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1993 ret = rbd_mirror_peer_site_remove(_ioctx, _uuid)
1995 raise make_ex(ret, 'error removing mirror peer')
1997 def mirror_peer_list(self, ioctx):
1999 Iterate over the peers of a pool.
2001 :param ioctx: determines which RADOS pool is read
2002 :type ioctx: :class:`rados.Ioctx`
2003 :returns: :class:`MirrorPeerIterator`
2005 return MirrorPeerIterator(ioctx)
2007 def mirror_peer_set_client(self, ioctx, uuid, client_name):
2009 Set mirror peer client name
2011 :param ioctx: determines which RADOS pool is written
2012 :type ioctx: :class:`rados.Ioctx`
2013 :param uuid: uuid of the mirror peer
2015 :param client_name: client name of the mirror peer to set
2016 :type client_name: str
2018 uuid = cstr(uuid, 'uuid')
2019 client_name = cstr(client_name, 'client_name')
2021 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2023 char *_client_name = client_name
2025 ret = rbd_mirror_peer_site_set_client_name(_ioctx, _uuid,
2028 raise make_ex(ret, 'error setting mirror peer client name')
2030 def mirror_peer_set_name(self, ioctx, uuid, site_name):
2032 Set mirror peer site name
2034 :param ioctx: determines which RADOS pool is written
2035 :type ioctx: :class:`rados.Ioctx`
2036 :param uuid: uuid of the mirror peer
2038 :param site_name: site name of the mirror peer to set
2039 :type site_name: str
2041 uuid = cstr(uuid, 'uuid')
2042 site_name = cstr(site_name, 'site_name')
2044 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2046 char *_site_name = site_name
2048 ret = rbd_mirror_peer_site_set_name(_ioctx, _uuid, _site_name)
2050 raise make_ex(ret, 'error setting mirror peer site name')
2052 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
2053 self.mirror_peer_set_name(ioctx, uuid, cluster_name)
2055 def mirror_peer_get_attributes(self, ioctx, uuid):
2057 Get optional mirror peer attributes
2059 :param ioctx: determines which RADOS pool is written
2060 :type ioctx: :class:`rados.Ioctx`
2061 :param uuid: uuid of the mirror peer
2064 :returns: dict - contains the following keys:
2066 * ``mon_host`` (str) - monitor addresses
2068 * ``key`` (str) - CephX key
2070 uuid = cstr(uuid, 'uuid')
2072 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2076 size_t _keys_size = 512
2077 size_t _vals_size = 512
2081 _keys = <char *>realloc_chk(_keys, _keys_size)
2082 _vals = <char *>realloc_chk(_vals, _vals_size)
2084 ret = rbd_mirror_peer_site_get_attributes(
2085 _ioctx, _uuid, _keys, &_keys_size, _vals, &_vals_size,
2089 elif ret != -errno.ERANGE:
2090 raise make_ex(ret, 'error getting mirror peer attributes')
2091 keys = [decode_cstr(x) for x in _keys[:_keys_size].split(b'\0')[:-1]]
2092 vals = [decode_cstr(x) for x in _vals[:_vals_size].split(b'\0')[:-1]]
2093 return dict(zip(keys, vals))
2098 def mirror_peer_set_attributes(self, ioctx, uuid, attributes):
2100 Set optional mirror peer attributes
2102 :param ioctx: determines which RADOS pool is written
2103 :type ioctx: :class:`rados.Ioctx`
2104 :param uuid: uuid of the mirror peer
2106 :param attributes: 'mon_host' and 'key' attributes
2107 :type attributes: dict
2109 uuid = cstr(uuid, 'uuid')
2110 keys_str = b'\0'.join([cstr(x[0], 'key') for x in attributes.items()])
2111 vals_str = b'\0'.join([cstr(x[1], 'val') for x in attributes.items()])
2113 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2115 char *_keys = keys_str
2116 char *_vals = vals_str
2117 size_t _count = len(attributes)
2120 ret = rbd_mirror_peer_site_set_attributes(_ioctx, _uuid, _keys,
2123 raise make_ex(ret, 'error setting mirror peer attributes')
2125 def mirror_image_status_list(self, ioctx):
2127 Iterate over the mirror image statuses of a pool.
2129 :param ioctx: determines which RADOS pool is read
2130 :type ioctx: :class:`rados.Ioctx`
2131 :returns: :class:`MirrorImageStatusIterator`
2133 return MirrorImageStatusIterator(ioctx)
2135 def mirror_image_status_summary(self, ioctx):
2137 Get mirror image status summary of a pool.
2139 :param ioctx: determines which RADOS pool is read
2140 :type ioctx: :class:`rados.Ioctx`
2141 :returns: list - a list of (state, count) tuples
2144 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2145 rbd_mirror_image_status_state_t *states = NULL
2149 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
2150 sizeof(rbd_mirror_image_status_state_t) * maxlen)
2151 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
2153 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
2156 raise make_ex(ret, 'error getting mirror image status summary')
2157 return [(states[i], counts[i]) for i in range(maxlen)]
2162 def mirror_image_instance_id_list(self, ioctx):
2164 Iterate over the mirror image instance ids of a pool.
2166 :param ioctx: determines which RADOS pool is read
2167 :type ioctx: :class:`rados.Ioctx`
2168 :returns: :class:`MirrorImageInstanceIdIterator`
2170 return MirrorImageInstanceIdIterator(ioctx)
2172 def mirror_image_info_list(self, ioctx, mode_filter=None):
2174 Iterate over the mirror image instance ids of a pool.
2176 :param ioctx: determines which RADOS pool is read
2177 :param mode_filter: list images in this image mirror mode
2178 :type ioctx: :class:`rados.Ioctx`
2179 :returns: :class:`MirrorImageInfoIterator`
2181 return MirrorImageInfoIterator(ioctx, mode_filter)
2183 def pool_metadata_get(self, ioctx, key):
2185 Get pool metadata for the given key.
2187 :param ioctx: determines which RADOS pool is read
2188 :type ioctx: :class:`rados.Ioctx`
2189 :param key: metadata key
2191 :returns: str - metadata value
2193 key = cstr(key, 'key')
2195 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2202 value = <char *>realloc_chk(value, size)
2204 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2205 if ret != -errno.ERANGE:
2207 if ret == -errno.ENOENT:
2208 raise KeyError('no metadata %s' % (key))
2210 raise make_ex(ret, 'error getting metadata %s' % (key))
2211 return decode_cstr(value)
2215 def pool_metadata_set(self, ioctx, key, value):
2217 Set pool metadata for the given key.
2219 :param ioctx: determines which RADOS pool is read
2220 :type ioctx: :class:`rados.Ioctx`
2221 :param key: metadata key
2223 :param value: metadata value
2226 key = cstr(key, 'key')
2227 value = cstr(value, 'value')
2229 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2231 char *_value = value
2233 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2236 raise make_ex(ret, 'error setting metadata %s' % (key))
2238 def pool_metadata_remove(self, ioctx, key):
2240 Remove pool metadata for the given key.
2242 :param ioctx: determines which RADOS pool is read
2243 :type ioctx: :class:`rados.Ioctx`
2244 :param key: metadata key
2246 :returns: str - metadata value
2248 key = cstr(key, 'key')
2250 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2253 ret = rbd_pool_metadata_remove(_ioctx, _key)
2255 if ret == -errno.ENOENT:
2256 raise KeyError('no metadata %s' % (key))
2258 raise make_ex(ret, 'error removing metadata %s' % (key))
2260 def pool_metadata_list(self, ioctx):
2264 :returns: :class:`PoolMetadataIterator`
2266 return PoolMetadataIterator(ioctx)
2268 def config_list(self, ioctx):
2270 List pool-level config overrides.
2272 :returns: :class:`ConfigPoolIterator`
2274 return ConfigPoolIterator(ioctx)
2276 def config_get(self, ioctx, key):
2278 Get a pool-level configuration override.
2280 :param ioctx: determines which RADOS pool is read
2281 :type ioctx: :class:`rados.Ioctx`
2284 :returns: str - value
2286 conf_key = 'conf_' + key
2287 conf_key = cstr(conf_key, 'key')
2289 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2290 char *_key = conf_key
2296 value = <char *>realloc_chk(value, size)
2298 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2299 if ret != -errno.ERANGE:
2301 if ret == -errno.ENOENT:
2302 raise KeyError('no config %s for pool %s' % (key, ioctx.get_pool_name()))
2304 raise make_ex(ret, 'error getting config %s for pool %s' %
2305 (key, ioctx.get_pool_name()))
2306 return decode_cstr(value)
2310 def config_set(self, ioctx, key, value):
2312 Get a pool-level configuration override.
2314 :param ioctx: determines which RADOS pool is read
2315 :type ioctx: :class:`rados.Ioctx`
2321 conf_key = 'conf_' + key
2322 conf_key = cstr(conf_key, 'key')
2323 value = cstr(value, 'value')
2325 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2326 char *_key = conf_key
2327 char *_value = value
2329 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2332 raise make_ex(ret, 'error setting config %s for pool %s' %
2333 (key, ioctx.get_pool_name()))
2335 def config_remove(self, ioctx, key):
2337 Remove a pool-level configuration override.
2339 :param ioctx: determines which RADOS pool is read
2340 :type ioctx: :class:`rados.Ioctx`
2343 :returns: str - value
2345 conf_key = 'conf_' + key
2346 conf_key = cstr(conf_key, 'key')
2348 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2349 char *_key = conf_key
2351 ret = rbd_pool_metadata_remove(_ioctx, _key)
2353 if ret == -errno.ENOENT:
2354 raise KeyError('no config %s for pool %s' %
2355 (key, ioctx.get_pool_name()))
2357 raise make_ex(ret, 'error removing config %s for pool %s' %
2358 (key, ioctx.get_pool_name()))
2360 def group_create(self, ioctx, name):
2364 :param ioctx: determines which RADOS pool is used
2365 :type ioctx: :class:`rados.Ioctx`
2366 :param name: the name of the group
2368 :raises: :class:`ObjectExists`
2369 :raises: :class:`InvalidArgument`
2370 :raises: :class:`FunctionNotSupported`
2372 name = cstr(name, 'name')
2375 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2377 ret = rbd_group_create(_ioctx, _name)
2379 raise make_ex(ret, 'error creating group %s' % name, group_errno_to_exception)
2381 def group_remove(self, ioctx, name):
2383 Delete an RBD group. This may take a long time, since it does
2384 not return until every image in the group has been removed
2387 :param ioctx: determines which RADOS pool the group is in
2388 :type ioctx: :class:`rados.Ioctx`
2389 :param name: the name of the group to remove
2391 :raises: :class:`ObjectNotFound`
2392 :raises: :class:`InvalidArgument`
2393 :raises: :class:`FunctionNotSupported`
2395 name = cstr(name, 'name')
2397 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2400 ret = rbd_group_remove(_ioctx, _name)
2402 raise make_ex(ret, 'error removing group', group_errno_to_exception)
2404 def group_list(self, ioctx):
2408 :param ioctx: determines which RADOS pool is read
2409 :type ioctx: :class:`rados.Ioctx`
2410 :returns: list -- a list of groups names
2411 :raises: :class:`FunctionNotSupported`
2414 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2416 char *c_names = NULL
2419 c_names = <char *>realloc_chk(c_names, size)
2421 ret = rbd_group_list(_ioctx, c_names, &size)
2424 elif ret != -errno.ERANGE:
2425 raise make_ex(ret, 'error listing groups', group_errno_to_exception)
2426 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
2431 def group_rename(self, ioctx, src, dest):
2433 Rename an RBD group.
2435 :param ioctx: determines which RADOS pool the group is in
2436 :type ioctx: :class:`rados.Ioctx`
2437 :param src: the current name of the group
2439 :param dest: the new name of the group
2441 :raises: :class:`ObjectExists`
2442 :raises: :class:`ObjectNotFound`
2443 :raises: :class:`InvalidArgument`
2444 :raises: :class:`FunctionNotSupported`
2446 src = cstr(src, 'src')
2447 dest = cstr(dest, 'dest')
2449 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2453 ret = rbd_group_rename(_ioctx, _src, _dest)
2455 raise make_ex(ret, 'error renaming group')
2457 def namespace_create(self, ioctx, name):
2459 Create an RBD namespace within a pool
2461 :param ioctx: determines which RADOS pool
2462 :type ioctx: :class:`rados.Ioctx`
2463 :param name: namespace name
2466 name = cstr(name, 'name')
2468 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2469 const char *_name = name
2471 ret = rbd_namespace_create(_ioctx, _name)
2473 raise make_ex(ret, 'error creating namespace')
2475 def namespace_remove(self, ioctx, name):
2477 Remove an RBD namespace from a pool
2479 :param ioctx: determines which RADOS pool
2480 :type ioctx: :class:`rados.Ioctx`
2481 :param name: namespace name
2484 name = cstr(name, 'name')
2486 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2487 const char *_name = name
2489 ret = rbd_namespace_remove(_ioctx, _name)
2491 raise make_ex(ret, 'error removing namespace')
2493 def namespace_exists(self, ioctx, name):
2495 Verifies if a namespace exists within a pool
2497 :param ioctx: determines which RADOS pool
2498 :type ioctx: :class:`rados.Ioctx`
2499 :param name: namespace name
2501 :returns: bool - true if namespace exists
2503 name = cstr(name, 'name')
2505 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2506 const char *_name = name
2507 bint _exists = False
2509 ret = rbd_namespace_exists(_ioctx, _name, &_exists)
2511 raise make_ex(ret, 'error verifying namespace')
2512 return bool(_exists != 0)
2514 def namespace_list(self, ioctx):
2516 List all namespaces within a pool
2518 :param ioctx: determines which RADOS pool
2519 :type ioctx: :class:`rados.Ioctx`
2520 :returns: list - collection of namespace names
2523 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2528 _names = <char *>realloc_chk(_names, _size)
2530 ret = rbd_namespace_list(_ioctx, _names, &_size)
2533 elif ret != -errno.ERANGE:
2534 raise make_ex(ret, 'error listing namespaces')
2535 return [decode_cstr(name) for name in _names[:_size].split(b'\0')
2540 def pool_init(self, ioctx, force):
2542 Initialize an RBD pool
2543 :param ioctx: determines which RADOS pool
2544 :type ioctx: :class:`rados.Ioctx`
2545 :param force: force init
2549 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2552 ret = rbd_pool_init(_ioctx, _force)
2554 raise make_ex(ret, 'error initializing pool')
2556 def pool_stats_get(self, ioctx):
2558 Return RBD pool stats
2560 :param ioctx: determines which RADOS pool
2561 :type ioctx: :class:`rados.Ioctx`
2562 :returns: dict - contains the following keys:
2564 * ``image_count`` (int) - image count
2566 * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
2568 * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
2570 * ``image_snap_count`` (int) - image snap count
2572 * ``trash_count`` (int) - trash image count
2574 * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
2576 * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
2578 * ``trash_snap_count`` (int) - trash snap count
2582 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2583 uint64_t _image_count = 0
2584 uint64_t _image_provisioned_bytes = 0
2585 uint64_t _image_max_provisioned_bytes = 0
2586 uint64_t _image_snap_count = 0
2587 uint64_t _trash_count = 0
2588 uint64_t _trash_provisioned_bytes = 0
2589 uint64_t _trash_max_provisioned_bytes = 0
2590 uint64_t _trash_snap_count = 0
2591 rbd_pool_stats_t _stats
2593 rbd_pool_stats_create(&_stats)
2594 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
2596 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
2597 &_image_provisioned_bytes)
2598 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
2599 &_image_max_provisioned_bytes)
2600 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
2602 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
2604 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
2605 &_trash_provisioned_bytes)
2606 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
2607 &_trash_max_provisioned_bytes)
2608 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
2612 ret = rbd_pool_stats_get(_ioctx, _stats)
2614 raise make_ex(ret, 'error retrieving pool stats')
2616 return {'image_count': _image_count,
2617 'image_provisioned_bytes': _image_provisioned_bytes,
2618 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
2619 'image_snap_count': _image_snap_count,
2620 'trash_count': _trash_count,
2621 'trash_provisioned_bytes': _trash_provisioned_bytes,
2622 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
2623 'trash_snap_count': _trash_snap_count}
2625 rbd_pool_stats_destroy(_stats)
2627 def features_to_string(self, features):
2629 Convert features bitmask to str.
2631 :param features: feature bitmask
2633 :returns: str - the features str of the image
2634 :raises: :class:`InvalidArgument`
2637 int ret = -errno.ERANGE
2638 uint64_t _features = features
2640 char *str_features = NULL
2642 while ret == -errno.ERANGE:
2643 str_features = <char *>realloc_chk(str_features, size)
2645 ret = rbd_features_to_string(_features, str_features, &size)
2648 raise make_ex(ret, 'error converting features bitmask to str')
2649 return decode_cstr(str_features)
2653 def features_from_string(self, str_features):
2655 Get features bitmask from str, if str_features is empty, it will return
2656 RBD_FEATURES_DEFAULT.
2658 :param str_features: feature str
2659 :type str_features: str
2660 :returns: int - the features bitmask of the image
2661 :raises: :class:`InvalidArgument`
2663 str_features = cstr(str_features, 'str_features')
2665 const char *_str_features = str_features
2668 ret = rbd_features_from_string(_str_features, &features)
2670 raise make_ex(ret, 'error getting features bitmask from str')
2674 cdef class MirrorPeerIterator(object):
2676 Iterator over mirror peer info for a pool.
2678 Yields a dictionary containing information about a peer.
2682 * ``uuid`` (str) - uuid of the peer
2684 * ``direction`` (int) - direction enum
2686 * ``site_name`` (str) - cluster name of the peer
2688 * ``mirror_uuid`` (str) - mirror uuid of the peer
2690 * ``client_name`` (str) - client name of the peer
2694 rbd_mirror_peer_site_t *peers
2697 def __init__(self, ioctx):
2699 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2703 self.peers = <rbd_mirror_peer_site_t *>realloc_chk(
2704 self.peers, self.num_peers * sizeof(rbd_mirror_peer_site_t))
2706 ret = rbd_mirror_peer_site_list(_ioctx, self.peers,
2709 if ret == -errno.ERANGE:
2712 raise make_ex(ret, 'error listing peers')
2716 for i in range(self.num_peers):
2718 'uuid' : decode_cstr(self.peers[i].uuid),
2719 'direction' : int(self.peers[i].direction),
2720 'site_name' : decode_cstr(self.peers[i].site_name),
2721 'cluster_name' : decode_cstr(self.peers[i].site_name),
2722 'mirror_uuid' : decode_cstr(self.peers[i].mirror_uuid),
2723 'client_name' : decode_cstr(self.peers[i].client_name),
2726 def __dealloc__(self):
2728 rbd_mirror_peer_site_list_cleanup(self.peers, self.num_peers)
2731 cdef class MirrorImageStatusIterator(object):
2733 Iterator over mirror image status for a pool.
2735 Yields a dictionary containing mirror status of an image.
2739 * ``name`` (str) - mirror image name
2741 * ``id`` (str) - mirror image id
2743 * ``info`` (dict) - mirror image info
2745 * ``state`` (int) - status mirror state
2747 * ``description`` (str) - status description
2749 * ``last_update`` (datetime) - last status update time
2751 * ``up`` (bool) - is mirroring agent up
2753 * ``remote_statuses`` (array) -
2755 * ``mirror uuid`` (str) - remote mirror uuid
2757 * ``state`` (int) - status mirror state
2759 * ``description`` (str) - status description
2761 * ``last_update`` (datetime) - last status update time
2763 * ``up`` (bool) - is mirroring agent up
2771 rbd_mirror_image_site_status_t *s_status
2772 rbd_mirror_image_global_status_t *images
2775 def __init__(self, ioctx):
2776 self.ioctx = convert_ioctx(ioctx)
2777 self.max_read = 1024
2778 self.last_read = strdup("")
2779 self.image_ids = <char **>realloc_chk(NULL,
2780 sizeof(char *) * self.max_read)
2781 self.images = <rbd_mirror_image_global_status_t *>realloc_chk(NULL,
2782 sizeof(rbd_mirror_image_global_status_t) * self.max_read)
2784 self.get_next_chunk()
2788 while self.size > 0:
2789 for i in range(self.size):
2793 for x in range(self.images[i].site_statuses_count):
2794 s_status = &self.images[i].site_statuses[x]
2796 'state' : s_status.state,
2797 'description' : decode_cstr(s_status.description),
2798 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
2801 mirror_uuid = decode_cstr(s_status.mirror_uuid)
2802 if mirror_uuid == '':
2803 local_status = site_status
2805 site_status['mirror_uuid'] = mirror_uuid
2806 site_statuses += site_status
2809 'name' : decode_cstr(self.images[i].name),
2810 'id' : decode_cstr(self.image_ids[i]),
2812 'global_id' : decode_cstr(self.images[i].info.global_id),
2813 'state' : self.images[i].info.state,
2815 'remote_statuses': site_statuses,
2818 status.update(local_status)
2820 if self.size < self.max_read:
2822 self.get_next_chunk()
2824 def __dealloc__(self):
2825 rbd_mirror_image_global_status_list_cleanup(self.image_ids, self.images,
2828 free(self.last_read)
2830 free(self.image_ids)
2834 def get_next_chunk(self):
2836 rbd_mirror_image_global_status_list_cleanup(self.image_ids,
2841 ret = rbd_mirror_image_global_status_list(self.ioctx,
2845 self.images, &self.size)
2847 raise make_ex(ret, 'error listing mirror images status')
2849 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2850 free(self.last_read)
2851 self.last_read = strdup(last_read)
2853 free(self.last_read)
2854 self.last_read = strdup("")
2856 cdef class MirrorImageInstanceIdIterator(object):
2858 Iterator over mirror image instance id for a pool.
2860 Yields ``(image_id, instance_id)`` tuple.
2871 def __init__(self, ioctx):
2872 self.ioctx = convert_ioctx(ioctx)
2873 self.max_read = 1024
2874 self.last_read = strdup("")
2875 self.image_ids = <char **>realloc_chk(NULL,
2876 sizeof(char *) * self.max_read)
2877 self.instance_ids = <char **>realloc_chk(NULL,
2878 sizeof(char *) * self.max_read)
2880 self.get_next_chunk()
2883 while self.size > 0:
2884 for i in range(self.size):
2885 yield (decode_cstr(self.image_ids[i]),
2886 decode_cstr(self.instance_ids[i]))
2887 if self.size < self.max_read:
2889 self.get_next_chunk()
2891 def __dealloc__(self):
2892 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2893 self.instance_ids, self.size)
2895 free(self.last_read)
2897 free(self.image_ids)
2898 if self.instance_ids:
2899 free(self.instance_ids)
2901 def get_next_chunk(self):
2903 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2908 ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read,
2914 raise make_ex(ret, 'error listing mirror images instance ids')
2916 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2917 free(self.last_read)
2918 self.last_read = strdup(last_read)
2920 free(self.last_read)
2921 self.last_read = strdup("")
2923 cdef class MirrorImageInfoIterator(object):
2925 Iterator over mirror image info for a pool.
2927 Yields ``(image_id, info)`` tuple.
2932 rbd_mirror_image_mode_t mode_filter
2933 rbd_mirror_image_mode_t *mode_filter_ptr
2937 rbd_mirror_image_info_t *info_entries
2938 rbd_mirror_image_mode_t *mode_entries
2941 def __init__(self, ioctx, mode_filter):
2942 self.ioctx = convert_ioctx(ioctx)
2943 if mode_filter is not None:
2944 self.mode_filter = mode_filter
2945 self.mode_filter_ptr = &self.mode_filter
2947 self.mode_filter_ptr = NULL
2948 self.max_read = 1024
2949 self.last_read = strdup("")
2950 self.image_ids = <char **>realloc_chk(NULL,
2951 sizeof(char *) * self.max_read)
2952 self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
2953 sizeof(rbd_mirror_image_info_t) * self.max_read)
2954 self.mode_entries = <rbd_mirror_image_mode_t *>realloc_chk(NULL,
2955 sizeof(rbd_mirror_image_mode_t) * self.max_read)
2957 self.get_next_chunk()
2960 while self.size > 0:
2961 for i in range(self.size):
2962 yield (decode_cstr(self.image_ids[i]),
2964 'mode' : int(self.mode_entries[i]),
2965 'global_id' : decode_cstr(self.info_entries[i].global_id),
2966 'state' : int(self.info_entries[i].state),
2967 'primary' : self.info_entries[i].primary,
2969 if self.size < self.max_read:
2971 self.get_next_chunk()
2973 def __dealloc__(self):
2974 rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries,
2977 free(self.last_read)
2979 free(self.image_ids)
2980 if self.info_entries:
2981 free(self.info_entries)
2982 if self.mode_entries:
2983 free(self.mode_entries)
2985 def get_next_chunk(self):
2987 rbd_mirror_image_info_list_cleanup(self.image_ids,
2988 self.info_entries, self.size)
2991 ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr,
2992 self.last_read, self.max_read,
2993 self.image_ids, self.mode_entries,
2994 self.info_entries, &self.size)
2996 raise make_ex(ret, 'error listing mirror image info')
2998 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2999 free(self.last_read)
3000 self.last_read = strdup(last_read)
3002 free(self.last_read)
3003 self.last_read = strdup("")
3005 cdef class PoolMetadataIterator(object):
3007 Iterator over pool metadata list.
3009 Yields ``(key, value)`` tuple.
3011 * ``key`` (str) - metadata key
3012 * ``value`` (str) - metadata value
3021 def __init__(self, ioctx):
3022 self.ioctx = convert_ioctx(ioctx)
3023 self.last_read = strdup("")
3025 self.get_next_chunk()
3028 while len(self.next_chunk) > 0:
3029 for pair in self.next_chunk:
3031 if len(self.next_chunk) < self.max_read:
3033 self.get_next_chunk()
3035 def __dealloc__(self):
3037 free(self.last_read)
3039 def get_next_chunk(self):
3042 size_t keys_size = 4096
3044 size_t vals_size = 4096
3047 c_keys = <char *>realloc_chk(c_keys, keys_size)
3048 c_vals = <char *>realloc_chk(c_vals, vals_size)
3050 ret = rbd_pool_metadata_list(self.ioctx, self.last_read,
3051 self.max_read, c_keys,
3052 &keys_size, c_vals, &vals_size)
3055 elif ret != -errno.ERANGE:
3056 raise make_ex(ret, 'error listing metadata')
3057 keys = [decode_cstr(key) for key in
3058 c_keys[:keys_size].split(b'\0') if key]
3059 vals = [decode_cstr(val) for val in
3060 c_vals[:vals_size].split(b'\0') if val]
3062 last_read = cstr(keys[-1], 'last_read')
3063 free(self.last_read)
3064 self.last_read = strdup(last_read)
3065 self.next_chunk = list(zip(keys, vals))
3070 cdef class ConfigPoolIterator(object):
3072 Iterator over pool-level overrides for a pool.
3074 Yields a dictionary containing information about an override.
3078 * ``name`` (str) - override name
3080 * ``value`` (str) - override value
3082 * ``source`` (str) - override source
3086 rbd_config_option_t *options
3089 def __init__(self, ioctx):
3091 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3093 self.num_options = 32
3095 self.options = <rbd_config_option_t *>realloc_chk(
3096 self.options, self.num_options * sizeof(rbd_config_option_t))
3098 ret = rbd_config_pool_list(_ioctx, self.options, &self.num_options)
3100 if ret == -errno.ERANGE:
3102 self.num_options = 0
3103 raise make_ex(ret, 'error listing config options')
3107 for i in range(self.num_options):
3109 'name' : decode_cstr(self.options[i].name),
3110 'value' : decode_cstr(self.options[i].value),
3111 'source' : self.options[i].source,
3114 def __dealloc__(self):
3116 rbd_config_pool_list_cleanup(self.options, self.num_options)
3119 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
3120 except? -9000 with gil:
3121 # Make sure that if we wound up with an exception from a previous callback,
3122 # we stop calling back (just in case librbd ever fails to bail out on the
3123 # first negative return, as older versions did)
3124 if exc.PyErr_Occurred():
3126 ret = (<object>cb)(offset, length, bool(write))
3131 cdef class Group(object):
3133 This class represents an RBD group. It is used to interact with
3134 snapshots and images members.
3141 cdef rados_ioctx_t _ioctx
3143 def __init__(self, ioctx, name):
3144 name = cstr(name, 'name')
3147 self._ioctx = convert_ioctx(ioctx)
3150 def __enter__(self):
3153 def __exit__(self, type_, value, traceback):
3156 def add_image(self, image_ioctx, image_name):
3158 Add an image to a group.
3160 :param image_ioctx: determines which RADOS pool the image belongs to.
3161 :type ioctx: :class:`rados.Ioctx`
3162 :param name: the name of the image to add
3165 :raises: :class:`ObjectNotFound`
3166 :raises: :class:`ObjectExists`
3167 :raises: :class:`InvalidArgument`
3168 :raises: :class:`FunctionNotSupported`
3170 image_name = cstr(image_name, 'image_name')
3172 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3173 char *_image_name = image_name
3175 ret = rbd_group_image_add(self._ioctx, self._name, _image_ioctx, _image_name)
3177 raise make_ex(ret, 'error adding image to group', group_errno_to_exception)
3179 def remove_image(self, image_ioctx, image_name):
3181 Remove an image from a group.
3183 :param image_ioctx: determines which RADOS pool the image belongs to.
3184 :type ioctx: :class:`rados.Ioctx`
3185 :param name: the name of the image to remove
3188 :raises: :class:`ObjectNotFound`
3189 :raises: :class:`InvalidArgument`
3190 :raises: :class:`FunctionNotSupported`
3192 image_name = cstr(image_name, 'image_name')
3194 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3195 char *_image_name = image_name
3197 ret = rbd_group_image_remove(self._ioctx, self._name, _image_ioctx, _image_name)
3199 raise make_ex(ret, 'error removing image from group', group_errno_to_exception)
3202 def list_images(self):
3204 Iterate over the images of a group.
3206 :returns: :class:`GroupImageIterator`
3208 return GroupImageIterator(self)
3210 def create_snap(self, snap_name):
3212 Create a snapshot for the group.
3214 :param snap_name: the name of the snapshot to create
3217 :raises: :class:`ObjectNotFound`
3218 :raises: :class:`ObjectExists`
3219 :raises: :class:`InvalidArgument`
3220 :raises: :class:`FunctionNotSupported`
3222 snap_name = cstr(snap_name, 'snap_name')
3224 char *_snap_name = snap_name
3226 ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
3228 raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
3230 def remove_snap(self, snap_name):
3232 Remove a snapshot from the group.
3234 :param snap_name: the name of the snapshot to remove
3237 :raises: :class:`ObjectNotFound`
3238 :raises: :class:`InvalidArgument`
3239 :raises: :class:`FunctionNotSupported`
3241 snap_name = cstr(snap_name, 'snap_name')
3243 char *_snap_name = snap_name
3245 ret = rbd_group_snap_remove(self._ioctx, self._name, _snap_name)
3247 raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
3249 def rename_snap(self, old_snap_name, new_snap_name):
3251 Rename group's snapshot.
3253 :raises: :class:`ObjectNotFound`
3254 :raises: :class:`ObjectExists`
3255 :raises: :class:`InvalidArgument`
3256 :raises: :class:`FunctionNotSupported`
3259 old_snap_name = cstr(old_snap_name, 'old_snap_name')
3260 new_snap_name = cstr(new_snap_name, 'new_snap_name')
3262 char *_old_snap_name = old_snap_name
3263 char *_new_snap_name = new_snap_name
3265 ret = rbd_group_snap_rename(self._ioctx, self._name, _old_snap_name,
3268 raise make_ex(ret, 'error renaming group snapshot',
3269 group_errno_to_exception)
3271 def list_snaps(self):
3273 Iterate over the images of a group.
3275 :returns: :class:`GroupSnapIterator`
3277 return GroupSnapIterator(self)
3279 def rollback_to_snap(self, name):
3281 Rollback group to snapshot.
3283 :param name: the group snapshot to rollback to
3285 :raises: :class:`ObjectNotFound`
3286 :raises: :class:`IOError`
3288 name = cstr(name, 'name')
3289 cdef char *_name = name
3291 ret = rbd_group_snap_rollback(self._ioctx, self._name, _name)
3293 raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
3295 def requires_not_closed(f):
3296 def wrapper(self, *args, **kwargs):
3297 self.require_not_closed()
3298 return f(self, *args, **kwargs)
3302 cdef class Image(object):
3304 This class represents an RBD image. It is used to perform I/O on
3305 the image and interact with snapshots.
3307 **Note**: Any method of this class may raise :class:`ImageNotFound`
3308 if the image has been deleted.
3310 cdef rbd_image_t image
3314 cdef rados_ioctx_t _ioctx
3316 def __init__(self, ioctx, name=None, snapshot=None,
3317 read_only=False, image_id=None):
3319 Open the image at the given snapshot.
3320 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
3322 If a snapshot is specified, the image will be read-only, unless
3323 :func:`Image.set_snap` is called later.
3325 If read-only mode is used, metadata for the :class:`Image`
3326 object (such as which snapshots exist) may become obsolete. See
3327 the C api for more details.
3329 To clean up from opening the image, :func:`Image.close` should
3330 be called. For ease of use, this is done automatically when
3331 an :class:`Image` is used as a context manager (see :pep:`343`).
3333 :param ioctx: determines which RADOS pool the image is in
3334 :type ioctx: :class:`rados.Ioctx`
3335 :param name: the name of the image
3337 :param snapshot: which snapshot to read from
3338 :type snaphshot: str
3339 :param read_only: whether to open the image in read-only mode
3340 :type read_only: bool
3341 :param image_id: the id of the image
3344 name = cstr(name, 'name', opt=True)
3345 image_id = cstr(image_id, 'image_id', opt=True)
3346 snapshot = cstr(snapshot, 'snapshot', opt=True)
3348 if name is not None and image_id is not None:
3349 raise InvalidArgument("only need to specify image name or image id")
3350 elif name is None and image_id is None:
3351 raise InvalidArgument("image name or image id was not specified")
3352 elif name is not None:
3355 self.name = image_id
3356 # Keep around a reference to the ioctx, so it won't get deleted
3359 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3360 char *_name = opt_str(name)
3361 char *_image_id = opt_str(image_id)
3362 char *_snapshot = opt_str(snapshot)
3365 if name is not None:
3366 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
3368 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
3371 if name is not None:
3372 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
3374 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
3376 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
3379 self.name = self.get_name()
3381 def __enter__(self):
3384 def __exit__(self, type_, value, traceback):
3386 Closes the image. See :func:`close`
3391 def __get_completion(self, oncomplete):
3393 Constructs a completion to use with asynchronous operations
3395 :param oncomplete: callback for the completion
3397 :raises: :class:`Error`
3398 :returns: completion object
3401 completion_obj = Completion(self, oncomplete)
3404 rbd_completion_t completion
3405 PyObject* p_completion_obj= <PyObject*>completion_obj
3408 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
3411 raise make_ex(ret, "error getting a completion")
3413 completion_obj.rbd_comp = completion
3414 return completion_obj
3416 def require_not_closed(self):
3418 Checks if the Image is not closed
3420 :raises: :class:`InvalidArgument`
3423 raise InvalidArgument("image is closed")
3427 Release the resources used by this image object.
3429 After this is called, this object should not be used.
3434 ret = rbd_close(self.image)
3436 raise make_ex(ret, 'error while closing image %s' % (
3439 def __dealloc__(self):
3443 return "rbd.Image(ioctx, %r)" % self.name
3445 @requires_not_closed
3446 def resize(self, size, allow_shrink=True):
3448 Change the size of the image, allow shrink.
3450 :param size: the new size of the image
3452 :param allow_shrink: permit shrinking
3453 :type allow_shrink: bool
3455 old_size = self.size()
3456 if old_size == size:
3458 if not allow_shrink and old_size > size:
3459 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
3461 uint64_t _size = size
3462 bint _allow_shrink = allow_shrink
3463 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3465 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
3467 raise make_ex(ret, 'error resizing image %s' % self.name)
3469 @requires_not_closed
3472 Get information about the image. Currently parent pool and
3473 parent name are always -1 and ''.
3475 :returns: dict - contains the following keys:
3477 * ``size`` (int) - the size of the image in bytes
3479 * ``obj_size`` (int) - the size of each object that comprises the
3482 * ``num_objs`` (int) - the number of objects in the image
3484 * ``order`` (int) - log_2(object_size)
3486 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
3489 * ``parent_pool`` (int) - deprecated
3491 * ``parent_name`` (str) - deprecated
3493 See also :meth:`format` and :meth:`features`.
3496 cdef rbd_image_info_t info
3498 ret = rbd_stat(self.image, &info, sizeof(info))
3500 raise make_ex(ret, 'error getting info for image %s' % self.name)
3503 'obj_size' : info.obj_size,
3504 'num_objs' : info.num_objs,
3505 'order' : info.order,
3506 'block_name_prefix' : decode_cstr(info.block_name_prefix),
3507 'parent_pool' : info.parent_pool,
3508 'parent_name' : info.parent_name
3511 @requires_not_closed
3514 Get the RBD image name
3516 :returns: str - image name
3519 int ret = -errno.ERANGE
3521 char *image_name = NULL
3523 while ret == -errno.ERANGE:
3524 image_name = <char *>realloc_chk(image_name, size)
3526 ret = rbd_get_name(self.image, image_name, &size)
3529 raise make_ex(ret, 'error getting name for image %s' % self.name)
3530 return decode_cstr(image_name)
3534 @requires_not_closed
3537 Get the RBD v2 internal image id
3539 :returns: str - image id
3542 int ret = -errno.ERANGE
3544 char *image_id = NULL
3546 while ret == -errno.ERANGE and size <= 4096:
3547 image_id = <char *>realloc_chk(image_id, size)
3549 ret = rbd_get_id(self.image, image_id, size)
3550 if ret == -errno.ERANGE:
3554 raise make_ex(ret, 'error getting id for image %s' % self.name)
3555 return decode_cstr(image_id)
3559 @requires_not_closed
3560 def block_name_prefix(self):
3562 Get the RBD block name prefix
3564 :returns: str - block name prefix
3567 int ret = -errno.ERANGE
3571 while ret == -errno.ERANGE and size <= 4096:
3572 prefix = <char *>realloc_chk(prefix, size)
3574 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3575 if ret == -errno.ERANGE:
3579 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3580 return decode_cstr(prefix)
3584 @requires_not_closed
3585 def data_pool_id(self):
3587 Get the pool id of the pool where the data of this RBD image is stored.
3589 :returns: int - the pool id
3591 return rbd_get_data_pool_id(self.image)
3593 @requires_not_closed
3594 def get_parent_image_spec(self):
3596 Get spec of the cloned image's parent
3598 :returns: dict - contains the following keys:
3599 * ``pool_name`` (str) - parent pool name
3600 * ``pool_namespace`` (str) - parent pool namespace
3601 * ``image_name`` (str) - parent image name
3602 * ``snap_name`` (str) - parent snapshot name
3604 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3607 rbd_linked_image_spec_t parent_spec
3608 rbd_snap_spec_t snap_spec
3610 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3612 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3614 result = {'pool_name': decode_cstr(parent_spec.pool_name),
3615 'pool_namespace': decode_cstr(parent_spec.pool_namespace),
3616 'image_name': decode_cstr(parent_spec.image_name),
3617 'snap_name': decode_cstr(snap_spec.name)}
3619 rbd_linked_image_spec_cleanup(&parent_spec)
3620 rbd_snap_spec_cleanup(&snap_spec)
3623 @requires_not_closed
3624 def parent_info(self):
3626 Deprecated. Use `get_parent_image_spec` instead.
3628 Get information about a cloned image's parent (if any)
3630 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3632 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3634 parent = self.get_parent_image_spec()
3635 return (parent['pool_name'], parent['image_name'], parent['snap_name'])
3637 @requires_not_closed
3638 def parent_id(self):
3640 Get image id of a cloned image's parent (if any)
3642 :returns: str - the parent id
3643 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3646 rbd_linked_image_spec_t parent_spec
3647 rbd_snap_spec_t snap_spec
3649 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3651 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3653 result = decode_cstr(parent_spec.image_id)
3655 rbd_linked_image_spec_cleanup(&parent_spec)
3656 rbd_snap_spec_cleanup(&snap_spec)
3659 @requires_not_closed
3660 def old_format(self):
3662 Find out whether the image uses the old RBD format.
3664 :returns: bool - whether the image uses the old RBD format
3668 ret = rbd_get_old_format(self.image, &old)
3670 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3673 @requires_not_closed
3676 Get the size of the image. If open to a snapshot, returns the
3677 size of that snapshot.
3679 :returns: int - the size of the image in bytes
3681 cdef uint64_t image_size
3683 ret = rbd_get_size(self.image, &image_size)
3685 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3688 @requires_not_closed
3691 Get the features bitmask of the image.
3693 :returns: int - the features bitmask of the image
3695 cdef uint64_t features
3697 ret = rbd_get_features(self.image, &features)
3699 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3702 @requires_not_closed
3703 def update_features(self, features, enabled):
3705 Update the features bitmask of the image by enabling/disabling
3706 a single feature. The feature must support the ability to be
3707 dynamically enabled/disabled.
3709 :param features: feature bitmask to enable/disable
3711 :param enabled: whether to enable/disable the feature
3713 :raises: :class:`InvalidArgument`
3716 uint64_t _features = features
3717 uint8_t _enabled = bool(enabled)
3719 ret = rbd_update_features(self.image, _features, _enabled)
3721 raise make_ex(ret, 'error updating features for image %s' %
3724 @requires_not_closed
3725 def op_features(self):
3727 Get the op features bitmask of the image.
3729 :returns: int - the op features bitmask of the image
3731 cdef uint64_t op_features
3733 ret = rbd_get_op_features(self.image, &op_features)
3735 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3738 @requires_not_closed
3741 Get the number of overlapping bytes between the image and its parent
3742 image. If open to a snapshot, returns the overlap between the snapshot
3743 and the parent image.
3745 :returns: int - the overlap in bytes
3746 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3748 cdef uint64_t overlap
3750 ret = rbd_get_overlap(self.image, &overlap)
3752 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3755 @requires_not_closed
3758 Get the flags bitmask of the image.
3760 :returns: int - the flags bitmask of the image
3764 ret = rbd_get_flags(self.image, &flags)
3766 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3769 @requires_not_closed
3772 Get information about the image's group.
3774 :returns: dict - contains the following keys:
3776 * ``pool`` (int) - id of the group pool
3778 * ``name`` (str) - name of the group
3781 cdef rbd_group_info_t info
3783 ret = rbd_get_group(self.image, &info, sizeof(info))
3785 raise make_ex(ret, 'error getting group for image %s' % self.name)
3788 'name' : decode_cstr(info.name)
3790 rbd_group_info_cleanup(&info, sizeof(info))
3793 @requires_not_closed
3794 def is_exclusive_lock_owner(self):
3796 Get the status of the image exclusive lock.
3798 :returns: bool - true if the image is exclusively locked
3802 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3804 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3807 @requires_not_closed
3808 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3809 stripe_unit=None, stripe_count=None, data_pool=None):
3811 Copy the image to another location.
3813 :param dest_ioctx: determines which pool to copy into
3814 :type dest_ioctx: :class:`rados.Ioctx`
3815 :param dest_name: the name of the copy
3816 :type dest_name: str
3817 :param features: bitmask of features to enable; if set, must include layering
3819 :param order: the image is split into (2**order) byte objects
3821 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3822 :type stripe_unit: int
3823 :param stripe_count: objects to stripe over before looping
3824 :type stripe_count: int
3825 :param data_pool: optional separate pool for data blocks
3826 :type data_pool: str
3827 :raises: :class:`TypeError`
3828 :raises: :class:`InvalidArgument`
3829 :raises: :class:`ImageExists`
3830 :raises: :class:`FunctionNotSupported`
3831 :raises: :class:`ArgumentOutOfRange`
3833 dest_name = cstr(dest_name, 'dest_name')
3834 data_pool = cstr(data_pool, 'data_pool', opt=True)
3836 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3837 char *_dest_name = dest_name
3838 rbd_image_options_t opts
3840 rbd_image_options_create(&opts)
3842 if features is not None:
3843 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3845 if order is not None:
3846 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3848 if stripe_unit is not None:
3849 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3851 if stripe_count is not None:
3852 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3854 if data_pool is not None:
3855 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3858 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3860 rbd_image_options_destroy(opts)
3862 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3864 @requires_not_closed
3865 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3866 stripe_unit=None, stripe_count=None, data_pool=None):
3868 Deep copy the image to another location.
3870 :param dest_ioctx: determines which pool to copy into
3871 :type dest_ioctx: :class:`rados.Ioctx`
3872 :param dest_name: the name of the copy
3873 :type dest_name: str
3874 :param features: bitmask of features to enable; if set, must include layering
3876 :param order: the image is split into (2**order) byte objects
3878 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3879 :type stripe_unit: int
3880 :param stripe_count: objects to stripe over before looping
3881 :type stripe_count: int
3882 :param data_pool: optional separate pool for data blocks
3883 :type data_pool: str
3884 :raises: :class:`TypeError`
3885 :raises: :class:`InvalidArgument`
3886 :raises: :class:`ImageExists`
3887 :raises: :class:`FunctionNotSupported`
3888 :raises: :class:`ArgumentOutOfRange`
3890 dest_name = cstr(dest_name, 'dest_name')
3891 data_pool = cstr(data_pool, 'data_pool', opt=True)
3893 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3894 char *_dest_name = dest_name
3895 rbd_image_options_t opts
3897 rbd_image_options_create(&opts)
3899 if features is not None:
3900 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3902 if order is not None:
3903 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3905 if stripe_unit is not None:
3906 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3908 if stripe_count is not None:
3909 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3911 if data_pool is not None:
3912 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3915 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3917 rbd_image_options_destroy(opts)
3919 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3921 @requires_not_closed
3922 def list_snaps(self):
3924 Iterate over the snapshots of an image.
3926 :returns: :class:`SnapIterator`
3928 return SnapIterator(self)
3930 @requires_not_closed
3931 def create_snap(self, name):
3933 Create a snapshot of the image.
3935 :param name: the name of the snapshot
3937 :raises: :class:`ImageExists`
3939 name = cstr(name, 'name')
3940 cdef char *_name = name
3942 ret = rbd_snap_create(self.image, _name)
3944 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3946 @requires_not_closed
3947 def rename_snap(self, srcname, dstname):
3949 rename a snapshot of the image.
3951 :param srcname: the src name of the snapshot
3953 :param dstname: the dst name of the snapshot
3955 :raises: :class:`ImageExists`
3957 srcname = cstr(srcname, 'srcname')
3958 dstname = cstr(dstname, 'dstname')
3960 char *_srcname = srcname
3961 char *_dstname = dstname
3963 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3965 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3967 @requires_not_closed
3968 def remove_snap(self, name):
3970 Delete a snapshot of the image.
3972 :param name: the name of the snapshot
3974 :raises: :class:`IOError`, :class:`ImageBusy`, :class:`ImageNotFound`
3976 name = cstr(name, 'name')
3977 cdef char *_name = name
3979 ret = rbd_snap_remove(self.image, _name)
3981 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3983 @requires_not_closed
3984 def remove_snap2(self, name, flags):
3986 Delete a snapshot of the image.
3988 :param name: the name of the snapshot
3989 :param flags: the flags for removal
3991 :raises: :class:`IOError`, :class:`ImageBusy`
3993 self.require_not_closed()
3995 name = cstr(name, 'name')
3998 uint32_t _flags = flags
3999 librbd_progress_fn_t prog_cb = &no_op_progress_callback
4001 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
4003 raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
4005 @requires_not_closed
4006 def remove_snap_by_id(self, snap_id):
4008 Delete a snapshot of the image by its id.
4010 :param id: the id of the snapshot
4012 :raises: :class:`IOError`, :class:`ImageBusy`
4015 uint64_t _snap_id = snap_id
4017 ret = rbd_snap_remove_by_id(self.image, _snap_id)
4019 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
4021 @requires_not_closed
4022 def rollback_to_snap(self, name):
4024 Revert the image to its contents at a snapshot. This is a
4025 potentially expensive operation, since it rolls back each
4026 object individually.
4028 :param name: the snapshot to rollback to
4030 :raises: :class:`IOError`
4032 name = cstr(name, 'name')
4033 cdef char *_name = name
4035 ret = rbd_snap_rollback(self.image, _name)
4037 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
4039 @requires_not_closed
4040 def protect_snap(self, name):
4042 Mark a snapshot as protected. This means it can't be deleted
4043 until it is unprotected.
4045 :param name: the snapshot to protect
4047 :raises: :class:`IOError`, :class:`ImageNotFound`
4049 name = cstr(name, 'name')
4050 cdef char *_name = name
4052 ret = rbd_snap_protect(self.image, _name)
4054 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
4056 @requires_not_closed
4057 def unprotect_snap(self, name):
4059 Mark a snapshot unprotected. This allows it to be deleted if
4062 :param name: the snapshot to unprotect
4064 :raises: :class:`IOError`, :class:`ImageNotFound`
4066 name = cstr(name, 'name')
4067 cdef char *_name = name
4069 ret = rbd_snap_unprotect(self.image, _name)
4071 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
4073 @requires_not_closed
4074 def is_protected_snap(self, name):
4076 Find out whether a snapshot is protected from deletion.
4078 :param name: the snapshot to check
4080 :returns: bool - whether the snapshot is protected
4081 :raises: :class:`IOError`, :class:`ImageNotFound`
4083 name = cstr(name, 'name')
4088 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
4090 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
4091 return is_protected == 1
4093 @requires_not_closed
4094 def snap_exists(self, name):
4096 Find out whether a snapshot is exists.
4098 :param name: the snapshot to check
4100 :returns: bool - whether the snapshot is exists
4102 name = cstr(name, 'name')
4105 bint _exists = False
4107 ret = rbd_snap_exists(self.image, _name, &_exists)
4109 raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
4110 return bool(_exists != 0)
4112 @requires_not_closed
4113 def get_snap_limit(self):
4115 Get the snapshot limit for an image.
4117 :returns: int - the snapshot limit for an image
4122 ret = rbd_snap_get_limit(self.image, &limit)
4124 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
4127 @requires_not_closed
4128 def set_snap_limit(self, limit):
4130 Set the snapshot limit for an image.
4132 :param limit: the new limit to set
4135 uint64_t _limit = limit
4137 ret = rbd_snap_set_limit(self.image, _limit)
4139 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
4142 @requires_not_closed
4143 def get_snap_timestamp(self, snap_id):
4145 Get the snapshot timestamp for an image.
4146 :param snap_id: the snapshot id of a snap shot
4147 :returns: datetime - the snapshot timestamp for an image
4151 uint64_t _snap_id = snap_id
4153 ret = rbd_snap_get_timestamp(self.image, _snap_id, ×tamp)
4155 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
4156 return datetime.utcfromtimestamp(timestamp.tv_sec)
4158 @requires_not_closed
4159 def remove_snap_limit(self):
4161 Remove the snapshot limit for an image, essentially setting
4162 the limit to the maximum size allowed by the implementation.
4165 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
4167 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
4170 @requires_not_closed
4171 def set_snap(self, name):
4173 Set the snapshot to read from. Writes will raise ReadOnlyImage
4174 while a snapshot is set. Pass None to unset the snapshot
4175 (reads come from the current image) , and allow writing again.
4177 :param name: the snapshot to read from, or None to unset the snapshot
4178 :type name: str or None
4180 name = cstr(name, 'name', opt=True)
4181 cdef char *_name = opt_str(name)
4183 ret = rbd_snap_set(self.image, _name)
4185 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
4187 @requires_not_closed
4188 def set_snap_by_id(self, snap_id):
4190 Set the snapshot to read from. Writes will raise ReadOnlyImage
4191 while a snapshot is set. Pass None to unset the snapshot
4192 (reads come from the current image) , and allow writing again.
4194 :param snap_id: the snapshot to read from, or None to unset the snapshot
4198 snap_id = _LIBRADOS_SNAP_HEAD
4199 cdef int64_t _snap_id = snap_id
4201 ret = rbd_snap_set_by_id(self.image, _snap_id)
4203 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
4205 @requires_not_closed
4206 def snap_get_name(self, snap_id):
4208 Get snapshot name by id.
4210 :param snap_id: the snapshot id
4212 :returns: str - snapshot name
4213 :raises: :class:`ImageNotFound`
4216 int ret = -errno.ERANGE
4217 int64_t _snap_id = snap_id
4219 char *image_name = NULL
4221 while ret == -errno.ERANGE:
4222 image_name = <char *>realloc_chk(image_name, size)
4224 ret = rbd_snap_get_name(self.image, _snap_id, image_name, &size)
4227 raise make_ex(ret, 'error snap_get_name.')
4228 return decode_cstr(image_name)
4232 @requires_not_closed
4233 def snap_get_id(self, snap_name):
4235 Get snapshot id by name.
4237 :param snap_name: the snapshot name
4238 :type snap_name: str
4239 :returns: int - snapshot id
4240 :raises: :class:`ImageNotFound`
4242 snap_name = cstr(snap_name, 'snap_name')
4244 const char *_snap_name = snap_name
4247 ret = rbd_snap_get_id(self.image, _snap_name, &snap_id)
4249 raise make_ex(ret, 'error snap_get_id.')
4252 @requires_not_closed
4253 def read(self, offset, length, fadvise_flags=0):
4255 Read data from the image. Raises :class:`InvalidArgument` if
4256 part of the range specified is outside the image.
4258 :param offset: the offset to start reading at
4260 :param length: how many bytes to read
4262 :param fadvise_flags: fadvise flags for this read
4263 :type fadvise_flags: int
4264 :returns: str - the data read
4265 :raises: :class:`InvalidArgument`, :class:`IOError`
4268 # This usage of the Python API allows us to construct a string
4269 # that librbd directly reads into, avoiding an extra copy. Although
4270 # strings are normally immutable, this usage is explicitly supported
4271 # for freshly created string objects.
4274 uint64_t _offset = offset
4275 size_t _length = length
4276 int _fadvise_flags = fadvise_flags
4277 PyObject* ret_s = NULL
4278 ret_s = PyBytes_FromStringAndSize(NULL, length)
4280 ret_buf = PyBytes_AsString(ret_s)
4282 ret = rbd_read2(self.image, _offset, _length, ret_buf,
4285 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
4287 if ret != <ssize_t>length:
4288 _PyBytes_Resize(&ret_s, ret)
4290 return <object>ret_s
4292 # We DECREF unconditionally: the cast to object above will have
4293 # INCREFed if necessary. This also takes care of exceptions,
4294 # including if _PyString_Resize fails (that will free the string
4295 # itself and set ret_s to NULL, hence XDECREF).
4296 ref.Py_XDECREF(ret_s)
4298 @requires_not_closed
4299 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
4300 include_parent = True, whole_object = False):
4302 Iterate over the changed extents of an image.
4304 This will call iterate_cb with three arguments:
4306 (offset, length, exists)
4308 where the changed extent starts at offset bytes, continues for
4309 length bytes, and is full of data (if exists is True) or zeroes
4310 (if exists is False).
4312 If from_snapshot is None, it is interpreted as the beginning
4313 of time and this generates all allocated extents.
4315 The end version is whatever is currently selected (via set_snap)
4318 iterate_cb may raise an exception, which will abort the diff and will be
4319 propagated to the caller.
4321 Raises :class:`InvalidArgument` if from_snapshot is after
4322 the currently set snapshot.
4324 Raises :class:`ImageNotFound` if from_snapshot is not the name
4325 of a snapshot of the image.
4327 :param offset: start offset in bytes
4329 :param length: size of region to report on, in bytes
4331 :param from_snapshot: starting snapshot name, or None
4332 :type from_snapshot: str or None
4333 :param iterate_cb: function to call for each extent
4334 :type iterate_cb: function acception arguments for offset,
4336 :param include_parent: True if full history diff should include parent
4337 :type include_parent: bool
4338 :param whole_object: True if diff extents should cover whole object
4339 :type whole_object: bool
4340 :raises: :class:`InvalidArgument`, :class:`IOError`,
4341 :class:`ImageNotFound`
4343 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
4345 char *_from_snapshot = opt_str(from_snapshot)
4346 uint64_t _offset = offset, _length = length
4347 uint8_t _include_parent = include_parent
4348 uint8_t _whole_object = whole_object
4350 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
4351 _length, _include_parent, _whole_object,
4352 &diff_iterate_cb, <void *>iterate_cb)
4354 msg = 'error generating diff from snapshot %s' % from_snapshot
4355 raise make_ex(ret, msg)
4357 @requires_not_closed
4358 def write(self, data, offset, fadvise_flags=0):
4360 Write data to the image. Raises :class:`InvalidArgument` if
4361 part of the write would fall outside the image.
4363 :param data: the data to be written
4365 :param offset: where to start writing data
4367 :param fadvise_flags: fadvise flags for this write
4368 :type fadvise_flags: int
4369 :returns: int - the number of bytes written
4370 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
4371 :class:`InvalidArgument`, :class:`IOError`
4373 if not isinstance(data, bytes):
4374 raise TypeError('data must be a byte string')
4376 uint64_t _offset = offset, length = len(data)
4378 int _fadvise_flags = fadvise_flags
4380 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
4382 if ret == <ssize_t>length:
4385 raise make_ex(ret, "error writing to %s" % self.name)
4386 elif ret < <ssize_t>length:
4387 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
4389 raise LogicError("logic error: rbd_write(%s) \
4390 returned %d, but %d was the maximum number of bytes it could have \
4391 written." % (self.name, ret, length))
4393 @requires_not_closed
4394 def discard(self, offset, length):
4396 Trim the range from the image. It will be logically filled
4399 cdef uint64_t _offset = offset, _length = length
4401 ret = rbd_discard(self.image, _offset, _length)
4403 msg = 'error discarding region %d~%d' % (offset, length)
4404 raise make_ex(ret, msg)
4406 @requires_not_closed
4409 Block until all writes are fully flushed if caching is enabled.
4412 ret = rbd_flush(self.image)
4414 raise make_ex(ret, 'error flushing image')
4416 @requires_not_closed
4417 def invalidate_cache(self):
4419 Drop any cached data for the image.
4422 ret = rbd_invalidate_cache(self.image)
4424 raise make_ex(ret, 'error invalidating cache')
4426 @requires_not_closed
4427 def stripe_unit(self):
4429 Return the stripe unit used for the image.
4431 cdef uint64_t stripe_unit
4433 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
4435 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
4438 @requires_not_closed
4439 def stripe_count(self):
4441 Return the stripe count used for the image.
4443 cdef uint64_t stripe_count
4445 ret = rbd_get_stripe_count(self.image, &stripe_count)
4447 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
4450 @requires_not_closed
4451 def create_timestamp(self):
4453 Return the create timestamp for the image.
4458 ret = rbd_get_create_timestamp(self.image, ×tamp)
4460 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
4461 return datetime.utcfromtimestamp(timestamp.tv_sec)
4463 @requires_not_closed
4464 def access_timestamp(self):
4466 Return the access timestamp for the image.
4471 ret = rbd_get_access_timestamp(self.image, ×tamp)
4473 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
4474 return datetime.fromtimestamp(timestamp.tv_sec)
4476 @requires_not_closed
4477 def modify_timestamp(self):
4479 Return the modify timestamp for the image.
4484 ret = rbd_get_modify_timestamp(self.image, ×tamp)
4486 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
4487 return datetime.fromtimestamp(timestamp.tv_sec)
4489 @requires_not_closed
4490 def flatten(self, on_progress=None):
4492 Flatten clone image (copy all blocks from parent to child)
4493 :param on_progress: optional progress callback function
4494 :type on_progress: callback function
4497 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
4498 void *_prog_arg = NULL
4500 _prog_cb = &progress_callback
4501 _prog_arg = <void *>on_progress
4503 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
4505 raise make_ex(ret, "error flattening %s" % self.name)
4507 @requires_not_closed
4508 def sparsify(self, sparse_size):
4510 Reclaim space for zeroed image extents
4513 size_t _sparse_size = sparse_size
4515 ret = rbd_sparsify(self.image, _sparse_size)
4517 raise make_ex(ret, "error sparsifying %s" % self.name)
4519 @requires_not_closed
4520 def rebuild_object_map(self):
4522 Rebuild the object map for the image HEAD or currently set snapshot
4524 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
4526 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
4528 raise make_ex(ret, "error rebuilding object map %s" % self.name)
4530 @requires_not_closed
4531 def list_children(self):
4533 List children of the currently set snapshot (set via set_snap()).
4535 :returns: list - a list of (pool name, image name) tuples
4538 rbd_linked_image_spec_t *children = NULL
4539 size_t num_children = 10
4543 children = <rbd_linked_image_spec_t*>realloc_chk(
4544 children, num_children * sizeof(rbd_linked_image_spec_t))
4546 ret = rbd_list_children3(self.image, children,
4550 elif ret != -errno.ERANGE:
4551 raise make_ex(ret, 'error listing children.')
4553 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
4554 in children[:num_children] if not x.trash]
4557 rbd_linked_image_spec_list_cleanup(children, num_children)
4560 @requires_not_closed
4561 def list_children2(self):
4563 Iterate over the children of the image or its snapshot.
4565 :returns: :class:`ChildIterator`
4567 return ChildIterator(self)
4569 @requires_not_closed
4570 def list_descendants(self):
4572 Iterate over the descendants of the image.
4574 :returns: :class:`ChildIterator`
4576 return ChildIterator(self, True)
4578 @requires_not_closed
4579 def list_lockers(self):
4581 List clients that have locked the image and information
4584 :returns: dict - contains the following keys:
4586 * ``tag`` - the tag associated with the lock (every
4587 additional locker must use the same tag)
4588 * ``exclusive`` - boolean indicating whether the
4589 lock is exclusive or shared
4590 * ``lockers`` - a list of (client, cookie, address)
4594 size_t clients_size = 512, cookies_size = 512
4595 size_t addrs_size = 512, tag_size = 512
4597 char *c_clients = NULL
4598 char *c_cookies = NULL
4599 char *c_addrs = NULL
4604 c_clients = <char *>realloc_chk(c_clients, clients_size)
4605 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
4606 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
4607 c_tag = <char *>realloc_chk(c_tag, tag_size)
4609 ret = rbd_list_lockers(self.image, &exclusive,
4611 c_clients, &clients_size,
4612 c_cookies, &cookies_size,
4613 c_addrs, &addrs_size)
4616 elif ret != -errno.ERANGE:
4617 raise make_ex(ret, 'error listing images')
4620 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
4621 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
4622 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
4624 'tag' : decode_cstr(c_tag),
4625 'exclusive' : exclusive == 1,
4626 'lockers' : list(zip(clients, cookies, addrs)),
4634 @requires_not_closed
4635 def lock_acquire(self, lock_mode):
4637 Acquire a managed lock on the image.
4639 :param lock_mode: lock mode to set
4640 :type lock_mode: int
4641 :raises: :class:`ImageBusy` if the lock could not be acquired
4644 rbd_lock_mode_t _lock_mode = lock_mode
4646 ret = rbd_lock_acquire(self.image, _lock_mode)
4648 raise make_ex(ret, 'error acquiring lock on image')
4650 @requires_not_closed
4651 def lock_release(self):
4653 Release a managed lock on the image that was previously acquired.
4656 ret = rbd_lock_release(self.image)
4658 raise make_ex(ret, 'error releasing lock on image')
4660 @requires_not_closed
4661 def lock_get_owners(self):
4663 Iterate over the lock owners of an image.
4665 :returns: :class:`LockOwnerIterator`
4667 return LockOwnerIterator(self)
4669 @requires_not_closed
4670 def lock_break(self, lock_mode, lock_owner):
4672 Break the image lock held by a another client.
4674 :param lock_owner: the owner of the lock to break
4675 :type lock_owner: str
4677 lock_owner = cstr(lock_owner, 'lock_owner')
4679 rbd_lock_mode_t _lock_mode = lock_mode
4680 char *_lock_owner = lock_owner
4682 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
4684 raise make_ex(ret, 'error breaking lock on image')
4686 @requires_not_closed
4687 def lock_exclusive(self, cookie):
4689 Take an exclusive lock on the image.
4691 :raises: :class:`ImageBusy` if a different client or cookie locked it
4692 :class:`ImageExists` if the same client and cookie locked it
4694 cookie = cstr(cookie, 'cookie')
4695 cdef char *_cookie = cookie
4697 ret = rbd_lock_exclusive(self.image, _cookie)
4699 raise make_ex(ret, 'error acquiring exclusive lock on image')
4701 @requires_not_closed
4702 def lock_shared(self, cookie, tag):
4704 Take a shared lock on the image. The tag must match
4705 that of the existing lockers, if any.
4707 :raises: :class:`ImageBusy` if a different client or cookie locked it
4708 :class:`ImageExists` if the same client and cookie locked it
4710 cookie = cstr(cookie, 'cookie')
4711 tag = cstr(tag, 'tag')
4713 char *_cookie = cookie
4716 ret = rbd_lock_shared(self.image, _cookie, _tag)
4718 raise make_ex(ret, 'error acquiring shared lock on image')
4720 @requires_not_closed
4721 def unlock(self, cookie):
4723 Release a lock on the image that was locked by this rados client.
4725 cookie = cstr(cookie, 'cookie')
4726 cdef char *_cookie = cookie
4728 ret = rbd_unlock(self.image, _cookie)
4730 raise make_ex(ret, 'error unlocking image')
4732 @requires_not_closed
4733 def break_lock(self, client, cookie):
4735 Release a lock held by another rados client.
4737 client = cstr(client, 'client')
4738 cookie = cstr(cookie, 'cookie')
4740 char *_client = client
4741 char *_cookie = cookie
4743 ret = rbd_break_lock(self.image, _client, _cookie)
4745 raise make_ex(ret, 'error unlocking image')
4747 @requires_not_closed
4748 def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
4750 Enable mirroring for the image.
4752 cdef rbd_mirror_image_mode_t c_mode = mode
4754 ret = rbd_mirror_image_enable2(self.image, c_mode)
4756 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4758 @requires_not_closed
4759 def mirror_image_disable(self, force):
4761 Disable mirroring for the image.
4763 :param force: force disabling
4766 cdef bint c_force = force
4768 ret = rbd_mirror_image_disable(self.image, c_force)
4770 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4772 @requires_not_closed
4773 def mirror_image_promote(self, force):
4775 Promote the image to primary for mirroring.
4777 :param force: force promoting
4780 cdef bint c_force = force
4782 ret = rbd_mirror_image_promote(self.image, c_force)
4784 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4786 @requires_not_closed
4787 def mirror_image_demote(self):
4789 Demote the image to secondary for mirroring.
4792 ret = rbd_mirror_image_demote(self.image)
4794 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4796 @requires_not_closed
4797 def mirror_image_resync(self):
4799 Flag the image to resync.
4802 ret = rbd_mirror_image_resync(self.image)
4804 raise make_ex(ret, 'error to resync image %s' % self.name)
4806 @requires_not_closed
4807 def mirror_image_create_snapshot(self):
4809 Create mirror snapshot.
4811 :param force: ignore mirror snapshot limit
4813 :returns: int - the snapshot Id
4818 ret = rbd_mirror_image_create_snapshot(self.image, &snap_id)
4820 raise make_ex(ret, 'error creating mirror snapshot for image %s' %
4824 @requires_not_closed
4825 def mirror_image_get_info(self):
4827 Get mirror info for the image.
4829 :returns: dict - contains the following keys:
4831 * ``global_id`` (str) - image global id
4833 * ``state`` (int) - mirror state
4835 * ``primary`` (bool) - is image primary
4837 cdef rbd_mirror_image_info_t c_info
4839 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4841 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4843 'global_id' : decode_cstr(c_info.global_id),
4844 'state' : int(c_info.state),
4845 'primary' : c_info.primary,
4847 rbd_mirror_image_get_info_cleanup(&c_info)
4850 @requires_not_closed
4851 def mirror_image_get_mode(self):
4853 Get mirror mode for the image.
4855 :returns: int - mirror mode
4857 cdef rbd_mirror_image_mode_t c_mode
4859 ret = rbd_mirror_image_get_mode(self.image, &c_mode)
4861 raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
4864 @requires_not_closed
4865 def mirror_image_get_status(self):
4867 Get mirror status for the image.
4869 :returns: dict - contains the following keys:
4871 * ``name`` (str) - mirror image name
4873 * ``id`` (str) - mirror image id
4875 * ``info`` (dict) - mirror image info
4877 * ``state`` (int) - status mirror state
4879 * ``description`` (str) - status description
4881 * ``last_update`` (datetime) - last status update time
4883 * ``up`` (bool) - is mirroring agent up
4885 * ``remote_statuses`` (array) -
4887 * ``mirror_uuid`` (str) - remote mirror uuid
4889 * ``state`` (int) - status mirror state
4891 * ``description`` (str) - status description
4893 * ``last_update`` (datetime) - last status update time
4895 * ``up`` (bool) - is mirroring agent up
4898 rbd_mirror_image_site_status_t *s_status
4899 rbd_mirror_image_global_status_t c_status
4902 ret = rbd_mirror_image_get_global_status(self.image, &c_status,
4905 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4909 for i in range(c_status.site_statuses_count):
4910 s_status = &c_status.site_statuses[i]
4912 'state' : s_status.state,
4913 'description' : decode_cstr(s_status.description),
4914 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
4917 mirror_uuid = decode_cstr(s_status.mirror_uuid)
4918 if mirror_uuid == '':
4919 local_status = site_status
4921 site_statuses['mirror_uuid'] = mirror_uuid
4922 site_statuses += site_status
4924 'name': decode_cstr(c_status.name),
4927 'global_id' : decode_cstr(c_status.info.global_id),
4928 'state' : int(c_status.info.state),
4929 'primary' : c_status.info.primary,
4931 'remote_statuses': site_statuses,
4934 status.update(local_status)
4936 rbd_mirror_image_global_status_cleanup(&c_status)
4939 @requires_not_closed
4940 def mirror_image_get_instance_id(self):
4942 Get mirror instance id for the image.
4944 :returns: str - instance id
4947 int ret = -errno.ERANGE
4949 char *instance_id = NULL
4951 while ret == -errno.ERANGE and size <= 4096:
4952 instance_id = <char *>realloc_chk(instance_id, size)
4954 ret = rbd_mirror_image_get_instance_id(self.image,
4958 'error getting mirror instance id for image %s' %
4960 return decode_cstr(instance_id)
4964 @requires_not_closed
4965 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4967 Asynchronously read data from the image
4969 Raises :class:`InvalidArgument` if part of the range specified is
4972 oncomplete will be called with the returned read value as
4973 well as the completion:
4975 oncomplete(completion, data_read)
4977 :param offset: the offset to start reading at
4979 :param length: how many bytes to read
4981 :param oncomplete: what to do when the read is complete
4982 :type oncomplete: completion
4983 :param fadvise_flags: fadvise flags for this read
4984 :type fadvise_flags: int
4985 :returns: :class:`Completion` - the completion object
4986 :raises: :class:`InvalidArgument`, :class:`IOError`
4990 uint64_t _offset = offset
4991 size_t _length = length
4992 int _fadvise_flags = fadvise_flags
4993 Completion completion
4995 def oncomplete_(completion_v):
4996 cdef Completion _completion_v = completion_v
4997 return_value = _completion_v.get_return_value()
4998 if return_value > 0 and return_value != length:
4999 _PyBytes_Resize(&_completion_v.buf, return_value)
5000 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
5002 completion = self.__get_completion(oncomplete_)
5003 completion.buf = PyBytes_FromStringAndSize(NULL, length)
5004 ret_buf = PyBytes_AsString(completion.buf)
5006 completion.__persist()
5008 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
5009 completion.rbd_comp, _fadvise_flags)
5011 raise make_ex(ret, 'error reading %s %ld~%ld' %
5012 (self.name, offset, length))
5014 completion.__unpersist()
5019 @requires_not_closed
5020 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
5022 Asynchronously write data to the image
5024 Raises :class:`InvalidArgument` if part of the write would fall outside
5027 oncomplete will be called with the completion:
5029 oncomplete(completion)
5031 :param data: the data to be written
5033 :param offset: the offset to start writing at
5035 :param oncomplete: what to do when the write is complete
5036 :type oncomplete: completion
5037 :param fadvise_flags: fadvise flags for this write
5038 :type fadvise_flags: int
5039 :returns: :class:`Completion` - the completion object
5040 :raises: :class:`InvalidArgument`, :class:`IOError`
5043 uint64_t _offset = offset
5045 size_t _length = len(data)
5046 int _fadvise_flags = fadvise_flags
5047 Completion completion
5049 completion = self.__get_completion(oncomplete)
5051 completion.__persist()
5053 ret = rbd_aio_write2(self.image, _offset, _length, _data,
5054 completion.rbd_comp, _fadvise_flags)
5056 raise make_ex(ret, 'error writing %s %ld~%ld' %
5057 (self.name, offset, _length))
5059 completion.__unpersist()
5064 @requires_not_closed
5065 def aio_discard(self, offset, length, oncomplete):
5067 Asynchronously trim the range from the image. It will be logically
5071 uint64_t _offset = offset
5072 size_t _length = length
5073 Completion completion
5075 completion = self.__get_completion(oncomplete)
5077 completion.__persist()
5079 ret = rbd_aio_discard(self.image, _offset, _length,
5080 completion.rbd_comp)
5082 raise make_ex(ret, 'error discarding %s %ld~%ld' %
5083 (self.name, offset, _length))
5085 completion.__unpersist()
5090 @requires_not_closed
5091 def aio_flush(self, oncomplete):
5093 Asynchronously wait until all writes are fully flushed if caching is
5096 cdef Completion completion = self.__get_completion(oncomplete)
5098 completion.__persist()
5100 ret = rbd_aio_flush(self.image, completion.rbd_comp)
5102 raise make_ex(ret, 'error flushing')
5104 completion.__unpersist()
5109 @requires_not_closed
5110 def metadata_get(self, key):
5112 Get image metadata for the given key.
5114 :param key: metadata key
5116 :returns: str - metadata value
5118 key = cstr(key, 'key')
5126 value = <char *>realloc_chk(value, size)
5128 ret = rbd_metadata_get(self.image, _key, value, &size)
5129 if ret != -errno.ERANGE:
5131 if ret == -errno.ENOENT:
5132 raise KeyError('no metadata %s for image %s' % (key, self.name))
5134 raise make_ex(ret, 'error getting metadata %s for image %s' %
5136 return decode_cstr(value)
5140 @requires_not_closed
5141 def metadata_set(self, key, value):
5143 Set image metadata for the given key.
5145 :param key: metadata key
5147 :param value: metadata value
5150 key = cstr(key, 'key')
5151 value = cstr(value, 'value')
5154 char *_value = value
5156 ret = rbd_metadata_set(self.image, _key, _value)
5159 raise make_ex(ret, 'error setting metadata %s for image %s' %
5162 @requires_not_closed
5163 def metadata_remove(self, key):
5165 Remove image metadata for the given key.
5167 :param key: metadata key
5170 key = cstr(key, 'key')
5174 ret = rbd_metadata_remove(self.image, _key)
5176 if ret == -errno.ENOENT:
5177 raise KeyError('no metadata %s for image %s' % (key, self.name))
5179 raise make_ex(ret, 'error removing metadata %s for image %s' %
5182 @requires_not_closed
5183 def metadata_list(self):
5185 List image metadata.
5187 :returns: :class:`MetadataIterator`
5189 return MetadataIterator(self)
5191 @requires_not_closed
5192 def watchers_list(self):
5194 List image watchers.
5196 :returns: :class:`WatcherIterator`
5198 return WatcherIterator(self)
5200 @requires_not_closed
5201 def config_list(self):
5203 List image-level config overrides.
5205 :returns: :class:`ConfigImageIterator`
5207 return ConfigImageIterator(self)
5209 @requires_not_closed
5210 def config_set(self, key, value):
5212 Set an image-level configuration override.
5219 conf_key = 'conf_' + key
5220 conf_key = cstr(conf_key, 'key')
5221 value = cstr(value, 'value')
5223 char *_key = conf_key
5224 char *_value = value
5226 ret = rbd_metadata_set(self.image, _key, _value)
5229 raise make_ex(ret, 'error setting config %s for image %s' %
5232 @requires_not_closed
5233 def config_get(self, key):
5235 Get an image-level configuration override.
5239 :returns: str - value
5241 conf_key = 'conf_' + key
5242 conf_key = cstr(conf_key, 'key')
5244 char *_key = conf_key
5250 value = <char *>realloc_chk(value, size)
5252 ret = rbd_metadata_get(self.image, _key, value, &size)
5253 if ret != -errno.ERANGE:
5255 if ret == -errno.ENOENT:
5256 raise KeyError('no config %s for image %s' % (key, self.name))
5258 raise make_ex(ret, 'error getting config %s for image %s' %
5260 return decode_cstr(value)
5264 @requires_not_closed
5265 def config_remove(self, key):
5267 Remove an image-level configuration override.
5272 conf_key = 'conf_' + key
5273 conf_key = cstr(conf_key, 'key')
5275 char *_key = conf_key
5277 ret = rbd_metadata_remove(self.image, _key)
5279 if ret == -errno.ENOENT:
5280 raise KeyError('no config %s for image %s' % (key, self.name))
5282 raise make_ex(ret, 'error removing config %s for image %s' %
5285 @requires_not_closed
5286 def snap_get_namespace_type(self, snap_id):
5288 Get the snapshot namespace type.
5289 :param snap_id: the snapshot id of a snap shot
5293 rbd_snap_namespace_type_t namespace_type
5294 uint64_t _snap_id = snap_id
5296 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
5298 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
5300 return namespace_type
5302 @requires_not_closed
5303 def snap_get_group_namespace(self, snap_id):
5305 get the group namespace details.
5306 :param snap_id: the snapshot id of the group snapshot
5308 :returns: dict - contains the following keys:
5310 * ``pool`` (int) - pool id
5312 * ``name`` (str) - group name
5314 * ``snap_name`` (str) - group snap name
5317 rbd_snap_group_namespace_t group_namespace
5318 uint64_t _snap_id = snap_id
5320 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
5322 sizeof(rbd_snap_group_namespace_t))
5324 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
5327 'pool' : group_namespace.group_pool,
5328 'name' : decode_cstr(group_namespace.group_name),
5329 'snap_name' : decode_cstr(group_namespace.group_snap_name)
5331 rbd_snap_group_namespace_cleanup(&group_namespace,
5332 sizeof(rbd_snap_group_namespace_t))
5335 @requires_not_closed
5336 def snap_get_trash_namespace(self, snap_id):
5338 get the trash namespace details.
5339 :param snap_id: the snapshot id of the trash snapshot
5341 :returns: dict - contains the following keys:
5343 * ``original_name`` (str) - original snap name
5346 uint64_t _snap_id = snap_id
5351 _name = <char*>realloc_chk(_name, _size);
5353 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
5357 elif ret != -errno.ERANGE:
5358 raise make_ex(ret, 'error getting snapshot trash '
5359 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
5361 'original_name' : decode_cstr(_name)
5366 @requires_not_closed
5367 def snap_get_mirror_namespace(self, snap_id):
5369 get the mirror namespace details.
5370 :param snap_id: the snapshot id of the mirror snapshot
5372 :returns: dict - contains the following keys:
5374 * ``state`` (int) - the snapshot state
5376 * ``mirror_peer_uuids`` (list) - mirror peer uuids
5378 * ``complete`` (bool) - True if snapshot is complete
5380 * ``primary_mirror_uuid`` (str) - primary mirror uuid
5382 * ``primary_snap_id`` (int) - primary snapshot Id
5384 * ``last_copied_object_number`` (int) - last copied object number
5387 rbd_snap_mirror_namespace_t sn
5388 uint64_t _snap_id = snap_id
5390 ret = rbd_snap_get_mirror_namespace(
5391 self.image, _snap_id, &sn,
5392 sizeof(rbd_snap_mirror_namespace_t))
5394 raise make_ex(ret, 'error getting snapshot mirror '
5395 'namespace for image: %s, snap_id: %d' %
5396 (self.name, snap_id))
5398 cdef char *p = sn.mirror_peer_uuids
5399 for i in range(sn.mirror_peer_uuids_count):
5400 uuid = decode_cstr(p)
5405 'mirror_peer_uuids' : uuids,
5406 'complete' : sn.complete,
5407 'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
5408 'primary_snap_id' : sn.primary_snap_id,
5409 'last_copied_object_number' : sn.last_copied_object_number,
5411 rbd_snap_mirror_namespace_cleanup(
5412 &sn, sizeof(rbd_snap_mirror_namespace_t))
5416 cdef class ImageIterator(object):
5418 Iterator over RBD images in a pool
5420 Yields a dictionary containing information about the images
5424 * ``id`` (str) - image id
5426 * ``name`` (str) - image name
5428 cdef rados_ioctx_t ioctx
5429 cdef rbd_image_spec_t *images
5430 cdef size_t num_images
5432 def __init__(self, ioctx):
5433 self.ioctx = convert_ioctx(ioctx)
5435 self.num_images = 1024
5437 self.images = <rbd_image_spec_t*>realloc_chk(
5438 self.images, self.num_images * sizeof(rbd_image_spec_t))
5440 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
5443 elif ret == -errno.ERANGE:
5444 self.num_images *= 2
5446 raise make_ex(ret, 'error listing images.')
5449 for i in range(self.num_images):
5451 'id' : decode_cstr(self.images[i].id),
5452 'name' : decode_cstr(self.images[i].name)
5455 def __dealloc__(self):
5457 rbd_image_spec_list_cleanup(self.images, self.num_images)
5461 cdef class LockOwnerIterator(object):
5463 Iterator over managed lock owners for an image
5465 Yields a dictionary containing information about the image's lock
5469 * ``mode`` (int) - active lock mode
5471 * ``owner`` (str) - lock owner name
5475 rbd_lock_mode_t lock_mode
5477 size_t num_lock_owners
5480 def __init__(self, Image image):
5481 image.require_not_closed()
5484 self.lock_owners = NULL
5485 self.num_lock_owners = 8
5487 self.lock_owners = <char**>realloc_chk(self.lock_owners,
5488 self.num_lock_owners *
5491 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
5493 &self.num_lock_owners)
5496 elif ret == -errno.ENOENT:
5497 self.num_lock_owners = 0
5499 elif ret != -errno.ERANGE:
5500 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
5503 for i in range(self.num_lock_owners):
5505 'mode' : int(self.lock_mode),
5506 'owner' : decode_cstr(self.lock_owners[i]),
5509 def __dealloc__(self):
5510 if self.lock_owners:
5511 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
5512 free(self.lock_owners)
5514 cdef class MetadataIterator(object):
5516 Iterator over metadata list for an image.
5518 Yields ``(key, value)`` tuple.
5520 * ``key`` (str) - metadata key
5521 * ``value`` (str) - metadata value
5531 def __init__(self, Image image):
5532 image.require_not_closed()
5535 self.c_image = image.image
5536 self.last_read = strdup("")
5538 self.get_next_chunk()
5541 while len(self.next_chunk) > 0:
5542 for pair in self.next_chunk:
5544 if len(self.next_chunk) < self.max_read:
5546 self.get_next_chunk()
5548 def __dealloc__(self):
5550 free(self.last_read)
5552 def get_next_chunk(self):
5553 self.image.require_not_closed()
5557 size_t keys_size = 4096
5559 size_t vals_size = 4096
5562 c_keys = <char *>realloc_chk(c_keys, keys_size)
5563 c_vals = <char *>realloc_chk(c_vals, vals_size)
5565 ret = rbd_metadata_list(self.c_image, self.last_read,
5566 self.max_read, c_keys, &keys_size,
5570 elif ret != -errno.ERANGE:
5571 raise make_ex(ret, 'error listing metadata for image %s' %
5573 keys = [decode_cstr(key) for key in
5574 c_keys[:keys_size].split(b'\0') if key]
5575 vals = [decode_cstr(val) for val in
5576 c_vals[:vals_size].split(b'\0') if val]
5578 last_read = cstr(keys[-1], 'last_read')
5579 free(self.last_read)
5580 self.last_read = strdup(last_read)
5581 self.next_chunk = list(zip(keys, vals))
5586 cdef class SnapIterator(object):
5588 Iterator over snapshot info for an image.
5590 Yields a dictionary containing information about a snapshot.
5594 * ``id`` (int) - numeric identifier of the snapshot
5596 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
5598 * ``name`` (str) - name of the snapshot
5600 * ``namespace`` (int) - enum for snap namespace
5602 * ``group`` (dict) - optional for group namespace snapshots
5604 * ``trash`` (dict) - optional for trash namespace snapshots
5606 * ``mirror`` (dict) - optional for mirror namespace snapshots
5609 cdef rbd_snap_info_t *snaps
5613 def __init__(self, Image image):
5614 image.require_not_closed()
5620 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
5622 sizeof(rbd_snap_info_t))
5624 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
5626 self.num_snaps = ret
5628 elif ret != -errno.ERANGE:
5629 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
5632 for i in range(self.num_snaps):
5634 'id' : self.snaps[i].id,
5635 'size' : self.snaps[i].size,
5636 'name' : decode_cstr(self.snaps[i].name),
5637 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
5639 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
5641 group = self.image.snap_get_group_namespace(self.snaps[i].id)
5645 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
5647 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
5651 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR:
5653 mirror = self.image.snap_get_mirror_namespace(
5657 s['mirror'] = mirror
5660 def __dealloc__(self):
5662 rbd_snap_list_end(self.snaps)
5665 cdef class TrashIterator(object):
5667 Iterator over trash entries.
5669 Yields a dictionary containing trash info of an image.
5673 * `id` (str) - image id
5675 * `name` (str) - image name
5677 * `source` (str) - source of deletion
5679 * `deletion_time` (datetime) - time of deletion
5681 * `deferment_end_time` (datetime) - time that an image is allowed to be
5688 rbd_trash_image_info_t *entries
5690 def __init__(self, ioctx):
5691 self.ioctx = convert_ioctx(ioctx)
5692 self.num_entries = 1024
5695 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
5697 sizeof(rbd_trash_image_info_t))
5699 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
5701 self.num_entries = ret
5703 elif ret != -errno.ERANGE:
5704 raise make_ex(ret, 'error listing trash entries')
5706 __source_string = ['USER', 'MIRRORING']
5709 for i in range(self.num_entries):
5711 'id' : decode_cstr(self.entries[i].id),
5712 'name' : decode_cstr(self.entries[i].name),
5713 'source' : TrashIterator.__source_string[self.entries[i].source],
5714 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
5715 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
5718 def __dealloc__(self):
5719 rbd_trash_list_cleanup(self.entries, self.num_entries)
5723 cdef class ChildIterator(object):
5725 Iterator over child info for the image or its snapshot.
5727 Yields a dictionary containing information about a child.
5731 * ``pool`` (str) - name of the pool
5733 * ``pool_namespace`` (str) - namespace of the pool
5735 * ``image`` (str) - name of the child
5737 * ``id`` (str) - id of the child
5739 * ``trash`` (bool) - True if child is in trash bin
5742 cdef rbd_linked_image_spec_t *children
5743 cdef size_t num_children
5746 def __init__(self, Image image, descendants=False):
5747 image.require_not_closed()
5750 self.children = NULL
5751 self.num_children = 10
5753 self.children = <rbd_linked_image_spec_t*>realloc_chk(
5754 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
5757 ret = rbd_list_descendants(image.image, self.children,
5761 ret = rbd_list_children3(image.image, self.children,
5765 elif ret != -errno.ERANGE:
5766 raise make_ex(ret, 'error listing children.')
5769 for i in range(self.num_children):
5771 'pool' : decode_cstr(self.children[i].pool_name),
5772 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
5773 'image' : decode_cstr(self.children[i].image_name),
5774 'id' : decode_cstr(self.children[i].image_id),
5775 'trash' : self.children[i].trash
5778 def __dealloc__(self):
5780 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
5783 cdef class WatcherIterator(object):
5785 Iterator over watchers of an image.
5787 Yields a dictionary containing information about a watcher.
5791 * ``addr`` (str) - address of the watcher
5793 * ``id`` (int) - id of the watcher
5795 * ``cookie`` (int) - the watcher's cookie
5798 cdef rbd_image_watcher_t *watchers
5799 cdef size_t num_watchers
5802 def __init__(self, Image image):
5803 image.require_not_closed()
5806 self.watchers = NULL
5807 self.num_watchers = 10
5809 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
5811 sizeof(rbd_image_watcher_t))
5813 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
5816 elif ret != -errno.ERANGE:
5817 raise make_ex(ret, 'error listing watchers.')
5820 for i in range(self.num_watchers):
5822 'addr' : decode_cstr(self.watchers[i].addr),
5823 'id' : self.watchers[i].id,
5824 'cookie' : self.watchers[i].cookie
5827 def __dealloc__(self):
5829 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
5832 cdef class ConfigImageIterator(object):
5834 Iterator over image-level overrides for an image.
5836 Yields a dictionary containing information about an override.
5840 * ``name`` (str) - override name
5842 * ``value`` (str) - override value
5844 * ``source`` (str) - override source
5848 rbd_config_option_t *options
5851 def __init__(self, Image image):
5852 image.require_not_closed()
5855 self.num_options = 32
5857 self.options = <rbd_config_option_t *>realloc_chk(
5858 self.options, self.num_options * sizeof(rbd_config_option_t))
5860 ret = rbd_config_image_list(image.image, self.options,
5863 if ret == -errno.ERANGE:
5865 self.num_options = 0
5866 raise make_ex(ret, 'error listing config options')
5870 for i in range(self.num_options):
5872 'name' : decode_cstr(self.options[i].name),
5873 'value' : decode_cstr(self.options[i].value),
5874 'source' : self.options[i].source,
5877 def __dealloc__(self):
5879 rbd_config_image_list_cleanup(self.options, self.num_options)
5882 cdef class GroupImageIterator(object):
5884 Iterator over image info for a group.
5886 Yields a dictionary containing information about an image.
5890 * ``name`` (str) - name of the image
5892 * ``pool`` (int) - id of the pool this image belongs to
5894 * ``state`` (int) - state of the image
5897 cdef rbd_group_image_info_t *images
5898 cdef size_t num_images
5901 def __init__(self, Group group):
5904 self.num_images = 10
5906 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
5908 sizeof(rbd_group_image_info_t))
5910 ret = rbd_group_image_list(group._ioctx, group._name,
5912 sizeof(rbd_group_image_info_t),
5917 elif ret != -errno.ERANGE:
5918 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
5921 for i in range(self.num_images):
5923 'name' : decode_cstr(self.images[i].name),
5924 'pool' : self.images[i].pool,
5925 'state' : self.images[i].state,
5928 def __dealloc__(self):
5930 rbd_group_image_list_cleanup(self.images,
5931 sizeof(rbd_group_image_info_t),
5935 cdef class GroupSnapIterator(object):
5937 Iterator over snaps specs for a group.
5939 Yields a dictionary containing information about a snapshot.
5943 * ``name`` (str) - name of the snapshot
5945 * ``state`` (int) - state of the snapshot
5948 cdef rbd_group_snap_info_t *snaps
5949 cdef size_t num_snaps
5952 def __init__(self, Group group):
5957 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
5959 sizeof(rbd_group_snap_info_t))
5961 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
5962 sizeof(rbd_group_snap_info_t),
5967 elif ret != -errno.ERANGE:
5968 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
5971 for i in range(self.num_snaps):
5973 'name' : decode_cstr(self.snaps[i].name),
5974 'state' : self.snaps[i].state,
5977 def __dealloc__(self):
5979 rbd_group_snap_list_cleanup(self.snaps,
5980 sizeof(rbd_group_snap_info_t),