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_write_zeroes(rbd_image_t image, uint64_t ofs, uint64_t len,
504 int zero_flags, int op_flags)
505 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
506 const char *destname, rbd_image_options_t dest_opts)
507 int rbd_deep_copy(rbd_image_t src, rados_ioctx_t dest_io_ctx,
508 const char *destname, rbd_image_options_t dest_opts)
509 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
511 void rbd_snap_list_end(rbd_snap_info_t *snaps)
512 int rbd_snap_create(rbd_image_t image, const char *snapname)
513 int rbd_snap_remove(rbd_image_t image, const char *snapname)
514 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
515 librbd_progress_fn_t cb, void *cbdata)
516 int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
517 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
518 int rbd_snap_rename(rbd_image_t image, const char *snapname,
519 const char* dstsnapsname)
520 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
521 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
522 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
524 int rbd_snap_exists(rbd_image_t image, const char *snapname, bint *exists)
525 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
526 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
527 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
528 int rbd_snap_set(rbd_image_t image, const char *snapname)
529 int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
530 int rbd_snap_get_name(rbd_image_t image, uint64_t snap_id,
531 char *snapname, size_t *name_len)
532 int rbd_snap_get_id(rbd_image_t image, const char *snapname,
534 int rbd_snap_get_namespace_type(rbd_image_t image,
536 rbd_snap_namespace_type_t *namespace_type)
537 int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
538 rbd_snap_group_namespace_t *group_info,
539 size_t snap_group_namespace_size)
540 void rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_spec,
541 size_t snap_group_namespace_size)
542 int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
543 char *original_name, size_t max_length)
544 int rbd_snap_get_mirror_namespace(
545 rbd_image_t image, uint64_t snap_id,
546 rbd_snap_mirror_namespace_t *mirror_ns,
547 size_t snap_mirror_namespace_size)
548 void rbd_snap_mirror_namespace_cleanup(
549 rbd_snap_mirror_namespace_t *mirror_ns,
550 size_t snap_mirror_namespace_size)
552 int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
554 int rbd_sparsify(rbd_image_t image, size_t sparse_size)
555 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
557 int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
558 size_t *max_children)
559 int rbd_list_descendants(rbd_image_t image,
560 rbd_linked_image_spec_t *descendants,
561 size_t *max_descendants)
563 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
564 char *tag, size_t *tag_len,
565 char *clients, size_t *clients_len,
566 char *cookies, size_t *cookies_len,
567 char *addrs, size_t *addrs_len)
568 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
569 int rbd_lock_shared(rbd_image_t image, const char *cookie,
571 int rbd_unlock(rbd_image_t image, const char *cookie)
572 int rbd_break_lock(rbd_image_t image, const char *client,
575 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
576 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
577 int rbd_lock_release(rbd_image_t image)
578 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
579 char **lock_owners, size_t *max_lock_owners)
580 void rbd_lock_get_owners_cleanup(char **lock_owners,
581 size_t lock_owner_count)
582 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
585 # We use -9000 to propagate Python exceptions. We use except? to make sure
586 # things still work as intended if -9000 happens to be a valid errno value
588 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
589 uint64_t ofs, uint64_t len,
590 uint8_t include_parent, uint8_t whole_object,
591 int (*cb)(uint64_t, size_t, int, void *)
593 void *arg) except? -9000
595 int rbd_flush(rbd_image_t image)
596 int rbd_invalidate_cache(rbd_image_t image)
598 int rbd_mirror_image_enable2(rbd_image_t image,
599 rbd_mirror_image_mode_t mode)
600 int rbd_mirror_image_disable(rbd_image_t image, bint force)
601 int rbd_mirror_image_promote(rbd_image_t image, bint force)
602 int rbd_mirror_image_demote(rbd_image_t image)
603 int rbd_mirror_image_resync(rbd_image_t image)
604 int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id)
605 int rbd_mirror_image_get_info(rbd_image_t image,
606 rbd_mirror_image_info_t *mirror_image_info,
608 void rbd_mirror_image_get_info_cleanup(
609 rbd_mirror_image_info_t *mirror_image_info)
610 int rbd_mirror_image_get_mode(rbd_image_t image,
611 rbd_mirror_image_mode_t *mode)
612 int rbd_mirror_image_get_global_status(
614 rbd_mirror_image_global_status_t *mirror_image_global_status,
616 void rbd_mirror_image_global_status_cleanup(
617 rbd_mirror_image_global_status_t *mirror_image_global_status)
618 int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id,
619 size_t *id_max_length)
621 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
622 const char *buf, rbd_completion_t c, int op_flags)
623 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
624 char *buf, rbd_completion_t c, int op_flags)
625 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
627 int rbd_aio_write_zeroes(rbd_image_t image, uint64_t off, uint64_t len,
628 rbd_completion_t c, int zero_flags, int op_flags)
630 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
632 int rbd_aio_is_complete(rbd_completion_t c)
633 int rbd_aio_wait_for_complete(rbd_completion_t c)
634 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
635 void rbd_aio_release(rbd_completion_t c)
636 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
638 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
640 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
641 int rbd_metadata_remove(rbd_image_t image, const char *key)
642 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
643 char *keys, size_t *key_len, char *values,
645 int rbd_group_create(rados_ioctx_t p, const char *name)
646 int rbd_group_remove(rados_ioctx_t p, const char *name)
647 int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
648 int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest)
649 void rbd_group_info_cleanup(rbd_group_info_t *group_info,
650 size_t group_info_size)
651 int rbd_group_image_add(rados_ioctx_t group_p, const char *group_name,
652 rados_ioctx_t image_p, const char *image_name)
653 int rbd_group_image_remove(rados_ioctx_t group_p, const char *group_name,
654 rados_ioctx_t image_p, const char *image_name)
656 int rbd_group_image_list(rados_ioctx_t group_p,
657 const char *group_name,
658 rbd_group_image_info_t *images,
659 size_t group_image_info_size,
661 void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
662 size_t group_image_info_size, size_t len)
664 int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
665 const char *snap_name)
667 int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
668 const char *snap_name)
670 int rbd_group_snap_rename(rados_ioctx_t group_p, const char *group_name,
671 const char *old_snap_name,
672 const char *new_snap_name)
674 int rbd_group_snap_list(rados_ioctx_t group_p,
675 const char *group_name,
676 rbd_group_snap_info_t *snaps,
677 size_t group_snap_info_size,
680 void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
681 size_t group_snap_info_size, size_t len)
682 int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
683 const char *snap_name)
685 int rbd_watchers_list(rbd_image_t image, rbd_image_watcher_t *watchers,
686 size_t *max_watchers)
687 void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
690 int rbd_config_image_list(rbd_image_t image, rbd_config_option_t *options,
692 void rbd_config_image_list_cleanup(rbd_config_option_t *options,
695 int rbd_namespace_create(rados_ioctx_t io, const char *namespace_name)
696 int rbd_namespace_remove(rados_ioctx_t io, const char *namespace_name)
697 int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
699 int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
702 int rbd_pool_init(rados_ioctx_t, bint force)
704 void rbd_pool_stats_create(rbd_pool_stats_t *stats)
705 void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
706 int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
707 int stat_option, uint64_t* stat_val)
708 int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
710 ECANCELED = _ECANCELED
712 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
713 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
714 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
715 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
716 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
717 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
718 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
719 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
720 RBD_FEATURE_OPERATIONS = _RBD_FEATURE_OPERATIONS
721 RBD_FEATURE_MIGRATING = _RBD_FEATURE_MIGRATING
722 RBD_FEATURE_NON_PRIMARY = _RBD_FEATURE_NON_PRIMARY
724 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
725 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
726 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
727 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
728 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
730 RBD_OPERATION_FEATURE_CLONE_PARENT = _RBD_OPERATION_FEATURE_CLONE_PARENT
731 RBD_OPERATION_FEATURE_CLONE_CHILD = _RBD_OPERATION_FEATURE_CLONE_CHILD
732 RBD_OPERATION_FEATURE_GROUP = _RBD_OPERATION_FEATURE_GROUP
733 RBD_OPERATION_FEATURE_SNAP_TRASH = _RBD_OPERATION_FEATURE_SNAP_TRASH
735 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
736 RBD_FLAG_FAST_DIFF_INVALID = _RBD_FLAG_FAST_DIFF_INVALID
738 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
739 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
740 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
742 RBD_MIRROR_PEER_DIRECTION_RX = _RBD_MIRROR_PEER_DIRECTION_RX
743 RBD_MIRROR_PEER_DIRECTION_TX = _RBD_MIRROR_PEER_DIRECTION_TX
744 RBD_MIRROR_PEER_DIRECTION_RX_TX = _RBD_MIRROR_PEER_DIRECTION_RX_TX
746 RBD_MIRROR_IMAGE_MODE_JOURNAL = _RBD_MIRROR_IMAGE_MODE_JOURNAL
747 RBD_MIRROR_IMAGE_MODE_SNAPSHOT = _RBD_MIRROR_IMAGE_MODE_SNAPSHOT
749 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
750 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
751 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
753 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
754 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
755 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
756 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
757 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
758 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
759 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
761 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
762 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
764 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
765 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
766 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
767 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
768 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
769 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
771 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
772 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
773 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
774 RBD_SNAP_NAMESPACE_TYPE_MIRROR = _RBD_SNAP_NAMESPACE_TYPE_MIRROR
776 RBD_SNAP_MIRROR_STATE_PRIMARY = _RBD_SNAP_MIRROR_STATE_PRIMARY
777 RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED
778 RBD_SNAP_MIRROR_STATE_NON_PRIMARY = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY
779 RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
781 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
782 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
784 RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
785 RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
787 RBD_IMAGE_MIGRATION_STATE_UNKNOWN = _RBD_IMAGE_MIGRATION_STATE_UNKNOWN
788 RBD_IMAGE_MIGRATION_STATE_ERROR = _RBD_IMAGE_MIGRATION_STATE_ERROR
789 RBD_IMAGE_MIGRATION_STATE_PREPARING = _RBD_IMAGE_MIGRATION_STATE_PREPARING
790 RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
791 RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
792 RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
794 RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
795 RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
796 RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
798 RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
799 RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
800 RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
801 RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
802 RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
803 RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
804 RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
805 RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
807 RBD_SNAP_REMOVE_UNPROTECT = _RBD_SNAP_REMOVE_UNPROTECT
808 RBD_SNAP_REMOVE_FLATTEN = _RBD_SNAP_REMOVE_FLATTEN
809 RBD_SNAP_REMOVE_FORCE = _RBD_SNAP_REMOVE_FORCE
811 class Error(Exception):
815 class OSError(Error):
816 """ `OSError` class, derived from `Error` """
817 def __init__(self, message, errno=None):
818 super(OSError, self).__init__(message)
822 msg = super(OSError, self).__str__()
823 if self.errno is None:
825 return '[errno {0}] {1}'.format(self.errno, msg)
827 def __reduce__(self):
828 return (self.__class__, (self.message, self.errno))
830 class PermissionError(OSError):
831 def __init__(self, message, errno=None):
832 super(PermissionError, self).__init__(
833 "RBD permission error (%s)" % message, errno)
836 class ImageNotFound(OSError):
837 def __init__(self, message, errno=None):
838 super(ImageNotFound, self).__init__(
839 "RBD image not found (%s)" % message, errno)
842 class ObjectNotFound(OSError):
843 def __init__(self, message, errno=None):
844 super(ObjectNotFound, self).__init__(
845 "RBD object not found (%s)" % message, errno)
848 class ImageExists(OSError):
849 def __init__(self, message, errno=None):
850 super(ImageExists, self).__init__(
851 "RBD image already exists (%s)" % message, errno)
854 class ObjectExists(OSError):
855 def __init__(self, message, errno=None):
856 super(ObjectExists, self).__init__(
857 "RBD object already exists (%s)" % message, errno)
860 class IOError(OSError):
861 def __init__(self, message, errno=None):
862 super(IOError, self).__init__(
863 "RBD I/O error (%s)" % message, errno)
866 class NoSpace(OSError):
867 def __init__(self, message, errno=None):
868 super(NoSpace, self).__init__(
869 "RBD insufficient space available (%s)" % message, errno)
872 class IncompleteWriteError(OSError):
873 def __init__(self, message, errno=None):
874 super(IncompleteWriteError, self).__init__(
875 "RBD incomplete write (%s)" % message, errno)
878 class InvalidArgument(OSError):
879 def __init__(self, message, errno=None):
880 super(InvalidArgument, self).__init__(
881 "RBD invalid argument (%s)" % message, errno)
884 class LogicError(OSError):
885 def __init__(self, message, errno=None):
886 super(LogicError, self).__init__(
887 "RBD logic error (%s)" % message, errno)
890 class ReadOnlyImage(OSError):
891 def __init__(self, message, errno=None):
892 super(ReadOnlyImage, self).__init__(
893 "RBD read-only image (%s)" % message, errno)
896 class ImageBusy(OSError):
897 def __init__(self, message, errno=None):
898 super(ImageBusy, self).__init__(
899 "RBD image is busy (%s)" % message, errno)
902 class ImageHasSnapshots(OSError):
903 def __init__(self, message, errno=None):
904 super(ImageHasSnapshots, self).__init__(
905 "RBD image has snapshots (%s)" % message, errno)
908 class FunctionNotSupported(OSError):
909 def __init__(self, message, errno=None):
910 super(FunctionNotSupported, self).__init__(
911 "RBD function not supported (%s)" % message, errno)
914 class ArgumentOutOfRange(OSError):
915 def __init__(self, message, errno=None):
916 super(ArgumentOutOfRange, self).__init__(
917 "RBD arguments out of range (%s)" % message, errno)
920 class ConnectionShutdown(OSError):
921 def __init__(self, message, errno=None):
922 super(ConnectionShutdown, self).__init__(
923 "RBD connection was shutdown (%s)" % message, errno)
926 class Timeout(OSError):
927 def __init__(self, message, errno=None):
928 super(Timeout, self).__init__(
929 "RBD operation timeout (%s)" % message, errno)
932 class DiskQuotaExceeded(OSError):
933 def __init__(self, message, errno=None):
934 super(DiskQuotaExceeded, self).__init__(
935 "RBD disk quota exceeded (%s)" % message, errno)
937 class OperationNotSupported(OSError):
938 def __init__(self, message, errno=None):
939 super(OperationNotSupported, self).__init__(
940 "RBD operation not supported (%s)" % message, errno)
942 class OperationCanceled(OSError):
943 def __init__(self, message, errno=None):
944 super(OperationCanceled, self).__init__(
945 "RBD operation canceled (%s)" % message, errno)
947 cdef errno_to_exception = {
948 errno.EPERM : PermissionError,
949 errno.ENOENT : ImageNotFound,
951 errno.ENOSPC : NoSpace,
952 errno.EEXIST : ImageExists,
953 errno.EINVAL : InvalidArgument,
954 errno.EROFS : ReadOnlyImage,
955 errno.EBUSY : ImageBusy,
956 errno.ENOTEMPTY : ImageHasSnapshots,
957 errno.ENOSYS : FunctionNotSupported,
958 errno.EDOM : ArgumentOutOfRange,
959 errno.ESHUTDOWN : ConnectionShutdown,
960 errno.ETIMEDOUT : Timeout,
961 errno.EDQUOT : DiskQuotaExceeded,
962 errno.EOPNOTSUPP : OperationNotSupported,
963 ECANCELED : OperationCanceled,
966 cdef group_errno_to_exception = {
967 errno.EPERM : PermissionError,
968 errno.ENOENT : ObjectNotFound,
970 errno.ENOSPC : NoSpace,
971 errno.EEXIST : ObjectExists,
972 errno.EINVAL : InvalidArgument,
973 errno.EROFS : ReadOnlyImage,
974 errno.EBUSY : ImageBusy,
975 errno.ENOTEMPTY : ImageHasSnapshots,
976 errno.ENOSYS : FunctionNotSupported,
977 errno.EDOM : ArgumentOutOfRange,
978 errno.ESHUTDOWN : ConnectionShutdown,
979 errno.ETIMEDOUT : Timeout,
980 errno.EDQUOT : DiskQuotaExceeded,
981 errno.EOPNOTSUPP : OperationNotSupported,
982 ECANCELED : OperationCanceled,
985 cdef make_ex(ret, msg, exception_map=errno_to_exception):
987 Translate a librbd return code into an exception.
989 :param ret: the return code
991 :param msg: the error message to use
993 :returns: a subclass of :class:`Error`
996 if ret in exception_map:
997 return exception_map[ret](msg, errno=ret)
999 return OSError(msg, errno=ret)
1002 cdef rados_t convert_rados(rados.Rados rados) except? NULL:
1003 return <rados_t>rados.cluster
1005 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
1006 return <rados_ioctx_t>ioctx.io
1008 cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
1009 return (<object>ptr)(offset, total)
1011 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
1014 def cstr(val, name, encoding="utf-8", opt=False):
1016 Create a byte string from a Python string
1018 :param basestring val: Python string
1019 :param str name: Name of the string parameter, for exceptions
1020 :param str encoding: Encoding to use
1021 :param bool opt: If True, None is allowed
1023 :raises: :class:`InvalidArgument`
1025 if opt and val is None:
1027 if isinstance(val, bytes):
1029 elif isinstance(val, str):
1030 return val.encode(encoding)
1031 elif sys.version_info < (3, 0) and isinstance(val, unicode):
1032 return val.encode(encoding)
1034 raise InvalidArgument('%s must be a string' % name)
1036 def decode_cstr(val, encoding="utf-8"):
1038 Decode a byte string into a Python string.
1040 :param bytes val: byte string
1041 :rtype: unicode or None
1046 return val.decode(encoding)
1049 cdef char* opt_str(s) except? NULL:
1054 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
1055 cdef void *ret = realloc(ptr, size)
1057 raise MemoryError("realloc failed")
1060 RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST)
1061 RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY)
1063 cdef class Completion
1065 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
1067 Callback to oncomplete() for asynchronous operations
1069 cdef Completion cb = <Completion>args
1073 cdef class Completion(object):
1074 """completion object"""
1079 rbd_completion_t rbd_comp
1084 def __cinit__(self, image, object oncomplete):
1085 self.oncomplete = oncomplete
1087 self.persisted = False
1089 def is_complete(self):
1091 Has an asynchronous operation completed?
1093 This does not imply that the callback has finished.
1095 :returns: True if the operation is completed
1098 ret = rbd_aio_is_complete(self.rbd_comp)
1101 def wait_for_complete_and_cb(self):
1103 Wait for an asynchronous operation to complete
1105 This method waits for the callback to execute, if one was provided.
1106 It will also re-raise any exceptions raised by the callback. You
1107 should call this to "reap" asynchronous completions and ensure that
1108 any exceptions in the callbacks are handled, as an exception internal
1109 to this module may have occurred.
1112 rbd_aio_wait_for_complete(self.rbd_comp)
1115 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
1117 def get_return_value(self):
1119 Get the return value of an asychronous operation
1121 The return value is set when the operation is complete.
1123 :returns: int - return value of the operation
1126 ret = rbd_aio_get_return_value(self.rbd_comp)
1129 def __dealloc__(self):
1131 Release a completion
1133 This is automatically called when the completion object is freed.
1135 ref.Py_XDECREF(self.buf)
1137 if self.rbd_comp != NULL:
1139 rbd_aio_release(self.rbd_comp)
1140 self.rbd_comp = NULL
1142 cdef void _complete(self):
1146 self.oncomplete(self)
1147 # In the event that something raises an exception during the next 2
1148 # lines of code, we will not be able to catch it, and this may result
1149 # in the app not noticing a failed callback. However, this should only
1150 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
1151 # should not be a problem because the callback thread from librbd
1152 # ought to have SIGINT blocked.
1154 self.exc_info = sys.exc_info()
1156 cdef __persist(self):
1157 if self.oncomplete is not None and not self.persisted:
1158 # Increment our own reference count to make sure the completion
1159 # is not freed until the callback is called. The completion is
1160 # allowed to be freed if there is no callback.
1162 self.persisted = True
1164 cdef __unpersist(self):
1167 self.persisted = False
1172 This class wraps librbd CRUD functions.
1176 Get the version number of the ``librbd`` C library.
1178 :returns: a tuple of ``(major, minor, extra)`` components of the
1184 rbd_version(&major, &minor, &extra)
1185 return (major, minor, extra)
1187 def create(self, ioctx, name, size, order=None, old_format=False,
1188 features=None, stripe_unit=None, stripe_count=None,
1191 Create an rbd image.
1193 :param ioctx: the context in which to create the image
1194 :type ioctx: :class:`rados.Ioctx`
1195 :param name: what the image is called
1197 :param size: how big the image is in bytes
1199 :param order: the image is split into (2**order) byte objects
1201 :param old_format: whether to create an old-style image that
1202 is accessible by old clients, but can't
1203 use more advanced features like layering.
1204 :type old_format: bool
1205 :param features: bitmask of features to enable
1207 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1208 :type stripe_unit: int
1209 :param stripe_count: objects to stripe over before looping
1210 :type stripe_count: int
1211 :param data_pool: optional separate pool for data blocks
1212 :type data_pool: str
1213 :raises: :class:`ImageExists`
1214 :raises: :class:`TypeError`
1215 :raises: :class:`InvalidArgument`
1216 :raises: :class:`FunctionNotSupported`
1218 name = cstr(name, 'name')
1219 data_pool = cstr(data_pool, 'data_pool', opt=True)
1221 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1223 uint64_t _size = size
1225 rbd_image_options_t opts
1226 if order is not None:
1230 ((stripe_unit is not None) and stripe_unit != 0) or
1231 ((stripe_count is not None) and stripe_count != 0) or
1233 raise InvalidArgument('format 1 images do not support feature '
1234 'masks, non-default striping, nor data '
1237 ret = rbd_create(_ioctx, _name, _size, &_order)
1239 rbd_image_options_create(&opts)
1241 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
1242 1 if old_format else 2)
1243 if features is not None:
1244 rbd_image_options_set_uint64(opts,
1245 RBD_IMAGE_OPTION_FEATURES,
1247 if order is not None:
1248 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1250 if stripe_unit is not None:
1251 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1253 if stripe_count is not None:
1254 rbd_image_options_set_uint64(opts,
1255 RBD_IMAGE_OPTION_STRIPE_COUNT,
1257 if data_pool is not None:
1258 rbd_image_options_set_string(opts,
1259 RBD_IMAGE_OPTION_DATA_POOL,
1262 ret = rbd_create4(_ioctx, _name, _size, opts)
1264 rbd_image_options_destroy(opts)
1266 raise make_ex(ret, 'error creating image')
1268 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
1269 features=None, order=None, stripe_unit=None, stripe_count=None,
1272 Clone a parent rbd snapshot into a COW sparse child.
1274 :param p_ioctx: the parent context that represents the parent snap
1275 :type ioctx: :class:`rados.Ioctx`
1276 :param p_name: the parent image name
1278 :param p_snapname: the parent image snapshot name
1280 :param c_ioctx: the child context that represents the new clone
1281 :type ioctx: :class:`rados.Ioctx`
1282 :param c_name: the clone (child) name
1284 :param features: bitmask of features to enable; if set, must include layering
1286 :param order: the image is split into (2**order) byte objects
1288 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1289 :type stripe_unit: int
1290 :param stripe_count: objects to stripe over before looping
1291 :type stripe_count: int
1292 :param data_pool: optional separate pool for data blocks
1293 :type data_pool: str
1294 :raises: :class:`TypeError`
1295 :raises: :class:`InvalidArgument`
1296 :raises: :class:`ImageExists`
1297 :raises: :class:`FunctionNotSupported`
1298 :raises: :class:`ArgumentOutOfRange`
1300 p_snapname = cstr(p_snapname, 'p_snapname')
1301 p_name = cstr(p_name, 'p_name')
1302 c_name = cstr(c_name, 'c_name')
1303 data_pool = cstr(data_pool, 'data_pool', opt=True)
1305 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
1306 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
1307 char *_p_name = p_name
1308 char *_p_snapname = p_snapname
1309 char *_c_name = c_name
1310 rbd_image_options_t opts
1312 rbd_image_options_create(&opts)
1314 if features is not None:
1315 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1317 if order is not None:
1318 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1320 if stripe_unit is not None:
1321 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1323 if stripe_count is not None:
1324 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1326 if data_pool is not None:
1327 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1330 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
1331 _c_ioctx, _c_name, opts)
1333 rbd_image_options_destroy(opts)
1335 raise make_ex(ret, 'error creating clone')
1337 def list(self, ioctx):
1341 :param ioctx: determines which RADOS pool is read
1342 :type ioctx: :class:`rados.Ioctx`
1343 :returns: list -- a list of image names
1346 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1348 char *c_names = NULL
1351 c_names = <char *>realloc_chk(c_names, size)
1353 ret = rbd_list(_ioctx, c_names, &size)
1356 elif ret != -errno.ERANGE:
1357 raise make_ex(ret, 'error listing images')
1358 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
1363 def list2(self, ioctx):
1365 Iterate over the images in the pool.
1367 :param ioctx: determines which RADOS pool the image is in
1368 :type ioctx: :class:`rados.Ioctx`
1369 :returns: :class:`ImageIterator`
1371 return ImageIterator(ioctx)
1373 def remove(self, ioctx, name, on_progress=None):
1375 Delete an RBD image. This may take a long time, since it does
1376 not return until every object that comprises the image has
1377 been deleted. Note that all snapshots must be deleted before
1378 the image can be removed. If there are snapshots left,
1379 :class:`ImageHasSnapshots` is raised. If the image is still
1380 open, or the watch from a crashed client has not expired,
1381 :class:`ImageBusy` is raised.
1383 :param ioctx: determines which RADOS pool the image is in
1384 :type ioctx: :class:`rados.Ioctx`
1385 :param name: the name of the image to remove
1387 :param on_progress: optional progress callback function
1388 :type on_progress: callback function
1389 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
1390 :class:`ImageHasSnapshots`
1392 name = cstr(name, 'name')
1394 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1396 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1397 void *_prog_arg = NULL
1399 _prog_cb = &progress_callback
1400 _prog_arg = <void *>on_progress
1402 ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
1404 raise make_ex(ret, 'error removing image')
1406 def rename(self, ioctx, src, dest):
1408 Rename an RBD image.
1410 :param ioctx: determines which RADOS pool the image is in
1411 :type ioctx: :class:`rados.Ioctx`
1412 :param src: the current name of the image
1414 :param dest: the new name of the image
1416 :raises: :class:`ImageNotFound`, :class:`ImageExists`
1418 src = cstr(src, 'src')
1419 dest = cstr(dest, 'dest')
1421 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1425 ret = rbd_rename(_ioctx, _src, _dest)
1427 raise make_ex(ret, 'error renaming image')
1429 def trash_move(self, ioctx, name, delay=0):
1431 Move an RBD image to the trash.
1433 :param ioctx: determines which RADOS pool the image is in
1434 :type ioctx: :class:`rados.Ioctx`
1435 :param name: the name of the image to remove
1437 :param delay: time delay in seconds before the image can be deleted
1440 :raises: :class:`ImageNotFound`
1442 name = cstr(name, 'name')
1444 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1446 uint64_t _delay = delay
1448 ret = rbd_trash_move(_ioctx, _name, _delay)
1450 raise make_ex(ret, 'error moving image to trash')
1452 def trash_purge(self, ioctx, expire_ts=None, threshold=-1):
1454 Delete RBD images from trash in bulk.
1456 By default it removes images with deferment end time less than now.
1458 The timestamp is configurable, e.g. delete images that have expired a
1461 If the threshold is used it deletes images until X% pool usage is met.
1463 :param ioctx: determines which RADOS pool the image is in
1464 :type ioctx: :class:`rados.Ioctx`
1465 :param expire_ts: timestamp for images to be considered as expired (UTC)
1466 :type expire_ts: datetime
1467 :param threshold: percentage of pool usage to be met (0 to 1)
1468 :type threshold: float
1471 expire_epoch_ts = time.mktime(expire_ts.timetuple())
1476 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1477 time_t _expire_ts = expire_epoch_ts
1478 float _threshold = threshold
1480 ret = rbd_trash_purge(_ioctx, _expire_ts, _threshold)
1482 raise make_ex(ret, 'error purging images from trash')
1484 def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
1486 Delete an RBD image from trash. If image deferment time has not
1487 expired :class:`PermissionError` is raised.
1489 :param ioctx: determines which RADOS pool the image is in
1490 :type ioctx: :class:`rados.Ioctx`
1491 :param image_id: the id of the image to remove
1493 :param force: force remove even if deferment time has not expired
1495 :param on_progress: optional progress callback function
1496 :type on_progress: callback function
1497 :raises: :class:`ImageNotFound`, :class:`PermissionError`
1499 image_id = cstr(image_id, 'image_id')
1501 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1502 char *_image_id = image_id
1504 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1505 void *_prog_arg = NULL
1507 _prog_cb = &progress_callback
1508 _prog_arg = <void *>on_progress
1510 ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
1511 _prog_cb, _prog_arg)
1513 raise make_ex(ret, 'error deleting image from trash')
1515 def trash_get(self, ioctx, image_id):
1517 Retrieve RBD image info from trash.
1519 :param ioctx: determines which RADOS pool the image is in
1520 :type ioctx: :class:`rados.Ioctx`
1521 :param image_id: the id of the image to restore
1523 :returns: dict - contains the following keys:
1525 * ``id`` (str) - image id
1527 * ``name`` (str) - image name
1529 * ``source`` (str) - source of deletion
1531 * ``deletion_time`` (datetime) - time of deletion
1533 * ``deferment_end_time`` (datetime) - time that an image is allowed
1534 to be removed from trash
1536 :raises: :class:`ImageNotFound`
1538 image_id = cstr(image_id, 'image_id')
1540 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1541 char *_image_id = image_id
1542 rbd_trash_image_info_t c_info
1544 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
1546 raise make_ex(ret, 'error retrieving image from trash')
1548 __source_string = ['USER', 'MIRRORING', 'MIGRATION', 'REMOVING']
1550 'id' : decode_cstr(c_info.id),
1551 'name' : decode_cstr(c_info.name),
1552 'source' : __source_string[c_info.source],
1553 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
1554 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
1556 rbd_trash_get_cleanup(&c_info)
1559 def trash_list(self, ioctx):
1561 List all entries from trash.
1563 :param ioctx: determines which RADOS pool the image is in
1564 :type ioctx: :class:`rados.Ioctx`
1565 :returns: :class:`TrashIterator`
1567 return TrashIterator(ioctx)
1569 def trash_restore(self, ioctx, image_id, name):
1571 Restore an RBD image from trash.
1573 :param ioctx: determines which RADOS pool the image is in
1574 :type ioctx: :class:`rados.Ioctx`
1575 :param image_id: the id of the image to restore
1577 :param name: the new name of the restored image
1579 :raises: :class:`ImageNotFound`
1581 image_id = cstr(image_id, 'image_id')
1582 name = cstr(name, 'name')
1584 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1585 char *_image_id = image_id
1588 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1590 raise make_ex(ret, 'error restoring image from trash')
1592 def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
1593 features=None, order=None, stripe_unit=None, stripe_count=None,
1596 Prepare an RBD image migration.
1598 :param ioctx: determines which RADOS pool the image is in
1599 :type ioctx: :class:`rados.Ioctx`
1600 :param image_name: the current name of the image
1602 :param dest_ioctx: determines which pool to migration into
1603 :type dest_ioctx: :class:`rados.Ioctx`
1604 :param dest_image_name: the name of the destination image (may be the same image)
1605 :type dest_image_name: str
1606 :param features: bitmask of features to enable; if set, must include layering
1608 :param order: the image is split into (2**order) byte objects
1610 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1611 :type stripe_unit: int
1612 :param stripe_count: objects to stripe over before looping
1613 :type stripe_count: int
1614 :param data_pool: optional separate pool for data blocks
1615 :type data_pool: str
1616 :raises: :class:`TypeError`
1617 :raises: :class:`InvalidArgument`
1618 :raises: :class:`ImageExists`
1619 :raises: :class:`FunctionNotSupported`
1620 :raises: :class:`ArgumentOutOfRange`
1622 image_name = cstr(image_name, 'image_name')
1623 dest_image_name = cstr(dest_image_name, 'dest_image_name')
1625 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1626 char *_image_name = image_name
1627 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1628 char *_dest_image_name = dest_image_name
1629 rbd_image_options_t opts
1631 rbd_image_options_create(&opts)
1633 if features is not None:
1634 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1636 if order is not None:
1637 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1639 if stripe_unit is not None:
1640 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1642 if stripe_count is not None:
1643 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1645 if data_pool is not None:
1646 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1649 ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
1650 _dest_image_name, opts)
1652 rbd_image_options_destroy(opts)
1654 raise make_ex(ret, 'error migrating image %s' % (image_name))
1656 def migration_execute(self, ioctx, image_name, on_progress=None):
1658 Execute a prepared RBD image migration.
1660 :param ioctx: determines which RADOS pool the image is in
1661 :type ioctx: :class:`rados.Ioctx`
1662 :param image_name: the name of the image
1663 :type image_name: str
1664 :param on_progress: optional progress callback function
1665 :type on_progress: callback function
1666 :raises: :class:`ImageNotFound`
1668 image_name = cstr(image_name, 'image_name')
1670 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1671 char *_image_name = image_name
1672 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1673 void *_prog_arg = NULL
1675 _prog_cb = &progress_callback
1676 _prog_arg = <void *>on_progress
1678 ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
1679 _prog_cb, _prog_arg)
1681 raise make_ex(ret, 'error aborting migration')
1683 def migration_commit(self, ioctx, image_name, on_progress=None):
1685 Commit an executed RBD image migration.
1687 :param ioctx: determines which RADOS pool the image is in
1688 :type ioctx: :class:`rados.Ioctx`
1689 :param image_name: the name of the image
1690 :type image_name: str
1691 :param on_progress: optional progress callback function
1692 :type on_progress: callback function
1693 :raises: :class:`ImageNotFound`
1695 image_name = cstr(image_name, 'image_name')
1697 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1698 char *_image_name = image_name
1699 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1700 void *_prog_arg = NULL
1702 _prog_cb = &progress_callback
1703 _prog_arg = <void *>on_progress
1705 ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
1706 _prog_cb, _prog_arg)
1708 raise make_ex(ret, 'error aborting migration')
1710 def migration_abort(self, ioctx, image_name, on_progress=None):
1712 Cancel a previously started but interrupted migration.
1714 :param ioctx: determines which RADOS pool the image is in
1715 :type ioctx: :class:`rados.Ioctx`
1716 :param image_name: the name of the image
1717 :type image_name: str
1718 :param on_progress: optional progress callback function
1719 :type on_progress: callback function
1720 :raises: :class:`ImageNotFound`
1722 image_name = cstr(image_name, 'image_name')
1724 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1725 char *_image_name = image_name
1726 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1727 void *_prog_arg = NULL
1729 _prog_cb = &progress_callback
1730 _prog_arg = <void *>on_progress
1732 ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
1733 _prog_cb, _prog_arg)
1735 raise make_ex(ret, 'error aborting migration')
1737 def migration_status(self, ioctx, image_name):
1739 Return RBD image migration status.
1741 :param ioctx: determines which RADOS pool the image is in
1742 :type ioctx: :class:`rados.Ioctx`
1743 :param image_name: the name of the image
1744 :type image_name: str
1745 :returns: dict - contains the following keys:
1747 * ``source_pool_id`` (int) - source image pool id
1749 * ``source_pool_namespace`` (str) - source image pool namespace
1751 * ``source_image_name`` (str) - source image name
1753 * ``source_image_id`` (str) - source image id
1755 * ``dest_pool_id`` (int) - destination image pool id
1757 * ``dest_pool_namespace`` (str) - destination image pool namespace
1759 * ``dest_image_name`` (str) - destination image name
1761 * ``dest_image_id`` (str) - destination image id
1763 * ``state`` (int) - current migration state
1765 * ``state_description`` (str) - migration state description
1767 :raises: :class:`ImageNotFound`
1769 image_name = cstr(image_name, 'image_name')
1771 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1772 char *_image_name = image_name
1773 rbd_image_migration_status_t c_status
1775 ret = rbd_migration_status(_ioctx, _image_name, &c_status,
1778 raise make_ex(ret, 'error getting migration status')
1781 'source_pool_id' : c_status.source_pool_id,
1782 'source_pool_namespace' : decode_cstr(c_status.source_pool_namespace),
1783 'source_image_name' : decode_cstr(c_status.source_image_name),
1784 'source_image_id' : decode_cstr(c_status.source_image_id),
1785 'dest_pool_id' : c_status.source_pool_id,
1786 'dest_pool_namespace' : decode_cstr(c_status.dest_pool_namespace),
1787 'dest_image_name' : decode_cstr(c_status.dest_image_name),
1788 'dest_image_id' : decode_cstr(c_status.dest_image_id),
1789 'state' : c_status.state,
1790 'state_description' : decode_cstr(c_status.state_description)
1793 rbd_migration_status_cleanup(&c_status)
1797 def mirror_site_name_get(self, rados):
1799 Get the local cluster's friendly site name
1801 :param rados: cluster connection
1802 :type rados: :class: rados.Rados
1803 :returns: str - local site name
1806 rados_t _rados = convert_rados(rados)
1807 char *_site_name = NULL
1808 size_t _max_size = 512
1811 _site_name = <char *>realloc_chk(_site_name, _max_size)
1813 ret = rbd_mirror_site_name_get(_rados, _site_name,
1817 elif ret != -errno.ERANGE:
1818 raise make_ex(ret, 'error getting site name')
1819 return decode_cstr(_site_name)
1823 def mirror_site_name_set(self, rados, site_name):
1825 Set the local cluster's friendly site name
1827 :param rados: cluster connection
1828 :type rados: :class: rados.Rados
1829 :param site_name: friendly site name
1832 site_name = cstr(site_name, 'site_name')
1834 rados_t _rados = convert_rados(rados)
1835 char *_site_name = site_name
1837 ret = rbd_mirror_site_name_set(_rados, _site_name)
1839 raise make_ex(ret, 'error setting mirror site name')
1841 def mirror_mode_get(self, ioctx):
1843 Get pool mirror mode.
1845 :param ioctx: determines which RADOS pool is read
1846 :type ioctx: :class:`rados.Ioctx`
1847 :returns: int - pool mirror mode
1850 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1851 rbd_mirror_mode_t mirror_mode
1853 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1855 raise make_ex(ret, 'error getting mirror mode')
1858 def mirror_mode_set(self, ioctx, mirror_mode):
1860 Set pool mirror mode.
1862 :param ioctx: determines which RADOS pool is written
1863 :type ioctx: :class:`rados.Ioctx`
1864 :param mirror_mode: mirror mode to set
1865 :type mirror_mode: int
1868 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1869 rbd_mirror_mode_t _mirror_mode = mirror_mode
1871 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1873 raise make_ex(ret, 'error setting mirror mode')
1875 def mirror_uuid_get(self, ioctx):
1877 Get pool mirror uuid
1879 :param ioctx: determines which RADOS pool is read
1880 :type ioctx: :class:`rados.Ioctx`
1881 :returns: ste - pool mirror uuid
1884 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1886 size_t _max_size = 512
1889 _uuid = <char *>realloc_chk(_uuid, _max_size)
1891 ret = rbd_mirror_uuid_get(_ioctx, _uuid, &_max_size)
1894 elif ret != -errno.ERANGE:
1895 raise make_ex(ret, 'error retrieving mirror uuid')
1896 return decode_cstr(_uuid)
1900 def mirror_peer_bootstrap_create(self, ioctx):
1902 Creates a new RBD mirroring bootstrap token for an
1905 :param ioctx: determines which RADOS pool is written
1906 :type ioctx: :class:`rados.Ioctx`
1907 :returns: str - bootstrap token
1910 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1912 size_t _max_size = 512
1915 _token = <char *>realloc_chk(_token, _max_size)
1917 ret = rbd_mirror_peer_bootstrap_create(_ioctx, _token,
1921 elif ret != -errno.ERANGE:
1922 raise make_ex(ret, 'error creating bootstrap token')
1923 return decode_cstr(_token)
1927 def mirror_peer_bootstrap_import(self, ioctx, direction, token):
1929 Import a bootstrap token from an external cluster to
1930 auto-configure the mirror peer.
1932 :param ioctx: determines which RADOS pool is written
1933 :type ioctx: :class:`rados.Ioctx`
1934 :param direction: mirror peer direction
1935 :type direction: int
1936 :param token: bootstrap token
1939 token = cstr(token, 'token')
1941 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1942 rbd_mirror_peer_direction_t _direction = direction
1943 char *_token = token
1945 ret = rbd_mirror_peer_bootstrap_import(_ioctx, _direction, _token)
1947 raise make_ex(ret, 'error importing bootstrap token')
1949 def mirror_peer_add(self, ioctx, site_name, client_name,
1950 direction=RBD_MIRROR_PEER_DIRECTION_RX_TX):
1954 :param ioctx: determines which RADOS pool is used
1955 :type ioctx: :class:`rados.Ioctx`
1956 :param site_name: mirror peer site name
1957 :type site_name: str
1958 :param client_name: mirror peer client name
1959 :type client_name: str
1960 :param direction: the direction of the mirroring
1961 :type direction: int
1962 :returns: str - peer uuid
1964 site_name = cstr(site_name, 'site_name')
1965 client_name = cstr(client_name, 'client_name')
1967 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1969 size_t _uuid_max_length = 512
1970 rbd_mirror_peer_direction_t _direction = direction
1971 char *_site_name = site_name
1972 char *_client_name = client_name
1974 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1975 ret = rbd_mirror_peer_site_add(_ioctx, _uuid, _uuid_max_length,
1976 _direction, _site_name, _client_name)
1978 raise make_ex(ret, 'error adding mirror peer')
1979 return decode_cstr(_uuid)
1983 def mirror_peer_remove(self, ioctx, uuid):
1987 :param ioctx: determines which RADOS pool is used
1988 :type ioctx: :class:`rados.Ioctx`
1989 :param uuid: peer uuid
1992 uuid = cstr(uuid, 'uuid')
1994 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1997 ret = rbd_mirror_peer_site_remove(_ioctx, _uuid)
1999 raise make_ex(ret, 'error removing mirror peer')
2001 def mirror_peer_list(self, ioctx):
2003 Iterate over the peers of a pool.
2005 :param ioctx: determines which RADOS pool is read
2006 :type ioctx: :class:`rados.Ioctx`
2007 :returns: :class:`MirrorPeerIterator`
2009 return MirrorPeerIterator(ioctx)
2011 def mirror_peer_set_client(self, ioctx, uuid, client_name):
2013 Set mirror peer client name
2015 :param ioctx: determines which RADOS pool is written
2016 :type ioctx: :class:`rados.Ioctx`
2017 :param uuid: uuid of the mirror peer
2019 :param client_name: client name of the mirror peer to set
2020 :type client_name: str
2022 uuid = cstr(uuid, 'uuid')
2023 client_name = cstr(client_name, 'client_name')
2025 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2027 char *_client_name = client_name
2029 ret = rbd_mirror_peer_site_set_client_name(_ioctx, _uuid,
2032 raise make_ex(ret, 'error setting mirror peer client name')
2034 def mirror_peer_set_name(self, ioctx, uuid, site_name):
2036 Set mirror peer site name
2038 :param ioctx: determines which RADOS pool is written
2039 :type ioctx: :class:`rados.Ioctx`
2040 :param uuid: uuid of the mirror peer
2042 :param site_name: site name of the mirror peer to set
2043 :type site_name: str
2045 uuid = cstr(uuid, 'uuid')
2046 site_name = cstr(site_name, 'site_name')
2048 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2050 char *_site_name = site_name
2052 ret = rbd_mirror_peer_site_set_name(_ioctx, _uuid, _site_name)
2054 raise make_ex(ret, 'error setting mirror peer site name')
2056 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
2057 self.mirror_peer_set_name(ioctx, uuid, cluster_name)
2059 def mirror_peer_get_attributes(self, ioctx, uuid):
2061 Get optional mirror peer attributes
2063 :param ioctx: determines which RADOS pool is written
2064 :type ioctx: :class:`rados.Ioctx`
2065 :param uuid: uuid of the mirror peer
2068 :returns: dict - contains the following keys:
2070 * ``mon_host`` (str) - monitor addresses
2072 * ``key`` (str) - CephX key
2074 uuid = cstr(uuid, 'uuid')
2076 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2080 size_t _keys_size = 512
2081 size_t _vals_size = 512
2085 _keys = <char *>realloc_chk(_keys, _keys_size)
2086 _vals = <char *>realloc_chk(_vals, _vals_size)
2088 ret = rbd_mirror_peer_site_get_attributes(
2089 _ioctx, _uuid, _keys, &_keys_size, _vals, &_vals_size,
2093 elif ret != -errno.ERANGE:
2094 raise make_ex(ret, 'error getting mirror peer attributes')
2095 keys = [decode_cstr(x) for x in _keys[:_keys_size].split(b'\0')[:-1]]
2096 vals = [decode_cstr(x) for x in _vals[:_vals_size].split(b'\0')[:-1]]
2097 return dict(zip(keys, vals))
2102 def mirror_peer_set_attributes(self, ioctx, uuid, attributes):
2104 Set optional mirror peer attributes
2106 :param ioctx: determines which RADOS pool is written
2107 :type ioctx: :class:`rados.Ioctx`
2108 :param uuid: uuid of the mirror peer
2110 :param attributes: 'mon_host' and 'key' attributes
2111 :type attributes: dict
2113 uuid = cstr(uuid, 'uuid')
2114 keys_str = b'\0'.join([cstr(x[0], 'key') for x in attributes.items()])
2115 vals_str = b'\0'.join([cstr(x[1], 'val') for x in attributes.items()])
2117 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2119 char *_keys = keys_str
2120 char *_vals = vals_str
2121 size_t _count = len(attributes)
2124 ret = rbd_mirror_peer_site_set_attributes(_ioctx, _uuid, _keys,
2127 raise make_ex(ret, 'error setting mirror peer attributes')
2129 def mirror_image_status_list(self, ioctx):
2131 Iterate over the mirror image statuses of a pool.
2133 :param ioctx: determines which RADOS pool is read
2134 :type ioctx: :class:`rados.Ioctx`
2135 :returns: :class:`MirrorImageStatusIterator`
2137 return MirrorImageStatusIterator(ioctx)
2139 def mirror_image_status_summary(self, ioctx):
2141 Get mirror image status summary of a pool.
2143 :param ioctx: determines which RADOS pool is read
2144 :type ioctx: :class:`rados.Ioctx`
2145 :returns: list - a list of (state, count) tuples
2148 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2149 rbd_mirror_image_status_state_t *states = NULL
2153 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
2154 sizeof(rbd_mirror_image_status_state_t) * maxlen)
2155 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
2157 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
2160 raise make_ex(ret, 'error getting mirror image status summary')
2161 return [(states[i], counts[i]) for i in range(maxlen)]
2166 def mirror_image_instance_id_list(self, ioctx):
2168 Iterate over the mirror image instance ids of a pool.
2170 :param ioctx: determines which RADOS pool is read
2171 :type ioctx: :class:`rados.Ioctx`
2172 :returns: :class:`MirrorImageInstanceIdIterator`
2174 return MirrorImageInstanceIdIterator(ioctx)
2176 def mirror_image_info_list(self, ioctx, mode_filter=None):
2178 Iterate over the mirror image instance ids of a pool.
2180 :param ioctx: determines which RADOS pool is read
2181 :param mode_filter: list images in this image mirror mode
2182 :type ioctx: :class:`rados.Ioctx`
2183 :returns: :class:`MirrorImageInfoIterator`
2185 return MirrorImageInfoIterator(ioctx, mode_filter)
2187 def pool_metadata_get(self, ioctx, key):
2189 Get pool metadata for the given key.
2191 :param ioctx: determines which RADOS pool is read
2192 :type ioctx: :class:`rados.Ioctx`
2193 :param key: metadata key
2195 :returns: str - metadata value
2197 key = cstr(key, 'key')
2199 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2206 value = <char *>realloc_chk(value, size)
2208 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2209 if ret != -errno.ERANGE:
2211 if ret == -errno.ENOENT:
2212 raise KeyError('no metadata %s' % (key))
2214 raise make_ex(ret, 'error getting metadata %s' % (key))
2215 return decode_cstr(value)
2219 def pool_metadata_set(self, ioctx, key, value):
2221 Set pool metadata for the given key.
2223 :param ioctx: determines which RADOS pool is read
2224 :type ioctx: :class:`rados.Ioctx`
2225 :param key: metadata key
2227 :param value: metadata value
2230 key = cstr(key, 'key')
2231 value = cstr(value, 'value')
2233 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2235 char *_value = value
2237 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2240 raise make_ex(ret, 'error setting metadata %s' % (key))
2242 def pool_metadata_remove(self, ioctx, key):
2244 Remove pool metadata for the given key.
2246 :param ioctx: determines which RADOS pool is read
2247 :type ioctx: :class:`rados.Ioctx`
2248 :param key: metadata key
2250 :returns: str - metadata value
2252 key = cstr(key, 'key')
2254 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2257 ret = rbd_pool_metadata_remove(_ioctx, _key)
2259 if ret == -errno.ENOENT:
2260 raise KeyError('no metadata %s' % (key))
2262 raise make_ex(ret, 'error removing metadata %s' % (key))
2264 def pool_metadata_list(self, ioctx):
2268 :returns: :class:`PoolMetadataIterator`
2270 return PoolMetadataIterator(ioctx)
2272 def config_list(self, ioctx):
2274 List pool-level config overrides.
2276 :returns: :class:`ConfigPoolIterator`
2278 return ConfigPoolIterator(ioctx)
2280 def config_get(self, ioctx, key):
2282 Get a pool-level configuration override.
2284 :param ioctx: determines which RADOS pool is read
2285 :type ioctx: :class:`rados.Ioctx`
2288 :returns: str - value
2290 conf_key = 'conf_' + key
2291 conf_key = cstr(conf_key, 'key')
2293 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2294 char *_key = conf_key
2300 value = <char *>realloc_chk(value, size)
2302 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2303 if ret != -errno.ERANGE:
2305 if ret == -errno.ENOENT:
2306 raise KeyError('no config %s for pool %s' % (key, ioctx.get_pool_name()))
2308 raise make_ex(ret, 'error getting config %s for pool %s' %
2309 (key, ioctx.get_pool_name()))
2310 return decode_cstr(value)
2314 def config_set(self, ioctx, key, value):
2316 Get a pool-level configuration override.
2318 :param ioctx: determines which RADOS pool is read
2319 :type ioctx: :class:`rados.Ioctx`
2325 conf_key = 'conf_' + key
2326 conf_key = cstr(conf_key, 'key')
2327 value = cstr(value, 'value')
2329 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2330 char *_key = conf_key
2331 char *_value = value
2333 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2336 raise make_ex(ret, 'error setting config %s for pool %s' %
2337 (key, ioctx.get_pool_name()))
2339 def config_remove(self, ioctx, key):
2341 Remove a pool-level configuration override.
2343 :param ioctx: determines which RADOS pool is read
2344 :type ioctx: :class:`rados.Ioctx`
2347 :returns: str - value
2349 conf_key = 'conf_' + key
2350 conf_key = cstr(conf_key, 'key')
2352 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2353 char *_key = conf_key
2355 ret = rbd_pool_metadata_remove(_ioctx, _key)
2357 if ret == -errno.ENOENT:
2358 raise KeyError('no config %s for pool %s' %
2359 (key, ioctx.get_pool_name()))
2361 raise make_ex(ret, 'error removing config %s for pool %s' %
2362 (key, ioctx.get_pool_name()))
2364 def group_create(self, ioctx, name):
2368 :param ioctx: determines which RADOS pool is used
2369 :type ioctx: :class:`rados.Ioctx`
2370 :param name: the name of the group
2372 :raises: :class:`ObjectExists`
2373 :raises: :class:`InvalidArgument`
2374 :raises: :class:`FunctionNotSupported`
2376 name = cstr(name, 'name')
2379 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2381 ret = rbd_group_create(_ioctx, _name)
2383 raise make_ex(ret, 'error creating group %s' % name, group_errno_to_exception)
2385 def group_remove(self, ioctx, name):
2387 Delete an RBD group. This may take a long time, since it does
2388 not return until every image in the group has been removed
2391 :param ioctx: determines which RADOS pool the group is in
2392 :type ioctx: :class:`rados.Ioctx`
2393 :param name: the name of the group to remove
2395 :raises: :class:`ObjectNotFound`
2396 :raises: :class:`InvalidArgument`
2397 :raises: :class:`FunctionNotSupported`
2399 name = cstr(name, 'name')
2401 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2404 ret = rbd_group_remove(_ioctx, _name)
2406 raise make_ex(ret, 'error removing group', group_errno_to_exception)
2408 def group_list(self, ioctx):
2412 :param ioctx: determines which RADOS pool is read
2413 :type ioctx: :class:`rados.Ioctx`
2414 :returns: list -- a list of groups names
2415 :raises: :class:`FunctionNotSupported`
2418 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2420 char *c_names = NULL
2423 c_names = <char *>realloc_chk(c_names, size)
2425 ret = rbd_group_list(_ioctx, c_names, &size)
2428 elif ret != -errno.ERANGE:
2429 raise make_ex(ret, 'error listing groups', group_errno_to_exception)
2430 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
2435 def group_rename(self, ioctx, src, dest):
2437 Rename an RBD group.
2439 :param ioctx: determines which RADOS pool the group is in
2440 :type ioctx: :class:`rados.Ioctx`
2441 :param src: the current name of the group
2443 :param dest: the new name of the group
2445 :raises: :class:`ObjectExists`
2446 :raises: :class:`ObjectNotFound`
2447 :raises: :class:`InvalidArgument`
2448 :raises: :class:`FunctionNotSupported`
2450 src = cstr(src, 'src')
2451 dest = cstr(dest, 'dest')
2453 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2457 ret = rbd_group_rename(_ioctx, _src, _dest)
2459 raise make_ex(ret, 'error renaming group')
2461 def namespace_create(self, ioctx, name):
2463 Create an RBD namespace within a pool
2465 :param ioctx: determines which RADOS pool
2466 :type ioctx: :class:`rados.Ioctx`
2467 :param name: namespace name
2470 name = cstr(name, 'name')
2472 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2473 const char *_name = name
2475 ret = rbd_namespace_create(_ioctx, _name)
2477 raise make_ex(ret, 'error creating namespace')
2479 def namespace_remove(self, ioctx, name):
2481 Remove an RBD namespace from a pool
2483 :param ioctx: determines which RADOS pool
2484 :type ioctx: :class:`rados.Ioctx`
2485 :param name: namespace name
2488 name = cstr(name, 'name')
2490 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2491 const char *_name = name
2493 ret = rbd_namespace_remove(_ioctx, _name)
2495 raise make_ex(ret, 'error removing namespace')
2497 def namespace_exists(self, ioctx, name):
2499 Verifies if a namespace exists within a pool
2501 :param ioctx: determines which RADOS pool
2502 :type ioctx: :class:`rados.Ioctx`
2503 :param name: namespace name
2505 :returns: bool - true if namespace exists
2507 name = cstr(name, 'name')
2509 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2510 const char *_name = name
2511 bint _exists = False
2513 ret = rbd_namespace_exists(_ioctx, _name, &_exists)
2515 raise make_ex(ret, 'error verifying namespace')
2516 return bool(_exists != 0)
2518 def namespace_list(self, ioctx):
2520 List all namespaces within a pool
2522 :param ioctx: determines which RADOS pool
2523 :type ioctx: :class:`rados.Ioctx`
2524 :returns: list - collection of namespace names
2527 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2532 _names = <char *>realloc_chk(_names, _size)
2534 ret = rbd_namespace_list(_ioctx, _names, &_size)
2537 elif ret != -errno.ERANGE:
2538 raise make_ex(ret, 'error listing namespaces')
2539 return [decode_cstr(name) for name in _names[:_size].split(b'\0')
2544 def pool_init(self, ioctx, force):
2546 Initialize an RBD pool
2547 :param ioctx: determines which RADOS pool
2548 :type ioctx: :class:`rados.Ioctx`
2549 :param force: force init
2553 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2556 ret = rbd_pool_init(_ioctx, _force)
2558 raise make_ex(ret, 'error initializing pool')
2560 def pool_stats_get(self, ioctx):
2562 Return RBD pool stats
2564 :param ioctx: determines which RADOS pool
2565 :type ioctx: :class:`rados.Ioctx`
2566 :returns: dict - contains the following keys:
2568 * ``image_count`` (int) - image count
2570 * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
2572 * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
2574 * ``image_snap_count`` (int) - image snap count
2576 * ``trash_count`` (int) - trash image count
2578 * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
2580 * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
2582 * ``trash_snap_count`` (int) - trash snap count
2586 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2587 uint64_t _image_count = 0
2588 uint64_t _image_provisioned_bytes = 0
2589 uint64_t _image_max_provisioned_bytes = 0
2590 uint64_t _image_snap_count = 0
2591 uint64_t _trash_count = 0
2592 uint64_t _trash_provisioned_bytes = 0
2593 uint64_t _trash_max_provisioned_bytes = 0
2594 uint64_t _trash_snap_count = 0
2595 rbd_pool_stats_t _stats
2597 rbd_pool_stats_create(&_stats)
2598 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
2600 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
2601 &_image_provisioned_bytes)
2602 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
2603 &_image_max_provisioned_bytes)
2604 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
2606 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
2608 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
2609 &_trash_provisioned_bytes)
2610 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
2611 &_trash_max_provisioned_bytes)
2612 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
2616 ret = rbd_pool_stats_get(_ioctx, _stats)
2618 raise make_ex(ret, 'error retrieving pool stats')
2620 return {'image_count': _image_count,
2621 'image_provisioned_bytes': _image_provisioned_bytes,
2622 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
2623 'image_snap_count': _image_snap_count,
2624 'trash_count': _trash_count,
2625 'trash_provisioned_bytes': _trash_provisioned_bytes,
2626 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
2627 'trash_snap_count': _trash_snap_count}
2629 rbd_pool_stats_destroy(_stats)
2631 def features_to_string(self, features):
2633 Convert features bitmask to str.
2635 :param features: feature bitmask
2637 :returns: str - the features str of the image
2638 :raises: :class:`InvalidArgument`
2641 int ret = -errno.ERANGE
2642 uint64_t _features = features
2644 char *str_features = NULL
2646 while ret == -errno.ERANGE:
2647 str_features = <char *>realloc_chk(str_features, size)
2649 ret = rbd_features_to_string(_features, str_features, &size)
2652 raise make_ex(ret, 'error converting features bitmask to str')
2653 return decode_cstr(str_features)
2657 def features_from_string(self, str_features):
2659 Get features bitmask from str, if str_features is empty, it will return
2660 RBD_FEATURES_DEFAULT.
2662 :param str_features: feature str
2663 :type str_features: str
2664 :returns: int - the features bitmask of the image
2665 :raises: :class:`InvalidArgument`
2667 str_features = cstr(str_features, 'str_features')
2669 const char *_str_features = str_features
2672 ret = rbd_features_from_string(_str_features, &features)
2674 raise make_ex(ret, 'error getting features bitmask from str')
2678 cdef class MirrorPeerIterator(object):
2680 Iterator over mirror peer info for a pool.
2682 Yields a dictionary containing information about a peer.
2686 * ``uuid`` (str) - uuid of the peer
2688 * ``direction`` (int) - direction enum
2690 * ``site_name`` (str) - cluster name of the peer
2692 * ``mirror_uuid`` (str) - mirror uuid of the peer
2694 * ``client_name`` (str) - client name of the peer
2698 rbd_mirror_peer_site_t *peers
2701 def __init__(self, ioctx):
2703 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2707 self.peers = <rbd_mirror_peer_site_t *>realloc_chk(
2708 self.peers, self.num_peers * sizeof(rbd_mirror_peer_site_t))
2710 ret = rbd_mirror_peer_site_list(_ioctx, self.peers,
2713 if ret == -errno.ERANGE:
2716 raise make_ex(ret, 'error listing peers')
2720 for i in range(self.num_peers):
2722 'uuid' : decode_cstr(self.peers[i].uuid),
2723 'direction' : int(self.peers[i].direction),
2724 'site_name' : decode_cstr(self.peers[i].site_name),
2725 'cluster_name' : decode_cstr(self.peers[i].site_name),
2726 'mirror_uuid' : decode_cstr(self.peers[i].mirror_uuid),
2727 'client_name' : decode_cstr(self.peers[i].client_name),
2730 def __dealloc__(self):
2732 rbd_mirror_peer_site_list_cleanup(self.peers, self.num_peers)
2735 cdef class MirrorImageStatusIterator(object):
2737 Iterator over mirror image status for a pool.
2739 Yields a dictionary containing mirror status of an image.
2743 * ``name`` (str) - mirror image name
2745 * ``id`` (str) - mirror image id
2747 * ``info`` (dict) - mirror image info
2749 * ``state`` (int) - status mirror state
2751 * ``description`` (str) - status description
2753 * ``last_update`` (datetime) - last status update time
2755 * ``up`` (bool) - is mirroring agent up
2757 * ``remote_statuses`` (array) -
2759 * ``mirror uuid`` (str) - remote mirror uuid
2761 * ``state`` (int) - status mirror state
2763 * ``description`` (str) - status description
2765 * ``last_update`` (datetime) - last status update time
2767 * ``up`` (bool) - is mirroring agent up
2775 rbd_mirror_image_site_status_t *s_status
2776 rbd_mirror_image_global_status_t *images
2779 def __init__(self, ioctx):
2780 self.ioctx = convert_ioctx(ioctx)
2781 self.max_read = 1024
2782 self.last_read = strdup("")
2783 self.image_ids = <char **>realloc_chk(NULL,
2784 sizeof(char *) * self.max_read)
2785 self.images = <rbd_mirror_image_global_status_t *>realloc_chk(NULL,
2786 sizeof(rbd_mirror_image_global_status_t) * self.max_read)
2788 self.get_next_chunk()
2792 while self.size > 0:
2793 for i in range(self.size):
2797 for x in range(self.images[i].site_statuses_count):
2798 s_status = &self.images[i].site_statuses[x]
2800 'state' : s_status.state,
2801 'description' : decode_cstr(s_status.description),
2802 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
2805 mirror_uuid = decode_cstr(s_status.mirror_uuid)
2806 if mirror_uuid == '':
2807 local_status = site_status
2809 site_status['mirror_uuid'] = mirror_uuid
2810 site_statuses += site_status
2813 'name' : decode_cstr(self.images[i].name),
2814 'id' : decode_cstr(self.image_ids[i]),
2816 'global_id' : decode_cstr(self.images[i].info.global_id),
2817 'state' : self.images[i].info.state,
2819 'remote_statuses': site_statuses,
2822 status.update(local_status)
2824 if self.size < self.max_read:
2826 self.get_next_chunk()
2828 def __dealloc__(self):
2829 rbd_mirror_image_global_status_list_cleanup(self.image_ids, self.images,
2832 free(self.last_read)
2834 free(self.image_ids)
2838 def get_next_chunk(self):
2840 rbd_mirror_image_global_status_list_cleanup(self.image_ids,
2845 ret = rbd_mirror_image_global_status_list(self.ioctx,
2849 self.images, &self.size)
2851 raise make_ex(ret, 'error listing mirror images status')
2853 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2854 free(self.last_read)
2855 self.last_read = strdup(last_read)
2857 free(self.last_read)
2858 self.last_read = strdup("")
2860 cdef class MirrorImageInstanceIdIterator(object):
2862 Iterator over mirror image instance id for a pool.
2864 Yields ``(image_id, instance_id)`` tuple.
2875 def __init__(self, ioctx):
2876 self.ioctx = convert_ioctx(ioctx)
2877 self.max_read = 1024
2878 self.last_read = strdup("")
2879 self.image_ids = <char **>realloc_chk(NULL,
2880 sizeof(char *) * self.max_read)
2881 self.instance_ids = <char **>realloc_chk(NULL,
2882 sizeof(char *) * self.max_read)
2884 self.get_next_chunk()
2887 while self.size > 0:
2888 for i in range(self.size):
2889 yield (decode_cstr(self.image_ids[i]),
2890 decode_cstr(self.instance_ids[i]))
2891 if self.size < self.max_read:
2893 self.get_next_chunk()
2895 def __dealloc__(self):
2896 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2897 self.instance_ids, self.size)
2899 free(self.last_read)
2901 free(self.image_ids)
2902 if self.instance_ids:
2903 free(self.instance_ids)
2905 def get_next_chunk(self):
2907 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2912 ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read,
2918 raise make_ex(ret, 'error listing mirror images instance ids')
2920 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2921 free(self.last_read)
2922 self.last_read = strdup(last_read)
2924 free(self.last_read)
2925 self.last_read = strdup("")
2927 cdef class MirrorImageInfoIterator(object):
2929 Iterator over mirror image info for a pool.
2931 Yields ``(image_id, info)`` tuple.
2936 rbd_mirror_image_mode_t mode_filter
2937 rbd_mirror_image_mode_t *mode_filter_ptr
2941 rbd_mirror_image_info_t *info_entries
2942 rbd_mirror_image_mode_t *mode_entries
2945 def __init__(self, ioctx, mode_filter):
2946 self.ioctx = convert_ioctx(ioctx)
2947 if mode_filter is not None:
2948 self.mode_filter = mode_filter
2949 self.mode_filter_ptr = &self.mode_filter
2951 self.mode_filter_ptr = NULL
2952 self.max_read = 1024
2953 self.last_read = strdup("")
2954 self.image_ids = <char **>realloc_chk(NULL,
2955 sizeof(char *) * self.max_read)
2956 self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
2957 sizeof(rbd_mirror_image_info_t) * self.max_read)
2958 self.mode_entries = <rbd_mirror_image_mode_t *>realloc_chk(NULL,
2959 sizeof(rbd_mirror_image_mode_t) * self.max_read)
2961 self.get_next_chunk()
2964 while self.size > 0:
2965 for i in range(self.size):
2966 yield (decode_cstr(self.image_ids[i]),
2968 'mode' : int(self.mode_entries[i]),
2969 'global_id' : decode_cstr(self.info_entries[i].global_id),
2970 'state' : int(self.info_entries[i].state),
2971 'primary' : self.info_entries[i].primary,
2973 if self.size < self.max_read:
2975 self.get_next_chunk()
2977 def __dealloc__(self):
2978 rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries,
2981 free(self.last_read)
2983 free(self.image_ids)
2984 if self.info_entries:
2985 free(self.info_entries)
2986 if self.mode_entries:
2987 free(self.mode_entries)
2989 def get_next_chunk(self):
2991 rbd_mirror_image_info_list_cleanup(self.image_ids,
2992 self.info_entries, self.size)
2995 ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr,
2996 self.last_read, self.max_read,
2997 self.image_ids, self.mode_entries,
2998 self.info_entries, &self.size)
3000 raise make_ex(ret, 'error listing mirror image info')
3002 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
3003 free(self.last_read)
3004 self.last_read = strdup(last_read)
3006 free(self.last_read)
3007 self.last_read = strdup("")
3009 cdef class PoolMetadataIterator(object):
3011 Iterator over pool metadata list.
3013 Yields ``(key, value)`` tuple.
3015 * ``key`` (str) - metadata key
3016 * ``value`` (str) - metadata value
3025 def __init__(self, ioctx):
3026 self.ioctx = convert_ioctx(ioctx)
3027 self.last_read = strdup("")
3029 self.get_next_chunk()
3032 while len(self.next_chunk) > 0:
3033 for pair in self.next_chunk:
3035 if len(self.next_chunk) < self.max_read:
3037 self.get_next_chunk()
3039 def __dealloc__(self):
3041 free(self.last_read)
3043 def get_next_chunk(self):
3046 size_t keys_size = 4096
3048 size_t vals_size = 4096
3051 c_keys = <char *>realloc_chk(c_keys, keys_size)
3052 c_vals = <char *>realloc_chk(c_vals, vals_size)
3054 ret = rbd_pool_metadata_list(self.ioctx, self.last_read,
3055 self.max_read, c_keys,
3056 &keys_size, c_vals, &vals_size)
3059 elif ret != -errno.ERANGE:
3060 raise make_ex(ret, 'error listing metadata')
3061 keys = [decode_cstr(key) for key in
3062 c_keys[:keys_size].split(b'\0') if key]
3063 vals = [decode_cstr(val) for val in
3064 c_vals[:vals_size].split(b'\0') if val]
3066 last_read = cstr(keys[-1], 'last_read')
3067 free(self.last_read)
3068 self.last_read = strdup(last_read)
3069 self.next_chunk = list(zip(keys, vals))
3074 cdef class ConfigPoolIterator(object):
3076 Iterator over pool-level overrides for a pool.
3078 Yields a dictionary containing information about an override.
3082 * ``name`` (str) - override name
3084 * ``value`` (str) - override value
3086 * ``source`` (str) - override source
3090 rbd_config_option_t *options
3093 def __init__(self, ioctx):
3095 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3097 self.num_options = 32
3099 self.options = <rbd_config_option_t *>realloc_chk(
3100 self.options, self.num_options * sizeof(rbd_config_option_t))
3102 ret = rbd_config_pool_list(_ioctx, self.options, &self.num_options)
3104 if ret == -errno.ERANGE:
3106 self.num_options = 0
3107 raise make_ex(ret, 'error listing config options')
3111 for i in range(self.num_options):
3113 'name' : decode_cstr(self.options[i].name),
3114 'value' : decode_cstr(self.options[i].value),
3115 'source' : self.options[i].source,
3118 def __dealloc__(self):
3120 rbd_config_pool_list_cleanup(self.options, self.num_options)
3123 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
3124 except? -9000 with gil:
3125 # Make sure that if we wound up with an exception from a previous callback,
3126 # we stop calling back (just in case librbd ever fails to bail out on the
3127 # first negative return, as older versions did)
3128 if exc.PyErr_Occurred():
3130 ret = (<object>cb)(offset, length, bool(write))
3135 cdef class Group(object):
3137 This class represents an RBD group. It is used to interact with
3138 snapshots and images members.
3145 cdef rados_ioctx_t _ioctx
3147 def __init__(self, ioctx, name):
3148 name = cstr(name, 'name')
3151 self._ioctx = convert_ioctx(ioctx)
3154 def __enter__(self):
3157 def __exit__(self, type_, value, traceback):
3160 def add_image(self, image_ioctx, image_name):
3162 Add an image to a group.
3164 :param image_ioctx: determines which RADOS pool the image belongs to.
3165 :type ioctx: :class:`rados.Ioctx`
3166 :param name: the name of the image to add
3169 :raises: :class:`ObjectNotFound`
3170 :raises: :class:`ObjectExists`
3171 :raises: :class:`InvalidArgument`
3172 :raises: :class:`FunctionNotSupported`
3174 image_name = cstr(image_name, 'image_name')
3176 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3177 char *_image_name = image_name
3179 ret = rbd_group_image_add(self._ioctx, self._name, _image_ioctx, _image_name)
3181 raise make_ex(ret, 'error adding image to group', group_errno_to_exception)
3183 def remove_image(self, image_ioctx, image_name):
3185 Remove an image from a group.
3187 :param image_ioctx: determines which RADOS pool the image belongs to.
3188 :type ioctx: :class:`rados.Ioctx`
3189 :param name: the name of the image to remove
3192 :raises: :class:`ObjectNotFound`
3193 :raises: :class:`InvalidArgument`
3194 :raises: :class:`FunctionNotSupported`
3196 image_name = cstr(image_name, 'image_name')
3198 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3199 char *_image_name = image_name
3201 ret = rbd_group_image_remove(self._ioctx, self._name, _image_ioctx, _image_name)
3203 raise make_ex(ret, 'error removing image from group', group_errno_to_exception)
3206 def list_images(self):
3208 Iterate over the images of a group.
3210 :returns: :class:`GroupImageIterator`
3212 return GroupImageIterator(self)
3214 def create_snap(self, snap_name):
3216 Create a snapshot for the group.
3218 :param snap_name: the name of the snapshot to create
3221 :raises: :class:`ObjectNotFound`
3222 :raises: :class:`ObjectExists`
3223 :raises: :class:`InvalidArgument`
3224 :raises: :class:`FunctionNotSupported`
3226 snap_name = cstr(snap_name, 'snap_name')
3228 char *_snap_name = snap_name
3230 ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
3232 raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
3234 def remove_snap(self, snap_name):
3236 Remove a snapshot from the group.
3238 :param snap_name: the name of the snapshot to remove
3241 :raises: :class:`ObjectNotFound`
3242 :raises: :class:`InvalidArgument`
3243 :raises: :class:`FunctionNotSupported`
3245 snap_name = cstr(snap_name, 'snap_name')
3247 char *_snap_name = snap_name
3249 ret = rbd_group_snap_remove(self._ioctx, self._name, _snap_name)
3251 raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
3253 def rename_snap(self, old_snap_name, new_snap_name):
3255 Rename group's snapshot.
3257 :raises: :class:`ObjectNotFound`
3258 :raises: :class:`ObjectExists`
3259 :raises: :class:`InvalidArgument`
3260 :raises: :class:`FunctionNotSupported`
3263 old_snap_name = cstr(old_snap_name, 'old_snap_name')
3264 new_snap_name = cstr(new_snap_name, 'new_snap_name')
3266 char *_old_snap_name = old_snap_name
3267 char *_new_snap_name = new_snap_name
3269 ret = rbd_group_snap_rename(self._ioctx, self._name, _old_snap_name,
3272 raise make_ex(ret, 'error renaming group snapshot',
3273 group_errno_to_exception)
3275 def list_snaps(self):
3277 Iterate over the images of a group.
3279 :returns: :class:`GroupSnapIterator`
3281 return GroupSnapIterator(self)
3283 def rollback_to_snap(self, name):
3285 Rollback group to snapshot.
3287 :param name: the group snapshot to rollback to
3289 :raises: :class:`ObjectNotFound`
3290 :raises: :class:`IOError`
3292 name = cstr(name, 'name')
3293 cdef char *_name = name
3295 ret = rbd_group_snap_rollback(self._ioctx, self._name, _name)
3297 raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
3299 def requires_not_closed(f):
3300 def wrapper(self, *args, **kwargs):
3301 self.require_not_closed()
3302 return f(self, *args, **kwargs)
3306 cdef class Image(object):
3308 This class represents an RBD image. It is used to perform I/O on
3309 the image and interact with snapshots.
3311 **Note**: Any method of this class may raise :class:`ImageNotFound`
3312 if the image has been deleted.
3314 cdef rbd_image_t image
3318 cdef rados_ioctx_t _ioctx
3320 def __init__(self, ioctx, name=None, snapshot=None,
3321 read_only=False, image_id=None):
3323 Open the image at the given snapshot.
3324 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
3326 If a snapshot is specified, the image will be read-only, unless
3327 :func:`Image.set_snap` is called later.
3329 If read-only mode is used, metadata for the :class:`Image`
3330 object (such as which snapshots exist) may become obsolete. See
3331 the C api for more details.
3333 To clean up from opening the image, :func:`Image.close` should
3334 be called. For ease of use, this is done automatically when
3335 an :class:`Image` is used as a context manager (see :pep:`343`).
3337 :param ioctx: determines which RADOS pool the image is in
3338 :type ioctx: :class:`rados.Ioctx`
3339 :param name: the name of the image
3341 :param snapshot: which snapshot to read from
3342 :type snaphshot: str
3343 :param read_only: whether to open the image in read-only mode
3344 :type read_only: bool
3345 :param image_id: the id of the image
3348 name = cstr(name, 'name', opt=True)
3349 image_id = cstr(image_id, 'image_id', opt=True)
3350 snapshot = cstr(snapshot, 'snapshot', opt=True)
3352 if name is not None and image_id is not None:
3353 raise InvalidArgument("only need to specify image name or image id")
3354 elif name is None and image_id is None:
3355 raise InvalidArgument("image name or image id was not specified")
3356 elif name is not None:
3359 self.name = image_id
3360 # Keep around a reference to the ioctx, so it won't get deleted
3363 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3364 char *_name = opt_str(name)
3365 char *_image_id = opt_str(image_id)
3366 char *_snapshot = opt_str(snapshot)
3369 if name is not None:
3370 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
3372 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
3375 if name is not None:
3376 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
3378 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
3380 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
3383 self.name = self.get_name()
3385 def __enter__(self):
3388 def __exit__(self, type_, value, traceback):
3390 Closes the image. See :func:`close`
3395 def __get_completion(self, oncomplete):
3397 Constructs a completion to use with asynchronous operations
3399 :param oncomplete: callback for the completion
3401 :raises: :class:`Error`
3402 :returns: completion object
3405 completion_obj = Completion(self, oncomplete)
3408 rbd_completion_t completion
3409 PyObject* p_completion_obj= <PyObject*>completion_obj
3412 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
3415 raise make_ex(ret, "error getting a completion")
3417 completion_obj.rbd_comp = completion
3418 return completion_obj
3420 def require_not_closed(self):
3422 Checks if the Image is not closed
3424 :raises: :class:`InvalidArgument`
3427 raise InvalidArgument("image is closed")
3431 Release the resources used by this image object.
3433 After this is called, this object should not be used.
3438 ret = rbd_close(self.image)
3440 raise make_ex(ret, 'error while closing image %s' % (
3443 def __dealloc__(self):
3447 return "rbd.Image(ioctx, %r)" % self.name
3449 @requires_not_closed
3450 def resize(self, size, allow_shrink=True):
3452 Change the size of the image, allow shrink.
3454 :param size: the new size of the image
3456 :param allow_shrink: permit shrinking
3457 :type allow_shrink: bool
3459 old_size = self.size()
3460 if old_size == size:
3462 if not allow_shrink and old_size > size:
3463 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
3465 uint64_t _size = size
3466 bint _allow_shrink = allow_shrink
3467 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3469 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
3471 raise make_ex(ret, 'error resizing image %s' % self.name)
3473 @requires_not_closed
3476 Get information about the image. Currently parent pool and
3477 parent name are always -1 and ''.
3479 :returns: dict - contains the following keys:
3481 * ``size`` (int) - the size of the image in bytes
3483 * ``obj_size`` (int) - the size of each object that comprises the
3486 * ``num_objs`` (int) - the number of objects in the image
3488 * ``order`` (int) - log_2(object_size)
3490 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
3493 * ``parent_pool`` (int) - deprecated
3495 * ``parent_name`` (str) - deprecated
3497 See also :meth:`format` and :meth:`features`.
3500 cdef rbd_image_info_t info
3502 ret = rbd_stat(self.image, &info, sizeof(info))
3504 raise make_ex(ret, 'error getting info for image %s' % self.name)
3507 'obj_size' : info.obj_size,
3508 'num_objs' : info.num_objs,
3509 'order' : info.order,
3510 'block_name_prefix' : decode_cstr(info.block_name_prefix),
3511 'parent_pool' : info.parent_pool,
3512 'parent_name' : info.parent_name
3515 @requires_not_closed
3518 Get the RBD image name
3520 :returns: str - image name
3523 int ret = -errno.ERANGE
3525 char *image_name = NULL
3527 while ret == -errno.ERANGE:
3528 image_name = <char *>realloc_chk(image_name, size)
3530 ret = rbd_get_name(self.image, image_name, &size)
3533 raise make_ex(ret, 'error getting name for image %s' % self.name)
3534 return decode_cstr(image_name)
3538 @requires_not_closed
3541 Get the RBD v2 internal image id
3543 :returns: str - image id
3546 int ret = -errno.ERANGE
3548 char *image_id = NULL
3550 while ret == -errno.ERANGE and size <= 4096:
3551 image_id = <char *>realloc_chk(image_id, size)
3553 ret = rbd_get_id(self.image, image_id, size)
3554 if ret == -errno.ERANGE:
3558 raise make_ex(ret, 'error getting id for image %s' % self.name)
3559 return decode_cstr(image_id)
3563 @requires_not_closed
3564 def block_name_prefix(self):
3566 Get the RBD block name prefix
3568 :returns: str - block name prefix
3571 int ret = -errno.ERANGE
3575 while ret == -errno.ERANGE and size <= 4096:
3576 prefix = <char *>realloc_chk(prefix, size)
3578 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3579 if ret == -errno.ERANGE:
3583 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3584 return decode_cstr(prefix)
3588 @requires_not_closed
3589 def data_pool_id(self):
3591 Get the pool id of the pool where the data of this RBD image is stored.
3593 :returns: int - the pool id
3595 return rbd_get_data_pool_id(self.image)
3597 @requires_not_closed
3598 def get_parent_image_spec(self):
3600 Get spec of the cloned image's parent
3602 :returns: dict - contains the following keys:
3603 * ``pool_name`` (str) - parent pool name
3604 * ``pool_namespace`` (str) - parent pool namespace
3605 * ``image_name`` (str) - parent image name
3606 * ``snap_name`` (str) - parent snapshot name
3608 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3611 rbd_linked_image_spec_t parent_spec
3612 rbd_snap_spec_t snap_spec
3614 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3616 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3618 result = {'pool_name': decode_cstr(parent_spec.pool_name),
3619 'pool_namespace': decode_cstr(parent_spec.pool_namespace),
3620 'image_name': decode_cstr(parent_spec.image_name),
3621 'snap_name': decode_cstr(snap_spec.name)}
3623 rbd_linked_image_spec_cleanup(&parent_spec)
3624 rbd_snap_spec_cleanup(&snap_spec)
3627 @requires_not_closed
3628 def parent_info(self):
3630 Deprecated. Use `get_parent_image_spec` instead.
3632 Get information about a cloned image's parent (if any)
3634 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3636 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3638 parent = self.get_parent_image_spec()
3639 return (parent['pool_name'], parent['image_name'], parent['snap_name'])
3641 @requires_not_closed
3642 def parent_id(self):
3644 Get image id of a cloned image's parent (if any)
3646 :returns: str - the parent id
3647 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3650 rbd_linked_image_spec_t parent_spec
3651 rbd_snap_spec_t snap_spec
3653 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3655 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3657 result = decode_cstr(parent_spec.image_id)
3659 rbd_linked_image_spec_cleanup(&parent_spec)
3660 rbd_snap_spec_cleanup(&snap_spec)
3663 @requires_not_closed
3664 def old_format(self):
3666 Find out whether the image uses the old RBD format.
3668 :returns: bool - whether the image uses the old RBD format
3672 ret = rbd_get_old_format(self.image, &old)
3674 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3677 @requires_not_closed
3680 Get the size of the image. If open to a snapshot, returns the
3681 size of that snapshot.
3683 :returns: int - the size of the image in bytes
3685 cdef uint64_t image_size
3687 ret = rbd_get_size(self.image, &image_size)
3689 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3692 @requires_not_closed
3695 Get the features bitmask of the image.
3697 :returns: int - the features bitmask of the image
3699 cdef uint64_t features
3701 ret = rbd_get_features(self.image, &features)
3703 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3706 @requires_not_closed
3707 def update_features(self, features, enabled):
3709 Update the features bitmask of the image by enabling/disabling
3710 a single feature. The feature must support the ability to be
3711 dynamically enabled/disabled.
3713 :param features: feature bitmask to enable/disable
3715 :param enabled: whether to enable/disable the feature
3717 :raises: :class:`InvalidArgument`
3720 uint64_t _features = features
3721 uint8_t _enabled = bool(enabled)
3723 ret = rbd_update_features(self.image, _features, _enabled)
3725 raise make_ex(ret, 'error updating features for image %s' %
3728 @requires_not_closed
3729 def op_features(self):
3731 Get the op features bitmask of the image.
3733 :returns: int - the op features bitmask of the image
3735 cdef uint64_t op_features
3737 ret = rbd_get_op_features(self.image, &op_features)
3739 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3742 @requires_not_closed
3745 Get the number of overlapping bytes between the image and its parent
3746 image. If open to a snapshot, returns the overlap between the snapshot
3747 and the parent image.
3749 :returns: int - the overlap in bytes
3750 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3752 cdef uint64_t overlap
3754 ret = rbd_get_overlap(self.image, &overlap)
3756 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3759 @requires_not_closed
3762 Get the flags bitmask of the image.
3764 :returns: int - the flags bitmask of the image
3768 ret = rbd_get_flags(self.image, &flags)
3770 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3773 @requires_not_closed
3776 Get information about the image's group.
3778 :returns: dict - contains the following keys:
3780 * ``pool`` (int) - id of the group pool
3782 * ``name`` (str) - name of the group
3785 cdef rbd_group_info_t info
3787 ret = rbd_get_group(self.image, &info, sizeof(info))
3789 raise make_ex(ret, 'error getting group for image %s' % self.name)
3792 'name' : decode_cstr(info.name)
3794 rbd_group_info_cleanup(&info, sizeof(info))
3797 @requires_not_closed
3798 def is_exclusive_lock_owner(self):
3800 Get the status of the image exclusive lock.
3802 :returns: bool - true if the image is exclusively locked
3806 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3808 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3811 @requires_not_closed
3812 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3813 stripe_unit=None, stripe_count=None, data_pool=None):
3815 Copy the image to another location.
3817 :param dest_ioctx: determines which pool to copy into
3818 :type dest_ioctx: :class:`rados.Ioctx`
3819 :param dest_name: the name of the copy
3820 :type dest_name: str
3821 :param features: bitmask of features to enable; if set, must include layering
3823 :param order: the image is split into (2**order) byte objects
3825 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3826 :type stripe_unit: int
3827 :param stripe_count: objects to stripe over before looping
3828 :type stripe_count: int
3829 :param data_pool: optional separate pool for data blocks
3830 :type data_pool: str
3831 :raises: :class:`TypeError`
3832 :raises: :class:`InvalidArgument`
3833 :raises: :class:`ImageExists`
3834 :raises: :class:`FunctionNotSupported`
3835 :raises: :class:`ArgumentOutOfRange`
3837 dest_name = cstr(dest_name, 'dest_name')
3838 data_pool = cstr(data_pool, 'data_pool', opt=True)
3840 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3841 char *_dest_name = dest_name
3842 rbd_image_options_t opts
3844 rbd_image_options_create(&opts)
3846 if features is not None:
3847 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3849 if order is not None:
3850 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3852 if stripe_unit is not None:
3853 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3855 if stripe_count is not None:
3856 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3858 if data_pool is not None:
3859 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3862 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3864 rbd_image_options_destroy(opts)
3866 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3868 @requires_not_closed
3869 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3870 stripe_unit=None, stripe_count=None, data_pool=None):
3872 Deep copy the image to another location.
3874 :param dest_ioctx: determines which pool to copy into
3875 :type dest_ioctx: :class:`rados.Ioctx`
3876 :param dest_name: the name of the copy
3877 :type dest_name: str
3878 :param features: bitmask of features to enable; if set, must include layering
3880 :param order: the image is split into (2**order) byte objects
3882 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3883 :type stripe_unit: int
3884 :param stripe_count: objects to stripe over before looping
3885 :type stripe_count: int
3886 :param data_pool: optional separate pool for data blocks
3887 :type data_pool: str
3888 :raises: :class:`TypeError`
3889 :raises: :class:`InvalidArgument`
3890 :raises: :class:`ImageExists`
3891 :raises: :class:`FunctionNotSupported`
3892 :raises: :class:`ArgumentOutOfRange`
3894 dest_name = cstr(dest_name, 'dest_name')
3895 data_pool = cstr(data_pool, 'data_pool', opt=True)
3897 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3898 char *_dest_name = dest_name
3899 rbd_image_options_t opts
3901 rbd_image_options_create(&opts)
3903 if features is not None:
3904 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3906 if order is not None:
3907 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3909 if stripe_unit is not None:
3910 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3912 if stripe_count is not None:
3913 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3915 if data_pool is not None:
3916 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3919 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3921 rbd_image_options_destroy(opts)
3923 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3925 @requires_not_closed
3926 def list_snaps(self):
3928 Iterate over the snapshots of an image.
3930 :returns: :class:`SnapIterator`
3932 return SnapIterator(self)
3934 @requires_not_closed
3935 def create_snap(self, name):
3937 Create a snapshot of the image.
3939 :param name: the name of the snapshot
3941 :raises: :class:`ImageExists`
3943 name = cstr(name, 'name')
3944 cdef char *_name = name
3946 ret = rbd_snap_create(self.image, _name)
3948 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3950 @requires_not_closed
3951 def rename_snap(self, srcname, dstname):
3953 rename a snapshot of the image.
3955 :param srcname: the src name of the snapshot
3957 :param dstname: the dst name of the snapshot
3959 :raises: :class:`ImageExists`
3961 srcname = cstr(srcname, 'srcname')
3962 dstname = cstr(dstname, 'dstname')
3964 char *_srcname = srcname
3965 char *_dstname = dstname
3967 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3969 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3971 @requires_not_closed
3972 def remove_snap(self, name):
3974 Delete a snapshot of the image.
3976 :param name: the name of the snapshot
3978 :raises: :class:`IOError`, :class:`ImageBusy`, :class:`ImageNotFound`
3980 name = cstr(name, 'name')
3981 cdef char *_name = name
3983 ret = rbd_snap_remove(self.image, _name)
3985 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3987 @requires_not_closed
3988 def remove_snap2(self, name, flags):
3990 Delete a snapshot of the image.
3992 :param name: the name of the snapshot
3993 :param flags: the flags for removal
3995 :raises: :class:`IOError`, :class:`ImageBusy`
3997 self.require_not_closed()
3999 name = cstr(name, 'name')
4002 uint32_t _flags = flags
4003 librbd_progress_fn_t prog_cb = &no_op_progress_callback
4005 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
4007 raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
4009 @requires_not_closed
4010 def remove_snap_by_id(self, snap_id):
4012 Delete a snapshot of the image by its id.
4014 :param id: the id of the snapshot
4016 :raises: :class:`IOError`, :class:`ImageBusy`
4019 uint64_t _snap_id = snap_id
4021 ret = rbd_snap_remove_by_id(self.image, _snap_id)
4023 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
4025 @requires_not_closed
4026 def rollback_to_snap(self, name):
4028 Revert the image to its contents at a snapshot. This is a
4029 potentially expensive operation, since it rolls back each
4030 object individually.
4032 :param name: the snapshot to rollback to
4034 :raises: :class:`IOError`
4036 name = cstr(name, 'name')
4037 cdef char *_name = name
4039 ret = rbd_snap_rollback(self.image, _name)
4041 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
4043 @requires_not_closed
4044 def protect_snap(self, name):
4046 Mark a snapshot as protected. This means it can't be deleted
4047 until it is unprotected.
4049 :param name: the snapshot to protect
4051 :raises: :class:`IOError`, :class:`ImageNotFound`
4053 name = cstr(name, 'name')
4054 cdef char *_name = name
4056 ret = rbd_snap_protect(self.image, _name)
4058 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
4060 @requires_not_closed
4061 def unprotect_snap(self, name):
4063 Mark a snapshot unprotected. This allows it to be deleted if
4066 :param name: the snapshot to unprotect
4068 :raises: :class:`IOError`, :class:`ImageNotFound`
4070 name = cstr(name, 'name')
4071 cdef char *_name = name
4073 ret = rbd_snap_unprotect(self.image, _name)
4075 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
4077 @requires_not_closed
4078 def is_protected_snap(self, name):
4080 Find out whether a snapshot is protected from deletion.
4082 :param name: the snapshot to check
4084 :returns: bool - whether the snapshot is protected
4085 :raises: :class:`IOError`, :class:`ImageNotFound`
4087 name = cstr(name, 'name')
4092 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
4094 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
4095 return is_protected == 1
4097 @requires_not_closed
4098 def snap_exists(self, name):
4100 Find out whether a snapshot is exists.
4102 :param name: the snapshot to check
4104 :returns: bool - whether the snapshot is exists
4106 name = cstr(name, 'name')
4109 bint _exists = False
4111 ret = rbd_snap_exists(self.image, _name, &_exists)
4113 raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
4114 return bool(_exists != 0)
4116 @requires_not_closed
4117 def get_snap_limit(self):
4119 Get the snapshot limit for an image.
4121 :returns: int - the snapshot limit for an image
4126 ret = rbd_snap_get_limit(self.image, &limit)
4128 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
4131 @requires_not_closed
4132 def set_snap_limit(self, limit):
4134 Set the snapshot limit for an image.
4136 :param limit: the new limit to set
4139 uint64_t _limit = limit
4141 ret = rbd_snap_set_limit(self.image, _limit)
4143 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
4146 @requires_not_closed
4147 def get_snap_timestamp(self, snap_id):
4149 Get the snapshot timestamp for an image.
4150 :param snap_id: the snapshot id of a snap shot
4151 :returns: datetime - the snapshot timestamp for an image
4155 uint64_t _snap_id = snap_id
4157 ret = rbd_snap_get_timestamp(self.image, _snap_id, ×tamp)
4159 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
4160 return datetime.utcfromtimestamp(timestamp.tv_sec)
4162 @requires_not_closed
4163 def remove_snap_limit(self):
4165 Remove the snapshot limit for an image, essentially setting
4166 the limit to the maximum size allowed by the implementation.
4169 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
4171 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
4174 @requires_not_closed
4175 def set_snap(self, name):
4177 Set the snapshot to read from. Writes will raise ReadOnlyImage
4178 while a snapshot is set. Pass None to unset the snapshot
4179 (reads come from the current image) , and allow writing again.
4181 :param name: the snapshot to read from, or None to unset the snapshot
4182 :type name: str or None
4184 name = cstr(name, 'name', opt=True)
4185 cdef char *_name = opt_str(name)
4187 ret = rbd_snap_set(self.image, _name)
4189 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
4191 @requires_not_closed
4192 def set_snap_by_id(self, snap_id):
4194 Set the snapshot to read from. Writes will raise ReadOnlyImage
4195 while a snapshot is set. Pass None to unset the snapshot
4196 (reads come from the current image) , and allow writing again.
4198 :param snap_id: the snapshot to read from, or None to unset the snapshot
4202 snap_id = _LIBRADOS_SNAP_HEAD
4203 cdef int64_t _snap_id = snap_id
4205 ret = rbd_snap_set_by_id(self.image, _snap_id)
4207 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
4209 @requires_not_closed
4210 def snap_get_name(self, snap_id):
4212 Get snapshot name by id.
4214 :param snap_id: the snapshot id
4216 :returns: str - snapshot name
4217 :raises: :class:`ImageNotFound`
4220 int ret = -errno.ERANGE
4221 int64_t _snap_id = snap_id
4223 char *image_name = NULL
4225 while ret == -errno.ERANGE:
4226 image_name = <char *>realloc_chk(image_name, size)
4228 ret = rbd_snap_get_name(self.image, _snap_id, image_name, &size)
4231 raise make_ex(ret, 'error snap_get_name.')
4232 return decode_cstr(image_name)
4236 @requires_not_closed
4237 def snap_get_id(self, snap_name):
4239 Get snapshot id by name.
4241 :param snap_name: the snapshot name
4242 :type snap_name: str
4243 :returns: int - snapshot id
4244 :raises: :class:`ImageNotFound`
4246 snap_name = cstr(snap_name, 'snap_name')
4248 const char *_snap_name = snap_name
4251 ret = rbd_snap_get_id(self.image, _snap_name, &snap_id)
4253 raise make_ex(ret, 'error snap_get_id.')
4256 @requires_not_closed
4257 def read(self, offset, length, fadvise_flags=0):
4259 Read data from the image. Raises :class:`InvalidArgument` if
4260 part of the range specified is outside the image.
4262 :param offset: the offset to start reading at
4264 :param length: how many bytes to read
4266 :param fadvise_flags: fadvise flags for this read
4267 :type fadvise_flags: int
4268 :returns: str - the data read
4269 :raises: :class:`InvalidArgument`, :class:`IOError`
4272 # This usage of the Python API allows us to construct a string
4273 # that librbd directly reads into, avoiding an extra copy. Although
4274 # strings are normally immutable, this usage is explicitly supported
4275 # for freshly created string objects.
4278 uint64_t _offset = offset
4279 size_t _length = length
4280 int _fadvise_flags = fadvise_flags
4281 PyObject* ret_s = NULL
4282 ret_s = PyBytes_FromStringAndSize(NULL, length)
4284 ret_buf = PyBytes_AsString(ret_s)
4286 ret = rbd_read2(self.image, _offset, _length, ret_buf,
4289 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
4291 if ret != <ssize_t>length:
4292 _PyBytes_Resize(&ret_s, ret)
4294 return <object>ret_s
4296 # We DECREF unconditionally: the cast to object above will have
4297 # INCREFed if necessary. This also takes care of exceptions,
4298 # including if _PyString_Resize fails (that will free the string
4299 # itself and set ret_s to NULL, hence XDECREF).
4300 ref.Py_XDECREF(ret_s)
4302 @requires_not_closed
4303 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
4304 include_parent = True, whole_object = False):
4306 Iterate over the changed extents of an image.
4308 This will call iterate_cb with three arguments:
4310 (offset, length, exists)
4312 where the changed extent starts at offset bytes, continues for
4313 length bytes, and is full of data (if exists is True) or zeroes
4314 (if exists is False).
4316 If from_snapshot is None, it is interpreted as the beginning
4317 of time and this generates all allocated extents.
4319 The end version is whatever is currently selected (via set_snap)
4322 iterate_cb may raise an exception, which will abort the diff and will be
4323 propagated to the caller.
4325 Raises :class:`InvalidArgument` if from_snapshot is after
4326 the currently set snapshot.
4328 Raises :class:`ImageNotFound` if from_snapshot is not the name
4329 of a snapshot of the image.
4331 :param offset: start offset in bytes
4333 :param length: size of region to report on, in bytes
4335 :param from_snapshot: starting snapshot name, or None
4336 :type from_snapshot: str or None
4337 :param iterate_cb: function to call for each extent
4338 :type iterate_cb: function acception arguments for offset,
4340 :param include_parent: True if full history diff should include parent
4341 :type include_parent: bool
4342 :param whole_object: True if diff extents should cover whole object
4343 :type whole_object: bool
4344 :raises: :class:`InvalidArgument`, :class:`IOError`,
4345 :class:`ImageNotFound`
4347 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
4349 char *_from_snapshot = opt_str(from_snapshot)
4350 uint64_t _offset = offset, _length = length
4351 uint8_t _include_parent = include_parent
4352 uint8_t _whole_object = whole_object
4354 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
4355 _length, _include_parent, _whole_object,
4356 &diff_iterate_cb, <void *>iterate_cb)
4358 msg = 'error generating diff from snapshot %s' % from_snapshot
4359 raise make_ex(ret, msg)
4361 @requires_not_closed
4362 def write(self, data, offset, fadvise_flags=0):
4364 Write data to the image. Raises :class:`InvalidArgument` if
4365 part of the write would fall outside the image.
4367 :param data: the data to be written
4369 :param offset: where to start writing data
4371 :param fadvise_flags: fadvise flags for this write
4372 :type fadvise_flags: int
4373 :returns: int - the number of bytes written
4374 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
4375 :class:`InvalidArgument`, :class:`IOError`
4377 if not isinstance(data, bytes):
4378 raise TypeError('data must be a byte string')
4380 uint64_t _offset = offset, length = len(data)
4382 int _fadvise_flags = fadvise_flags
4384 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
4386 if ret == <ssize_t>length:
4389 raise make_ex(ret, "error writing to %s" % self.name)
4390 elif ret < <ssize_t>length:
4391 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
4393 raise LogicError("logic error: rbd_write(%s) \
4394 returned %d, but %d was the maximum number of bytes it could have \
4395 written." % (self.name, ret, length))
4397 @requires_not_closed
4398 def discard(self, offset, length):
4400 Trim the range from the image. It will be logically filled
4403 cdef uint64_t _offset = offset, _length = length
4405 ret = rbd_discard(self.image, _offset, _length)
4407 msg = 'error discarding region %d~%d' % (offset, length)
4408 raise make_ex(ret, msg)
4410 @requires_not_closed
4411 def write_zeroes(self, offset, length, zero_flags = 0):
4413 Zero the range from the image. By default it will attempt to
4414 discard/unmap as much space as possible but any unaligned
4415 extent segments will still be zeroed.
4418 uint64_t _offset = offset, _length = length
4419 int _zero_flags = zero_flags
4421 ret = rbd_write_zeroes(self.image, _offset, _length,
4424 msg = 'error zeroing region %d~%d' % (offset, length)
4425 raise make_ex(ret, msg)
4427 @requires_not_closed
4430 Block until all writes are fully flushed if caching is enabled.
4433 ret = rbd_flush(self.image)
4435 raise make_ex(ret, 'error flushing image')
4437 @requires_not_closed
4438 def invalidate_cache(self):
4440 Drop any cached data for the image.
4443 ret = rbd_invalidate_cache(self.image)
4445 raise make_ex(ret, 'error invalidating cache')
4447 @requires_not_closed
4448 def stripe_unit(self):
4450 Return the stripe unit used for the image.
4452 cdef uint64_t stripe_unit
4454 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
4456 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
4459 @requires_not_closed
4460 def stripe_count(self):
4462 Return the stripe count used for the image.
4464 cdef uint64_t stripe_count
4466 ret = rbd_get_stripe_count(self.image, &stripe_count)
4468 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
4471 @requires_not_closed
4472 def create_timestamp(self):
4474 Return the create timestamp for the image.
4479 ret = rbd_get_create_timestamp(self.image, ×tamp)
4481 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
4482 return datetime.utcfromtimestamp(timestamp.tv_sec)
4484 @requires_not_closed
4485 def access_timestamp(self):
4487 Return the access timestamp for the image.
4492 ret = rbd_get_access_timestamp(self.image, ×tamp)
4494 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
4495 return datetime.fromtimestamp(timestamp.tv_sec)
4497 @requires_not_closed
4498 def modify_timestamp(self):
4500 Return the modify timestamp for the image.
4505 ret = rbd_get_modify_timestamp(self.image, ×tamp)
4507 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
4508 return datetime.fromtimestamp(timestamp.tv_sec)
4510 @requires_not_closed
4511 def flatten(self, on_progress=None):
4513 Flatten clone image (copy all blocks from parent to child)
4514 :param on_progress: optional progress callback function
4515 :type on_progress: callback function
4518 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
4519 void *_prog_arg = NULL
4521 _prog_cb = &progress_callback
4522 _prog_arg = <void *>on_progress
4524 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
4526 raise make_ex(ret, "error flattening %s" % self.name)
4528 @requires_not_closed
4529 def sparsify(self, sparse_size):
4531 Reclaim space for zeroed image extents
4534 size_t _sparse_size = sparse_size
4536 ret = rbd_sparsify(self.image, _sparse_size)
4538 raise make_ex(ret, "error sparsifying %s" % self.name)
4540 @requires_not_closed
4541 def rebuild_object_map(self):
4543 Rebuild the object map for the image HEAD or currently set snapshot
4545 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
4547 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
4549 raise make_ex(ret, "error rebuilding object map %s" % self.name)
4551 @requires_not_closed
4552 def list_children(self):
4554 List children of the currently set snapshot (set via set_snap()).
4556 :returns: list - a list of (pool name, image name) tuples
4559 rbd_linked_image_spec_t *children = NULL
4560 size_t num_children = 10
4564 children = <rbd_linked_image_spec_t*>realloc_chk(
4565 children, num_children * sizeof(rbd_linked_image_spec_t))
4567 ret = rbd_list_children3(self.image, children,
4571 elif ret != -errno.ERANGE:
4572 raise make_ex(ret, 'error listing children.')
4574 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
4575 in children[:num_children] if not x.trash]
4578 rbd_linked_image_spec_list_cleanup(children, num_children)
4581 @requires_not_closed
4582 def list_children2(self):
4584 Iterate over the children of the image or its snapshot.
4586 :returns: :class:`ChildIterator`
4588 return ChildIterator(self)
4590 @requires_not_closed
4591 def list_descendants(self):
4593 Iterate over the descendants of the image.
4595 :returns: :class:`ChildIterator`
4597 return ChildIterator(self, True)
4599 @requires_not_closed
4600 def list_lockers(self):
4602 List clients that have locked the image and information
4605 :returns: dict - contains the following keys:
4607 * ``tag`` - the tag associated with the lock (every
4608 additional locker must use the same tag)
4609 * ``exclusive`` - boolean indicating whether the
4610 lock is exclusive or shared
4611 * ``lockers`` - a list of (client, cookie, address)
4615 size_t clients_size = 512, cookies_size = 512
4616 size_t addrs_size = 512, tag_size = 512
4618 char *c_clients = NULL
4619 char *c_cookies = NULL
4620 char *c_addrs = NULL
4625 c_clients = <char *>realloc_chk(c_clients, clients_size)
4626 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
4627 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
4628 c_tag = <char *>realloc_chk(c_tag, tag_size)
4630 ret = rbd_list_lockers(self.image, &exclusive,
4632 c_clients, &clients_size,
4633 c_cookies, &cookies_size,
4634 c_addrs, &addrs_size)
4637 elif ret != -errno.ERANGE:
4638 raise make_ex(ret, 'error listing images')
4641 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
4642 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
4643 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
4645 'tag' : decode_cstr(c_tag),
4646 'exclusive' : exclusive == 1,
4647 'lockers' : list(zip(clients, cookies, addrs)),
4655 @requires_not_closed
4656 def lock_acquire(self, lock_mode):
4658 Acquire a managed lock on the image.
4660 :param lock_mode: lock mode to set
4661 :type lock_mode: int
4662 :raises: :class:`ImageBusy` if the lock could not be acquired
4665 rbd_lock_mode_t _lock_mode = lock_mode
4667 ret = rbd_lock_acquire(self.image, _lock_mode)
4669 raise make_ex(ret, 'error acquiring lock on image')
4671 @requires_not_closed
4672 def lock_release(self):
4674 Release a managed lock on the image that was previously acquired.
4677 ret = rbd_lock_release(self.image)
4679 raise make_ex(ret, 'error releasing lock on image')
4681 @requires_not_closed
4682 def lock_get_owners(self):
4684 Iterate over the lock owners of an image.
4686 :returns: :class:`LockOwnerIterator`
4688 return LockOwnerIterator(self)
4690 @requires_not_closed
4691 def lock_break(self, lock_mode, lock_owner):
4693 Break the image lock held by a another client.
4695 :param lock_owner: the owner of the lock to break
4696 :type lock_owner: str
4698 lock_owner = cstr(lock_owner, 'lock_owner')
4700 rbd_lock_mode_t _lock_mode = lock_mode
4701 char *_lock_owner = lock_owner
4703 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
4705 raise make_ex(ret, 'error breaking lock on image')
4707 @requires_not_closed
4708 def lock_exclusive(self, cookie):
4710 Take an exclusive lock on the image.
4712 :raises: :class:`ImageBusy` if a different client or cookie locked it
4713 :class:`ImageExists` if the same client and cookie locked it
4715 cookie = cstr(cookie, 'cookie')
4716 cdef char *_cookie = cookie
4718 ret = rbd_lock_exclusive(self.image, _cookie)
4720 raise make_ex(ret, 'error acquiring exclusive lock on image')
4722 @requires_not_closed
4723 def lock_shared(self, cookie, tag):
4725 Take a shared lock on the image. The tag must match
4726 that of the existing lockers, if any.
4728 :raises: :class:`ImageBusy` if a different client or cookie locked it
4729 :class:`ImageExists` if the same client and cookie locked it
4731 cookie = cstr(cookie, 'cookie')
4732 tag = cstr(tag, 'tag')
4734 char *_cookie = cookie
4737 ret = rbd_lock_shared(self.image, _cookie, _tag)
4739 raise make_ex(ret, 'error acquiring shared lock on image')
4741 @requires_not_closed
4742 def unlock(self, cookie):
4744 Release a lock on the image that was locked by this rados client.
4746 cookie = cstr(cookie, 'cookie')
4747 cdef char *_cookie = cookie
4749 ret = rbd_unlock(self.image, _cookie)
4751 raise make_ex(ret, 'error unlocking image')
4753 @requires_not_closed
4754 def break_lock(self, client, cookie):
4756 Release a lock held by another rados client.
4758 client = cstr(client, 'client')
4759 cookie = cstr(cookie, 'cookie')
4761 char *_client = client
4762 char *_cookie = cookie
4764 ret = rbd_break_lock(self.image, _client, _cookie)
4766 raise make_ex(ret, 'error unlocking image')
4768 @requires_not_closed
4769 def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
4771 Enable mirroring for the image.
4773 cdef rbd_mirror_image_mode_t c_mode = mode
4775 ret = rbd_mirror_image_enable2(self.image, c_mode)
4777 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4779 @requires_not_closed
4780 def mirror_image_disable(self, force):
4782 Disable mirroring for the image.
4784 :param force: force disabling
4787 cdef bint c_force = force
4789 ret = rbd_mirror_image_disable(self.image, c_force)
4791 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4793 @requires_not_closed
4794 def mirror_image_promote(self, force):
4796 Promote the image to primary for mirroring.
4798 :param force: force promoting
4801 cdef bint c_force = force
4803 ret = rbd_mirror_image_promote(self.image, c_force)
4805 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4807 @requires_not_closed
4808 def mirror_image_demote(self):
4810 Demote the image to secondary for mirroring.
4813 ret = rbd_mirror_image_demote(self.image)
4815 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4817 @requires_not_closed
4818 def mirror_image_resync(self):
4820 Flag the image to resync.
4823 ret = rbd_mirror_image_resync(self.image)
4825 raise make_ex(ret, 'error to resync image %s' % self.name)
4827 @requires_not_closed
4828 def mirror_image_create_snapshot(self):
4830 Create mirror snapshot.
4832 :param force: ignore mirror snapshot limit
4834 :returns: int - the snapshot Id
4839 ret = rbd_mirror_image_create_snapshot(self.image, &snap_id)
4841 raise make_ex(ret, 'error creating mirror snapshot for image %s' %
4845 @requires_not_closed
4846 def mirror_image_get_info(self):
4848 Get mirror info for the image.
4850 :returns: dict - contains the following keys:
4852 * ``global_id`` (str) - image global id
4854 * ``state`` (int) - mirror state
4856 * ``primary`` (bool) - is image primary
4858 cdef rbd_mirror_image_info_t c_info
4860 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4862 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4864 'global_id' : decode_cstr(c_info.global_id),
4865 'state' : int(c_info.state),
4866 'primary' : c_info.primary,
4868 rbd_mirror_image_get_info_cleanup(&c_info)
4871 @requires_not_closed
4872 def mirror_image_get_mode(self):
4874 Get mirror mode for the image.
4876 :returns: int - mirror mode
4878 cdef rbd_mirror_image_mode_t c_mode
4880 ret = rbd_mirror_image_get_mode(self.image, &c_mode)
4882 raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
4885 @requires_not_closed
4886 def mirror_image_get_status(self):
4888 Get mirror status for the image.
4890 :returns: dict - contains the following keys:
4892 * ``name`` (str) - mirror image name
4894 * ``id`` (str) - mirror image id
4896 * ``info`` (dict) - mirror image info
4898 * ``state`` (int) - status mirror state
4900 * ``description`` (str) - status description
4902 * ``last_update`` (datetime) - last status update time
4904 * ``up`` (bool) - is mirroring agent up
4906 * ``remote_statuses`` (array) -
4908 * ``mirror_uuid`` (str) - remote mirror uuid
4910 * ``state`` (int) - status mirror state
4912 * ``description`` (str) - status description
4914 * ``last_update`` (datetime) - last status update time
4916 * ``up`` (bool) - is mirroring agent up
4919 rbd_mirror_image_site_status_t *s_status
4920 rbd_mirror_image_global_status_t c_status
4923 ret = rbd_mirror_image_get_global_status(self.image, &c_status,
4926 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4930 for i in range(c_status.site_statuses_count):
4931 s_status = &c_status.site_statuses[i]
4933 'state' : s_status.state,
4934 'description' : decode_cstr(s_status.description),
4935 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
4938 mirror_uuid = decode_cstr(s_status.mirror_uuid)
4939 if mirror_uuid == '':
4940 local_status = site_status
4942 site_statuses['mirror_uuid'] = mirror_uuid
4943 site_statuses += site_status
4945 'name': decode_cstr(c_status.name),
4948 'global_id' : decode_cstr(c_status.info.global_id),
4949 'state' : int(c_status.info.state),
4950 'primary' : c_status.info.primary,
4952 'remote_statuses': site_statuses,
4955 status.update(local_status)
4957 rbd_mirror_image_global_status_cleanup(&c_status)
4960 @requires_not_closed
4961 def mirror_image_get_instance_id(self):
4963 Get mirror instance id for the image.
4965 :returns: str - instance id
4968 int ret = -errno.ERANGE
4970 char *instance_id = NULL
4972 while ret == -errno.ERANGE and size <= 4096:
4973 instance_id = <char *>realloc_chk(instance_id, size)
4975 ret = rbd_mirror_image_get_instance_id(self.image,
4979 'error getting mirror instance id for image %s' %
4981 return decode_cstr(instance_id)
4985 @requires_not_closed
4986 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4988 Asynchronously read data from the image
4990 Raises :class:`InvalidArgument` if part of the range specified is
4993 oncomplete will be called with the returned read value as
4994 well as the completion:
4996 oncomplete(completion, data_read)
4998 :param offset: the offset to start reading at
5000 :param length: how many bytes to read
5002 :param oncomplete: what to do when the read is complete
5003 :type oncomplete: completion
5004 :param fadvise_flags: fadvise flags for this read
5005 :type fadvise_flags: int
5006 :returns: :class:`Completion` - the completion object
5007 :raises: :class:`InvalidArgument`, :class:`IOError`
5011 uint64_t _offset = offset
5012 size_t _length = length
5013 int _fadvise_flags = fadvise_flags
5014 Completion completion
5016 def oncomplete_(completion_v):
5017 cdef Completion _completion_v = completion_v
5018 return_value = _completion_v.get_return_value()
5019 if return_value > 0 and return_value != length:
5020 _PyBytes_Resize(&_completion_v.buf, return_value)
5021 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
5023 completion = self.__get_completion(oncomplete_)
5024 completion.buf = PyBytes_FromStringAndSize(NULL, length)
5025 ret_buf = PyBytes_AsString(completion.buf)
5027 completion.__persist()
5029 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
5030 completion.rbd_comp, _fadvise_flags)
5032 raise make_ex(ret, 'error reading %s %ld~%ld' %
5033 (self.name, offset, length))
5035 completion.__unpersist()
5040 @requires_not_closed
5041 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
5043 Asynchronously write data to the image
5045 Raises :class:`InvalidArgument` if part of the write would fall outside
5048 oncomplete will be called with the completion:
5050 oncomplete(completion)
5052 :param data: the data to be written
5054 :param offset: the offset to start writing at
5056 :param oncomplete: what to do when the write is complete
5057 :type oncomplete: completion
5058 :param fadvise_flags: fadvise flags for this write
5059 :type fadvise_flags: int
5060 :returns: :class:`Completion` - the completion object
5061 :raises: :class:`InvalidArgument`, :class:`IOError`
5064 uint64_t _offset = offset
5066 size_t _length = len(data)
5067 int _fadvise_flags = fadvise_flags
5068 Completion completion
5070 completion = self.__get_completion(oncomplete)
5072 completion.__persist()
5074 ret = rbd_aio_write2(self.image, _offset, _length, _data,
5075 completion.rbd_comp, _fadvise_flags)
5077 raise make_ex(ret, 'error writing %s %ld~%ld' %
5078 (self.name, offset, _length))
5080 completion.__unpersist()
5085 @requires_not_closed
5086 def aio_discard(self, offset, length, oncomplete):
5088 Asynchronously trim the range from the image. It will be logically
5092 uint64_t _offset = offset
5093 size_t _length = length
5094 Completion completion
5096 completion = self.__get_completion(oncomplete)
5098 completion.__persist()
5100 ret = rbd_aio_discard(self.image, _offset, _length,
5101 completion.rbd_comp)
5103 raise make_ex(ret, 'error discarding %s %ld~%ld' %
5104 (self.name, offset, _length))
5106 completion.__unpersist()
5111 @requires_not_closed
5112 def aio_write_zeroes(self, offset, length, oncomplete, zero_flags = 0):
5114 Asynchronously Zero the range from the image. By default it will attempt
5115 to discard/unmap as much space as possible but any unaligned extent
5116 segments will still be zeroed.
5119 uint64_t _offset = offset
5120 size_t _length = length
5121 int _zero_flags = zero_flags
5122 Completion completion
5124 completion = self.__get_completion(oncomplete)
5126 completion.__persist()
5128 ret = rbd_aio_write_zeroes(self.image, _offset, _length,
5129 completion.rbd_comp, _zero_flags, 0)
5131 raise make_ex(ret, 'error zeroing %s %ld~%ld' %
5132 (self.name, offset, length))
5134 completion.__unpersist()
5139 @requires_not_closed
5140 def aio_flush(self, oncomplete):
5142 Asynchronously wait until all writes are fully flushed if caching is
5145 cdef Completion completion = self.__get_completion(oncomplete)
5147 completion.__persist()
5149 ret = rbd_aio_flush(self.image, completion.rbd_comp)
5151 raise make_ex(ret, 'error flushing')
5153 completion.__unpersist()
5158 @requires_not_closed
5159 def metadata_get(self, key):
5161 Get image metadata for the given key.
5163 :param key: metadata key
5165 :returns: str - metadata value
5167 key = cstr(key, 'key')
5175 value = <char *>realloc_chk(value, size)
5177 ret = rbd_metadata_get(self.image, _key, value, &size)
5178 if ret != -errno.ERANGE:
5180 if ret == -errno.ENOENT:
5181 raise KeyError('no metadata %s for image %s' % (key, self.name))
5183 raise make_ex(ret, 'error getting metadata %s for image %s' %
5185 return decode_cstr(value)
5189 @requires_not_closed
5190 def metadata_set(self, key, value):
5192 Set image metadata for the given key.
5194 :param key: metadata key
5196 :param value: metadata value
5199 key = cstr(key, 'key')
5200 value = cstr(value, 'value')
5203 char *_value = value
5205 ret = rbd_metadata_set(self.image, _key, _value)
5208 raise make_ex(ret, 'error setting metadata %s for image %s' %
5211 @requires_not_closed
5212 def metadata_remove(self, key):
5214 Remove image metadata for the given key.
5216 :param key: metadata key
5219 key = cstr(key, 'key')
5223 ret = rbd_metadata_remove(self.image, _key)
5225 if ret == -errno.ENOENT:
5226 raise KeyError('no metadata %s for image %s' % (key, self.name))
5228 raise make_ex(ret, 'error removing metadata %s for image %s' %
5231 @requires_not_closed
5232 def metadata_list(self):
5234 List image metadata.
5236 :returns: :class:`MetadataIterator`
5238 return MetadataIterator(self)
5240 @requires_not_closed
5241 def watchers_list(self):
5243 List image watchers.
5245 :returns: :class:`WatcherIterator`
5247 return WatcherIterator(self)
5249 @requires_not_closed
5250 def config_list(self):
5252 List image-level config overrides.
5254 :returns: :class:`ConfigImageIterator`
5256 return ConfigImageIterator(self)
5258 @requires_not_closed
5259 def config_set(self, key, value):
5261 Set an image-level configuration override.
5268 conf_key = 'conf_' + key
5269 conf_key = cstr(conf_key, 'key')
5270 value = cstr(value, 'value')
5272 char *_key = conf_key
5273 char *_value = value
5275 ret = rbd_metadata_set(self.image, _key, _value)
5278 raise make_ex(ret, 'error setting config %s for image %s' %
5281 @requires_not_closed
5282 def config_get(self, key):
5284 Get an image-level configuration override.
5288 :returns: str - value
5290 conf_key = 'conf_' + key
5291 conf_key = cstr(conf_key, 'key')
5293 char *_key = conf_key
5299 value = <char *>realloc_chk(value, size)
5301 ret = rbd_metadata_get(self.image, _key, value, &size)
5302 if ret != -errno.ERANGE:
5304 if ret == -errno.ENOENT:
5305 raise KeyError('no config %s for image %s' % (key, self.name))
5307 raise make_ex(ret, 'error getting config %s for image %s' %
5309 return decode_cstr(value)
5313 @requires_not_closed
5314 def config_remove(self, key):
5316 Remove an image-level configuration override.
5321 conf_key = 'conf_' + key
5322 conf_key = cstr(conf_key, 'key')
5324 char *_key = conf_key
5326 ret = rbd_metadata_remove(self.image, _key)
5328 if ret == -errno.ENOENT:
5329 raise KeyError('no config %s for image %s' % (key, self.name))
5331 raise make_ex(ret, 'error removing config %s for image %s' %
5334 @requires_not_closed
5335 def snap_get_namespace_type(self, snap_id):
5337 Get the snapshot namespace type.
5338 :param snap_id: the snapshot id of a snap shot
5342 rbd_snap_namespace_type_t namespace_type
5343 uint64_t _snap_id = snap_id
5345 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
5347 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
5349 return namespace_type
5351 @requires_not_closed
5352 def snap_get_group_namespace(self, snap_id):
5354 get the group namespace details.
5355 :param snap_id: the snapshot id of the group snapshot
5357 :returns: dict - contains the following keys:
5359 * ``pool`` (int) - pool id
5361 * ``name`` (str) - group name
5363 * ``snap_name`` (str) - group snap name
5366 rbd_snap_group_namespace_t group_namespace
5367 uint64_t _snap_id = snap_id
5369 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
5371 sizeof(rbd_snap_group_namespace_t))
5373 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
5376 'pool' : group_namespace.group_pool,
5377 'name' : decode_cstr(group_namespace.group_name),
5378 'snap_name' : decode_cstr(group_namespace.group_snap_name)
5380 rbd_snap_group_namespace_cleanup(&group_namespace,
5381 sizeof(rbd_snap_group_namespace_t))
5384 @requires_not_closed
5385 def snap_get_trash_namespace(self, snap_id):
5387 get the trash namespace details.
5388 :param snap_id: the snapshot id of the trash snapshot
5390 :returns: dict - contains the following keys:
5392 * ``original_name`` (str) - original snap name
5395 uint64_t _snap_id = snap_id
5400 _name = <char*>realloc_chk(_name, _size);
5402 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
5406 elif ret != -errno.ERANGE:
5407 raise make_ex(ret, 'error getting snapshot trash '
5408 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
5410 'original_name' : decode_cstr(_name)
5415 @requires_not_closed
5416 def snap_get_mirror_namespace(self, snap_id):
5418 get the mirror namespace details.
5419 :param snap_id: the snapshot id of the mirror snapshot
5421 :returns: dict - contains the following keys:
5423 * ``state`` (int) - the snapshot state
5425 * ``mirror_peer_uuids`` (list) - mirror peer uuids
5427 * ``complete`` (bool) - True if snapshot is complete
5429 * ``primary_mirror_uuid`` (str) - primary mirror uuid
5431 * ``primary_snap_id`` (int) - primary snapshot Id
5433 * ``last_copied_object_number`` (int) - last copied object number
5436 rbd_snap_mirror_namespace_t sn
5437 uint64_t _snap_id = snap_id
5439 ret = rbd_snap_get_mirror_namespace(
5440 self.image, _snap_id, &sn,
5441 sizeof(rbd_snap_mirror_namespace_t))
5443 raise make_ex(ret, 'error getting snapshot mirror '
5444 'namespace for image: %s, snap_id: %d' %
5445 (self.name, snap_id))
5447 cdef char *p = sn.mirror_peer_uuids
5448 for i in range(sn.mirror_peer_uuids_count):
5449 uuid = decode_cstr(p)
5454 'mirror_peer_uuids' : uuids,
5455 'complete' : sn.complete,
5456 'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
5457 'primary_snap_id' : sn.primary_snap_id,
5458 'last_copied_object_number' : sn.last_copied_object_number,
5460 rbd_snap_mirror_namespace_cleanup(
5461 &sn, sizeof(rbd_snap_mirror_namespace_t))
5465 cdef class ImageIterator(object):
5467 Iterator over RBD images in a pool
5469 Yields a dictionary containing information about the images
5473 * ``id`` (str) - image id
5475 * ``name`` (str) - image name
5477 cdef rados_ioctx_t ioctx
5478 cdef rbd_image_spec_t *images
5479 cdef size_t num_images
5481 def __init__(self, ioctx):
5482 self.ioctx = convert_ioctx(ioctx)
5484 self.num_images = 1024
5486 self.images = <rbd_image_spec_t*>realloc_chk(
5487 self.images, self.num_images * sizeof(rbd_image_spec_t))
5489 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
5492 elif ret == -errno.ERANGE:
5493 self.num_images *= 2
5495 raise make_ex(ret, 'error listing images.')
5498 for i in range(self.num_images):
5500 'id' : decode_cstr(self.images[i].id),
5501 'name' : decode_cstr(self.images[i].name)
5504 def __dealloc__(self):
5506 rbd_image_spec_list_cleanup(self.images, self.num_images)
5510 cdef class LockOwnerIterator(object):
5512 Iterator over managed lock owners for an image
5514 Yields a dictionary containing information about the image's lock
5518 * ``mode`` (int) - active lock mode
5520 * ``owner`` (str) - lock owner name
5524 rbd_lock_mode_t lock_mode
5526 size_t num_lock_owners
5529 def __init__(self, Image image):
5530 image.require_not_closed()
5533 self.lock_owners = NULL
5534 self.num_lock_owners = 8
5536 self.lock_owners = <char**>realloc_chk(self.lock_owners,
5537 self.num_lock_owners *
5540 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
5542 &self.num_lock_owners)
5545 elif ret == -errno.ENOENT:
5546 self.num_lock_owners = 0
5548 elif ret != -errno.ERANGE:
5549 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
5552 for i in range(self.num_lock_owners):
5554 'mode' : int(self.lock_mode),
5555 'owner' : decode_cstr(self.lock_owners[i]),
5558 def __dealloc__(self):
5559 if self.lock_owners:
5560 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
5561 free(self.lock_owners)
5563 cdef class MetadataIterator(object):
5565 Iterator over metadata list for an image.
5567 Yields ``(key, value)`` tuple.
5569 * ``key`` (str) - metadata key
5570 * ``value`` (str) - metadata value
5580 def __init__(self, Image image):
5581 image.require_not_closed()
5584 self.c_image = image.image
5585 self.last_read = strdup("")
5587 self.get_next_chunk()
5590 while len(self.next_chunk) > 0:
5591 for pair in self.next_chunk:
5593 if len(self.next_chunk) < self.max_read:
5595 self.get_next_chunk()
5597 def __dealloc__(self):
5599 free(self.last_read)
5601 def get_next_chunk(self):
5602 self.image.require_not_closed()
5606 size_t keys_size = 4096
5608 size_t vals_size = 4096
5611 c_keys = <char *>realloc_chk(c_keys, keys_size)
5612 c_vals = <char *>realloc_chk(c_vals, vals_size)
5614 ret = rbd_metadata_list(self.c_image, self.last_read,
5615 self.max_read, c_keys, &keys_size,
5619 elif ret != -errno.ERANGE:
5620 raise make_ex(ret, 'error listing metadata for image %s' %
5622 keys = [decode_cstr(key) for key in
5623 c_keys[:keys_size].split(b'\0') if key]
5624 vals = [decode_cstr(val) for val in
5625 c_vals[:vals_size].split(b'\0') if val]
5627 last_read = cstr(keys[-1], 'last_read')
5628 free(self.last_read)
5629 self.last_read = strdup(last_read)
5630 self.next_chunk = list(zip(keys, vals))
5635 cdef class SnapIterator(object):
5637 Iterator over snapshot info for an image.
5639 Yields a dictionary containing information about a snapshot.
5643 * ``id`` (int) - numeric identifier of the snapshot
5645 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
5647 * ``name`` (str) - name of the snapshot
5649 * ``namespace`` (int) - enum for snap namespace
5651 * ``group`` (dict) - optional for group namespace snapshots
5653 * ``trash`` (dict) - optional for trash namespace snapshots
5655 * ``mirror`` (dict) - optional for mirror namespace snapshots
5658 cdef rbd_snap_info_t *snaps
5662 def __init__(self, Image image):
5663 image.require_not_closed()
5669 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
5671 sizeof(rbd_snap_info_t))
5673 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
5675 self.num_snaps = ret
5677 elif ret != -errno.ERANGE:
5678 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
5681 for i in range(self.num_snaps):
5683 'id' : self.snaps[i].id,
5684 'size' : self.snaps[i].size,
5685 'name' : decode_cstr(self.snaps[i].name),
5686 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
5688 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
5690 group = self.image.snap_get_group_namespace(self.snaps[i].id)
5694 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
5696 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
5700 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR:
5702 mirror = self.image.snap_get_mirror_namespace(
5706 s['mirror'] = mirror
5709 def __dealloc__(self):
5711 rbd_snap_list_end(self.snaps)
5714 cdef class TrashIterator(object):
5716 Iterator over trash entries.
5718 Yields a dictionary containing trash info of an image.
5722 * `id` (str) - image id
5724 * `name` (str) - image name
5726 * `source` (str) - source of deletion
5728 * `deletion_time` (datetime) - time of deletion
5730 * `deferment_end_time` (datetime) - time that an image is allowed to be
5737 rbd_trash_image_info_t *entries
5739 def __init__(self, ioctx):
5740 self.ioctx = convert_ioctx(ioctx)
5741 self.num_entries = 1024
5744 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
5746 sizeof(rbd_trash_image_info_t))
5748 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
5750 self.num_entries = ret
5752 elif ret != -errno.ERANGE:
5753 raise make_ex(ret, 'error listing trash entries')
5755 __source_string = ['USER', 'MIRRORING']
5758 for i in range(self.num_entries):
5760 'id' : decode_cstr(self.entries[i].id),
5761 'name' : decode_cstr(self.entries[i].name),
5762 'source' : TrashIterator.__source_string[self.entries[i].source],
5763 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
5764 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
5767 def __dealloc__(self):
5768 rbd_trash_list_cleanup(self.entries, self.num_entries)
5772 cdef class ChildIterator(object):
5774 Iterator over child info for the image or its snapshot.
5776 Yields a dictionary containing information about a child.
5780 * ``pool`` (str) - name of the pool
5782 * ``pool_namespace`` (str) - namespace of the pool
5784 * ``image`` (str) - name of the child
5786 * ``id`` (str) - id of the child
5788 * ``trash`` (bool) - True if child is in trash bin
5791 cdef rbd_linked_image_spec_t *children
5792 cdef size_t num_children
5795 def __init__(self, Image image, descendants=False):
5796 image.require_not_closed()
5799 self.children = NULL
5800 self.num_children = 10
5802 self.children = <rbd_linked_image_spec_t*>realloc_chk(
5803 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
5806 ret = rbd_list_descendants(image.image, self.children,
5810 ret = rbd_list_children3(image.image, self.children,
5814 elif ret != -errno.ERANGE:
5815 raise make_ex(ret, 'error listing children.')
5818 for i in range(self.num_children):
5820 'pool' : decode_cstr(self.children[i].pool_name),
5821 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
5822 'image' : decode_cstr(self.children[i].image_name),
5823 'id' : decode_cstr(self.children[i].image_id),
5824 'trash' : self.children[i].trash
5827 def __dealloc__(self):
5829 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
5832 cdef class WatcherIterator(object):
5834 Iterator over watchers of an image.
5836 Yields a dictionary containing information about a watcher.
5840 * ``addr`` (str) - address of the watcher
5842 * ``id`` (int) - id of the watcher
5844 * ``cookie`` (int) - the watcher's cookie
5847 cdef rbd_image_watcher_t *watchers
5848 cdef size_t num_watchers
5851 def __init__(self, Image image):
5852 image.require_not_closed()
5855 self.watchers = NULL
5856 self.num_watchers = 10
5858 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
5860 sizeof(rbd_image_watcher_t))
5862 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
5865 elif ret != -errno.ERANGE:
5866 raise make_ex(ret, 'error listing watchers.')
5869 for i in range(self.num_watchers):
5871 'addr' : decode_cstr(self.watchers[i].addr),
5872 'id' : self.watchers[i].id,
5873 'cookie' : self.watchers[i].cookie
5876 def __dealloc__(self):
5878 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
5881 cdef class ConfigImageIterator(object):
5883 Iterator over image-level overrides for an image.
5885 Yields a dictionary containing information about an override.
5889 * ``name`` (str) - override name
5891 * ``value`` (str) - override value
5893 * ``source`` (str) - override source
5897 rbd_config_option_t *options
5900 def __init__(self, Image image):
5901 image.require_not_closed()
5904 self.num_options = 32
5906 self.options = <rbd_config_option_t *>realloc_chk(
5907 self.options, self.num_options * sizeof(rbd_config_option_t))
5909 ret = rbd_config_image_list(image.image, self.options,
5912 if ret == -errno.ERANGE:
5914 self.num_options = 0
5915 raise make_ex(ret, 'error listing config options')
5919 for i in range(self.num_options):
5921 'name' : decode_cstr(self.options[i].name),
5922 'value' : decode_cstr(self.options[i].value),
5923 'source' : self.options[i].source,
5926 def __dealloc__(self):
5928 rbd_config_image_list_cleanup(self.options, self.num_options)
5931 cdef class GroupImageIterator(object):
5933 Iterator over image info for a group.
5935 Yields a dictionary containing information about an image.
5939 * ``name`` (str) - name of the image
5941 * ``pool`` (int) - id of the pool this image belongs to
5943 * ``state`` (int) - state of the image
5946 cdef rbd_group_image_info_t *images
5947 cdef size_t num_images
5950 def __init__(self, Group group):
5953 self.num_images = 10
5955 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
5957 sizeof(rbd_group_image_info_t))
5959 ret = rbd_group_image_list(group._ioctx, group._name,
5961 sizeof(rbd_group_image_info_t),
5966 elif ret != -errno.ERANGE:
5967 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
5970 for i in range(self.num_images):
5972 'name' : decode_cstr(self.images[i].name),
5973 'pool' : self.images[i].pool,
5974 'state' : self.images[i].state,
5977 def __dealloc__(self):
5979 rbd_group_image_list_cleanup(self.images,
5980 sizeof(rbd_group_image_info_t),
5984 cdef class GroupSnapIterator(object):
5986 Iterator over snaps specs for a group.
5988 Yields a dictionary containing information about a snapshot.
5992 * ``name`` (str) - name of the snapshot
5994 * ``state`` (int) - state of the snapshot
5997 cdef rbd_group_snap_info_t *snaps
5998 cdef size_t num_snaps
6001 def __init__(self, Group group):
6006 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
6008 sizeof(rbd_group_snap_info_t))
6010 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
6011 sizeof(rbd_group_snap_info_t),
6016 elif ret != -errno.ERANGE:
6017 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
6020 for i in range(self.num_snaps):
6022 'name' : decode_cstr(self.snaps[i].name),
6023 'state' : self.snaps[i].state,
6026 def __dealloc__(self):
6028 rbd_group_snap_list_cleanup(self.snaps,
6029 sizeof(rbd_group_snap_info_t),