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"
276 _RBD_IMAGE_MIGRATION_STATE_ABORTING "RBD_IMAGE_MIGRATION_STATE_ABORTING"
278 ctypedef struct rbd_image_migration_status_t:
279 int64_t source_pool_id
280 char *source_pool_namespace
281 char *source_image_name
282 char *source_image_id
284 char *dest_pool_namespace
285 char *dest_image_name
287 rbd_image_migration_state_t state
288 char *state_description
290 ctypedef enum rbd_config_source_t:
291 _RBD_CONFIG_SOURCE_CONFIG "RBD_CONFIG_SOURCE_CONFIG"
292 _RBD_CONFIG_SOURCE_POOL "RBD_CONFIG_SOURCE_POOL"
293 _RBD_CONFIG_SOURCE_IMAGE "RBD_CONFIG_SOURCE_IMAGE"
295 ctypedef struct rbd_config_option_t:
298 rbd_config_source_t source
300 ctypedef enum rbd_pool_stat_option_t:
301 _RBD_POOL_STAT_OPTION_IMAGES "RBD_POOL_STAT_OPTION_IMAGES"
302 _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES"
303 _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES"
304 _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS "RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS"
305 _RBD_POOL_STAT_OPTION_TRASH_IMAGES "RBD_POOL_STAT_OPTION_TRASH_IMAGES"
306 _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES"
307 _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES"
308 _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
310 ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
312 void rbd_version(int *major, int *minor, int *extra)
314 void rbd_image_spec_list_cleanup(rbd_image_spec_t *image, size_t num_images)
315 void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
316 void rbd_linked_image_spec_list_cleanup(rbd_linked_image_spec_t *images,
318 void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
320 void rbd_image_options_create(rbd_image_options_t* opts)
321 void rbd_image_options_destroy(rbd_image_options_t opts)
322 int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
324 int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
326 int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
327 char* optval, size_t maxlen)
328 int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
330 int rbd_image_options_unset(rbd_image_options_t opts, int optname)
331 void rbd_image_options_clear(rbd_image_options_t opts)
332 int rbd_image_options_is_empty(rbd_image_options_t opts)
334 int rbd_list(rados_ioctx_t io, char *names, size_t *size)
335 int rbd_list2(rados_ioctx_t io, rbd_image_spec_t *images,
337 int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
339 int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
340 rbd_image_options_t opts)
341 int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
342 const char *p_snapname, rados_ioctx_t c_ioctx,
343 const char *c_name, rbd_image_options_t c_opts)
344 int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
345 librbd_progress_fn_t cb, void *cbdata)
346 int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
347 const char *destname)
349 int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay)
350 int rbd_trash_get(rados_ioctx_t io, const char *id,
351 rbd_trash_image_info_t *info)
352 void rbd_trash_get_cleanup(rbd_trash_image_info_t *info)
353 int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries,
355 void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
357 int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, float threshold)
358 int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
359 int force, librbd_progress_fn_t cb,
361 int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
363 int rbd_migration_prepare(rados_ioctx_t io_ctx, const char *image_name,
364 rados_ioctx_t dest_io_ctx,
365 const char *dest_image_name,
366 rbd_image_options_t opts)
367 int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
368 const char *image_name,
369 librbd_progress_fn_t cb,
371 int rbd_migration_commit_with_progress(rados_ioctx_t io_ctx,
372 const char *image_name,
373 librbd_progress_fn_t cb,
375 int rbd_migration_abort_with_progress(rados_ioctx_t io_ctx,
376 const char *image_name,
377 librbd_progress_fn_t cb, void *cbdata)
378 int rbd_migration_status(rados_ioctx_t io_ctx, const char *image_name,
379 rbd_image_migration_status_t *status,
381 void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
383 int rbd_mirror_site_name_get(rados_t cluster, char *name, size_t *max_len)
384 int rbd_mirror_site_name_set(rados_t cluster, const char *name)
386 int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
387 int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
389 int rbd_mirror_uuid_get(rados_ioctx_t io_ctx, char *mirror_uuid,
392 int rbd_mirror_peer_bootstrap_create(rados_ioctx_t io_ctx, char *token,
394 int rbd_mirror_peer_bootstrap_import(
395 rados_ioctx_t io_ctx, rbd_mirror_peer_direction_t direction,
398 int rbd_mirror_peer_site_add(
399 rados_ioctx_t io, char *uuid, size_t uuid_max_length,
400 rbd_mirror_peer_direction_t direction, const char *site_name,
401 const char *client_name)
402 int rbd_mirror_peer_site_remove(rados_ioctx_t io, const char *uuid)
403 int rbd_mirror_peer_site_list(
404 rados_ioctx_t io_ctx, rbd_mirror_peer_site_t *peers,int *max_peers)
405 void rbd_mirror_peer_site_list_cleanup(
406 rbd_mirror_peer_site_t *peers, int max_peers)
408 int rbd_mirror_peer_site_set_name(
409 rados_ioctx_t io_ctx, const char *uuid, const char *site_name)
410 int rbd_mirror_peer_site_set_client_name(
411 rados_ioctx_t io_ctx, const char *uuid, const char *client_name)
413 int rbd_mirror_peer_site_get_attributes(
414 rados_ioctx_t io_ctx, const char *uuid, char *keys, size_t *max_key_len,
415 char *values, size_t *max_val_length, size_t *key_value_count)
416 int rbd_mirror_peer_site_set_attributes(
417 rados_ioctx_t io_ctx, const char *uuid, const char *keys,
418 const char *values, size_t count)
420 int rbd_mirror_image_global_status_list(
421 rados_ioctx_t io, const char *start_id, size_t max, char **image_ids,
422 rbd_mirror_image_global_status_t *images, size_t *len)
423 void rbd_mirror_image_global_status_list_cleanup(
424 char **image_ids, rbd_mirror_image_global_status_t *images, size_t len)
425 int rbd_mirror_image_status_summary(rados_ioctx_t io,
426 rbd_mirror_image_status_state_t *states,
427 int *counts, size_t *maxlen)
428 int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx,
429 const char *start_id,
430 size_t max, char **image_ids,
433 void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
436 int rbd_mirror_image_info_list(rados_ioctx_t io_ctx,
437 rbd_mirror_image_mode_t *mode_filter,
438 const char *start_id, size_t max,
440 rbd_mirror_image_mode_t *mode_entries,
441 rbd_mirror_image_info_t *info_entries,
443 void rbd_mirror_image_info_list_cleanup(char **image_ids,
444 rbd_mirror_image_info_t *info_entries,
447 int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
448 char *value, size_t *val_len)
449 int rbd_pool_metadata_set(rados_ioctx_t io_ctx, const char *key,
451 int rbd_pool_metadata_remove(rados_ioctx_t io_ctx, const char *key)
452 int rbd_pool_metadata_list(rados_ioctx_t io_ctx, const char *start,
453 uint64_t max, char *keys, size_t *key_len,
454 char *values, size_t *vals_len)
456 int rbd_config_pool_list(rados_ioctx_t io_ctx, rbd_config_option_t *options,
458 void rbd_config_pool_list_cleanup(rbd_config_option_t *options,
461 int rbd_open(rados_ioctx_t io, const char *name,
462 rbd_image_t *image, const char *snap_name)
463 int rbd_open_by_id(rados_ioctx_t io, const char *image_id,
464 rbd_image_t *image, const char *snap_name)
465 int rbd_open_read_only(rados_ioctx_t io, const char *name,
466 rbd_image_t *image, const char *snap_name)
467 int rbd_open_by_id_read_only(rados_ioctx_t io, const char *image_id,
468 rbd_image_t *image, const char *snap_name)
469 int rbd_features_to_string(uint64_t features, char *str_features, size_t *size)
470 int rbd_features_from_string(const char *str_features, uint64_t *features)
471 int rbd_close(rbd_image_t image)
472 int rbd_resize2(rbd_image_t image, uint64_t size, bint allow_shrink,
473 librbd_progress_fn_t cb, void *cbdata)
474 int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
475 int rbd_get_old_format(rbd_image_t image, uint8_t *old)
476 int rbd_get_size(rbd_image_t image, uint64_t *size)
477 int rbd_get_features(rbd_image_t image, uint64_t *features)
478 int rbd_update_features(rbd_image_t image, uint64_t features,
480 int rbd_get_op_features(rbd_image_t image, uint64_t *op_features)
481 int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
482 int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
483 int rbd_get_create_timestamp(rbd_image_t image, timespec *timestamp)
484 int rbd_get_access_timestamp(rbd_image_t image, timespec *timestamp)
485 int rbd_get_modify_timestamp(rbd_image_t image, timespec *timestamp)
486 int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
487 int rbd_get_name(rbd_image_t image, char *name, size_t *name_len)
488 int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
489 int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
491 int64_t rbd_get_data_pool_id(rbd_image_t image)
492 int rbd_get_parent(rbd_image_t image,
493 rbd_linked_image_spec_t *parent_image,
494 rbd_snap_spec_t *parent_snap)
495 int rbd_get_flags(rbd_image_t image, uint64_t *flags)
496 int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
497 size_t group_info_size)
499 ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
500 char *buf, int op_flags)
501 ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
502 const char *buf, int op_flags)
503 int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
504 int rbd_write_zeroes(rbd_image_t image, uint64_t ofs, uint64_t len,
505 int zero_flags, int op_flags)
506 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
507 const char *destname, rbd_image_options_t dest_opts)
508 int rbd_deep_copy(rbd_image_t src, rados_ioctx_t dest_io_ctx,
509 const char *destname, rbd_image_options_t dest_opts)
510 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
512 void rbd_snap_list_end(rbd_snap_info_t *snaps)
513 int rbd_snap_create(rbd_image_t image, const char *snapname)
514 int rbd_snap_remove(rbd_image_t image, const char *snapname)
515 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
516 librbd_progress_fn_t cb, void *cbdata)
517 int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
518 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
519 int rbd_snap_rename(rbd_image_t image, const char *snapname,
520 const char* dstsnapsname)
521 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
522 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
523 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
525 int rbd_snap_exists(rbd_image_t image, const char *snapname, bint *exists)
526 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
527 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
528 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
529 int rbd_snap_set(rbd_image_t image, const char *snapname)
530 int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
531 int rbd_snap_get_name(rbd_image_t image, uint64_t snap_id,
532 char *snapname, size_t *name_len)
533 int rbd_snap_get_id(rbd_image_t image, const char *snapname,
535 int rbd_snap_get_namespace_type(rbd_image_t image,
537 rbd_snap_namespace_type_t *namespace_type)
538 int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
539 rbd_snap_group_namespace_t *group_info,
540 size_t snap_group_namespace_size)
541 void rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_spec,
542 size_t snap_group_namespace_size)
543 int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
544 char *original_name, size_t max_length)
545 int rbd_snap_get_mirror_namespace(
546 rbd_image_t image, uint64_t snap_id,
547 rbd_snap_mirror_namespace_t *mirror_ns,
548 size_t snap_mirror_namespace_size)
549 void rbd_snap_mirror_namespace_cleanup(
550 rbd_snap_mirror_namespace_t *mirror_ns,
551 size_t snap_mirror_namespace_size)
553 int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
555 int rbd_sparsify(rbd_image_t image, size_t sparse_size)
556 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
558 int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
559 size_t *max_children)
560 int rbd_list_descendants(rbd_image_t image,
561 rbd_linked_image_spec_t *descendants,
562 size_t *max_descendants)
564 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
565 char *tag, size_t *tag_len,
566 char *clients, size_t *clients_len,
567 char *cookies, size_t *cookies_len,
568 char *addrs, size_t *addrs_len)
569 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
570 int rbd_lock_shared(rbd_image_t image, const char *cookie,
572 int rbd_unlock(rbd_image_t image, const char *cookie)
573 int rbd_break_lock(rbd_image_t image, const char *client,
576 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
577 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
578 int rbd_lock_release(rbd_image_t image)
579 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
580 char **lock_owners, size_t *max_lock_owners)
581 void rbd_lock_get_owners_cleanup(char **lock_owners,
582 size_t lock_owner_count)
583 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
586 # We use -9000 to propagate Python exceptions. We use except? to make sure
587 # things still work as intended if -9000 happens to be a valid errno value
589 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
590 uint64_t ofs, uint64_t len,
591 uint8_t include_parent, uint8_t whole_object,
592 int (*cb)(uint64_t, size_t, int, void *)
594 void *arg) except? -9000
596 int rbd_flush(rbd_image_t image)
597 int rbd_invalidate_cache(rbd_image_t image)
599 int rbd_mirror_image_enable2(rbd_image_t image,
600 rbd_mirror_image_mode_t mode)
601 int rbd_mirror_image_disable(rbd_image_t image, bint force)
602 int rbd_mirror_image_promote(rbd_image_t image, bint force)
603 int rbd_mirror_image_demote(rbd_image_t image)
604 int rbd_mirror_image_resync(rbd_image_t image)
605 int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id)
606 int rbd_mirror_image_get_info(rbd_image_t image,
607 rbd_mirror_image_info_t *mirror_image_info,
609 void rbd_mirror_image_get_info_cleanup(
610 rbd_mirror_image_info_t *mirror_image_info)
611 int rbd_mirror_image_get_mode(rbd_image_t image,
612 rbd_mirror_image_mode_t *mode)
613 int rbd_mirror_image_get_global_status(
615 rbd_mirror_image_global_status_t *mirror_image_global_status,
617 void rbd_mirror_image_global_status_cleanup(
618 rbd_mirror_image_global_status_t *mirror_image_global_status)
619 int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id,
620 size_t *id_max_length)
622 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
623 const char *buf, rbd_completion_t c, int op_flags)
624 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
625 char *buf, rbd_completion_t c, int op_flags)
626 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
628 int rbd_aio_write_zeroes(rbd_image_t image, uint64_t off, uint64_t len,
629 rbd_completion_t c, int zero_flags, int op_flags)
631 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
633 int rbd_aio_is_complete(rbd_completion_t c)
634 int rbd_aio_wait_for_complete(rbd_completion_t c)
635 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
636 void rbd_aio_release(rbd_completion_t c)
637 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
639 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
641 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
642 int rbd_metadata_remove(rbd_image_t image, const char *key)
643 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
644 char *keys, size_t *key_len, char *values,
646 int rbd_group_create(rados_ioctx_t p, const char *name)
647 int rbd_group_remove(rados_ioctx_t p, const char *name)
648 int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
649 int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest)
650 void rbd_group_info_cleanup(rbd_group_info_t *group_info,
651 size_t group_info_size)
652 int rbd_group_image_add(rados_ioctx_t group_p, const char *group_name,
653 rados_ioctx_t image_p, const char *image_name)
654 int rbd_group_image_remove(rados_ioctx_t group_p, const char *group_name,
655 rados_ioctx_t image_p, const char *image_name)
657 int rbd_group_image_list(rados_ioctx_t group_p,
658 const char *group_name,
659 rbd_group_image_info_t *images,
660 size_t group_image_info_size,
662 void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
663 size_t group_image_info_size, size_t len)
665 int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
666 const char *snap_name)
668 int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
669 const char *snap_name)
671 int rbd_group_snap_rename(rados_ioctx_t group_p, const char *group_name,
672 const char *old_snap_name,
673 const char *new_snap_name)
675 int rbd_group_snap_list(rados_ioctx_t group_p,
676 const char *group_name,
677 rbd_group_snap_info_t *snaps,
678 size_t group_snap_info_size,
681 void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
682 size_t group_snap_info_size, size_t len)
683 int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
684 const char *snap_name)
686 int rbd_watchers_list(rbd_image_t image, rbd_image_watcher_t *watchers,
687 size_t *max_watchers)
688 void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
691 int rbd_config_image_list(rbd_image_t image, rbd_config_option_t *options,
693 void rbd_config_image_list_cleanup(rbd_config_option_t *options,
696 int rbd_namespace_create(rados_ioctx_t io, const char *namespace_name)
697 int rbd_namespace_remove(rados_ioctx_t io, const char *namespace_name)
698 int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
700 int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
703 int rbd_pool_init(rados_ioctx_t, bint force)
705 void rbd_pool_stats_create(rbd_pool_stats_t *stats)
706 void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
707 int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
708 int stat_option, uint64_t* stat_val)
709 int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
711 ECANCELED = _ECANCELED
713 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
714 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
715 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
716 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
717 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
718 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
719 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
720 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
721 RBD_FEATURE_OPERATIONS = _RBD_FEATURE_OPERATIONS
722 RBD_FEATURE_MIGRATING = _RBD_FEATURE_MIGRATING
723 RBD_FEATURE_NON_PRIMARY = _RBD_FEATURE_NON_PRIMARY
725 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
726 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
727 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
728 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
729 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
731 RBD_OPERATION_FEATURE_CLONE_PARENT = _RBD_OPERATION_FEATURE_CLONE_PARENT
732 RBD_OPERATION_FEATURE_CLONE_CHILD = _RBD_OPERATION_FEATURE_CLONE_CHILD
733 RBD_OPERATION_FEATURE_GROUP = _RBD_OPERATION_FEATURE_GROUP
734 RBD_OPERATION_FEATURE_SNAP_TRASH = _RBD_OPERATION_FEATURE_SNAP_TRASH
736 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
737 RBD_FLAG_FAST_DIFF_INVALID = _RBD_FLAG_FAST_DIFF_INVALID
739 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
740 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
741 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
743 RBD_MIRROR_PEER_DIRECTION_RX = _RBD_MIRROR_PEER_DIRECTION_RX
744 RBD_MIRROR_PEER_DIRECTION_TX = _RBD_MIRROR_PEER_DIRECTION_TX
745 RBD_MIRROR_PEER_DIRECTION_RX_TX = _RBD_MIRROR_PEER_DIRECTION_RX_TX
747 RBD_MIRROR_IMAGE_MODE_JOURNAL = _RBD_MIRROR_IMAGE_MODE_JOURNAL
748 RBD_MIRROR_IMAGE_MODE_SNAPSHOT = _RBD_MIRROR_IMAGE_MODE_SNAPSHOT
750 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
751 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
752 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
754 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
755 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
756 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
757 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
758 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
759 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
760 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
762 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
763 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
765 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
766 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
767 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
768 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
769 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
770 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
772 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
773 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
774 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
775 RBD_SNAP_NAMESPACE_TYPE_MIRROR = _RBD_SNAP_NAMESPACE_TYPE_MIRROR
777 RBD_SNAP_MIRROR_STATE_PRIMARY = _RBD_SNAP_MIRROR_STATE_PRIMARY
778 RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED
779 RBD_SNAP_MIRROR_STATE_NON_PRIMARY = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY
780 RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
782 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
783 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
785 RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
786 RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
788 RBD_IMAGE_MIGRATION_STATE_UNKNOWN = _RBD_IMAGE_MIGRATION_STATE_UNKNOWN
789 RBD_IMAGE_MIGRATION_STATE_ERROR = _RBD_IMAGE_MIGRATION_STATE_ERROR
790 RBD_IMAGE_MIGRATION_STATE_PREPARING = _RBD_IMAGE_MIGRATION_STATE_PREPARING
791 RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
792 RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
793 RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
794 RBD_IMAGE_MIGRATION_STATE_ABORTING = _RBD_IMAGE_MIGRATION_STATE_ABORTING
796 RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
797 RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
798 RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
800 RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
801 RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
802 RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
803 RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
804 RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
805 RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
806 RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
807 RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
809 RBD_SNAP_REMOVE_UNPROTECT = _RBD_SNAP_REMOVE_UNPROTECT
810 RBD_SNAP_REMOVE_FLATTEN = _RBD_SNAP_REMOVE_FLATTEN
811 RBD_SNAP_REMOVE_FORCE = _RBD_SNAP_REMOVE_FORCE
813 class Error(Exception):
817 class OSError(Error):
818 """ `OSError` class, derived from `Error` """
819 def __init__(self, message, errno=None):
820 super(OSError, self).__init__(message)
824 msg = super(OSError, self).__str__()
825 if self.errno is None:
827 return '[errno {0}] {1}'.format(self.errno, msg)
829 def __reduce__(self):
830 return (self.__class__, (self.message, self.errno))
832 class PermissionError(OSError):
833 def __init__(self, message, errno=None):
834 super(PermissionError, self).__init__(
835 "RBD permission error (%s)" % message, errno)
838 class ImageNotFound(OSError):
839 def __init__(self, message, errno=None):
840 super(ImageNotFound, self).__init__(
841 "RBD image not found (%s)" % message, errno)
844 class ObjectNotFound(OSError):
845 def __init__(self, message, errno=None):
846 super(ObjectNotFound, self).__init__(
847 "RBD object not found (%s)" % message, errno)
850 class ImageExists(OSError):
851 def __init__(self, message, errno=None):
852 super(ImageExists, self).__init__(
853 "RBD image already exists (%s)" % message, errno)
856 class ObjectExists(OSError):
857 def __init__(self, message, errno=None):
858 super(ObjectExists, self).__init__(
859 "RBD object already exists (%s)" % message, errno)
862 class IOError(OSError):
863 def __init__(self, message, errno=None):
864 super(IOError, self).__init__(
865 "RBD I/O error (%s)" % message, errno)
868 class NoSpace(OSError):
869 def __init__(self, message, errno=None):
870 super(NoSpace, self).__init__(
871 "RBD insufficient space available (%s)" % message, errno)
874 class IncompleteWriteError(OSError):
875 def __init__(self, message, errno=None):
876 super(IncompleteWriteError, self).__init__(
877 "RBD incomplete write (%s)" % message, errno)
880 class InvalidArgument(OSError):
881 def __init__(self, message, errno=None):
882 super(InvalidArgument, self).__init__(
883 "RBD invalid argument (%s)" % message, errno)
886 class LogicError(OSError):
887 def __init__(self, message, errno=None):
888 super(LogicError, self).__init__(
889 "RBD logic error (%s)" % message, errno)
892 class ReadOnlyImage(OSError):
893 def __init__(self, message, errno=None):
894 super(ReadOnlyImage, self).__init__(
895 "RBD read-only image (%s)" % message, errno)
898 class ImageBusy(OSError):
899 def __init__(self, message, errno=None):
900 super(ImageBusy, self).__init__(
901 "RBD image is busy (%s)" % message, errno)
904 class ImageHasSnapshots(OSError):
905 def __init__(self, message, errno=None):
906 super(ImageHasSnapshots, self).__init__(
907 "RBD image has snapshots (%s)" % message, errno)
910 class FunctionNotSupported(OSError):
911 def __init__(self, message, errno=None):
912 super(FunctionNotSupported, self).__init__(
913 "RBD function not supported (%s)" % message, errno)
916 class ArgumentOutOfRange(OSError):
917 def __init__(self, message, errno=None):
918 super(ArgumentOutOfRange, self).__init__(
919 "RBD arguments out of range (%s)" % message, errno)
922 class ConnectionShutdown(OSError):
923 def __init__(self, message, errno=None):
924 super(ConnectionShutdown, self).__init__(
925 "RBD connection was shutdown (%s)" % message, errno)
928 class Timeout(OSError):
929 def __init__(self, message, errno=None):
930 super(Timeout, self).__init__(
931 "RBD operation timeout (%s)" % message, errno)
934 class DiskQuotaExceeded(OSError):
935 def __init__(self, message, errno=None):
936 super(DiskQuotaExceeded, self).__init__(
937 "RBD disk quota exceeded (%s)" % message, errno)
939 class OperationNotSupported(OSError):
940 def __init__(self, message, errno=None):
941 super(OperationNotSupported, self).__init__(
942 "RBD operation not supported (%s)" % message, errno)
944 class OperationCanceled(OSError):
945 def __init__(self, message, errno=None):
946 super(OperationCanceled, self).__init__(
947 "RBD operation canceled (%s)" % message, errno)
949 cdef errno_to_exception = {
950 errno.EPERM : PermissionError,
951 errno.ENOENT : ImageNotFound,
953 errno.ENOSPC : NoSpace,
954 errno.EEXIST : ImageExists,
955 errno.EINVAL : InvalidArgument,
956 errno.EROFS : ReadOnlyImage,
957 errno.EBUSY : ImageBusy,
958 errno.ENOTEMPTY : ImageHasSnapshots,
959 errno.ENOSYS : FunctionNotSupported,
960 errno.EDOM : ArgumentOutOfRange,
961 errno.ESHUTDOWN : ConnectionShutdown,
962 errno.ETIMEDOUT : Timeout,
963 errno.EDQUOT : DiskQuotaExceeded,
964 errno.EOPNOTSUPP : OperationNotSupported,
965 ECANCELED : OperationCanceled,
968 cdef group_errno_to_exception = {
969 errno.EPERM : PermissionError,
970 errno.ENOENT : ObjectNotFound,
972 errno.ENOSPC : NoSpace,
973 errno.EEXIST : ObjectExists,
974 errno.EINVAL : InvalidArgument,
975 errno.EROFS : ReadOnlyImage,
976 errno.EBUSY : ImageBusy,
977 errno.ENOTEMPTY : ImageHasSnapshots,
978 errno.ENOSYS : FunctionNotSupported,
979 errno.EDOM : ArgumentOutOfRange,
980 errno.ESHUTDOWN : ConnectionShutdown,
981 errno.ETIMEDOUT : Timeout,
982 errno.EDQUOT : DiskQuotaExceeded,
983 errno.EOPNOTSUPP : OperationNotSupported,
984 ECANCELED : OperationCanceled,
987 cdef make_ex(ret, msg, exception_map=errno_to_exception):
989 Translate a librbd return code into an exception.
991 :param ret: the return code
993 :param msg: the error message to use
995 :returns: a subclass of :class:`Error`
998 if ret in exception_map:
999 return exception_map[ret](msg, errno=ret)
1001 return OSError(msg, errno=ret)
1004 cdef rados_t convert_rados(rados.Rados rados) except? NULL:
1005 return <rados_t>rados.cluster
1007 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
1008 return <rados_ioctx_t>ioctx.io
1010 cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
1011 return (<object>ptr)(offset, total)
1013 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
1016 def cstr(val, name, encoding="utf-8", opt=False):
1018 Create a byte string from a Python string
1020 :param basestring val: Python string
1021 :param str name: Name of the string parameter, for exceptions
1022 :param str encoding: Encoding to use
1023 :param bool opt: If True, None is allowed
1025 :raises: :class:`InvalidArgument`
1027 if opt and val is None:
1029 if isinstance(val, bytes):
1031 elif isinstance(val, str):
1032 return val.encode(encoding)
1033 elif sys.version_info < (3, 0) and isinstance(val, unicode):
1034 return val.encode(encoding)
1036 raise InvalidArgument('%s must be a string' % name)
1038 def decode_cstr(val, encoding="utf-8"):
1040 Decode a byte string into a Python string.
1042 :param bytes val: byte string
1043 :rtype: unicode or None
1048 return val.decode(encoding)
1051 cdef char* opt_str(s) except? NULL:
1056 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
1057 cdef void *ret = realloc(ptr, size)
1059 raise MemoryError("realloc failed")
1062 RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST)
1063 RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY)
1065 cdef class Completion
1067 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
1069 Callback to oncomplete() for asynchronous operations
1071 cdef Completion cb = <Completion>args
1075 cdef class Completion(object):
1076 """completion object"""
1081 rbd_completion_t rbd_comp
1086 def __cinit__(self, image, object oncomplete):
1087 self.oncomplete = oncomplete
1089 self.persisted = False
1091 def is_complete(self):
1093 Has an asynchronous operation completed?
1095 This does not imply that the callback has finished.
1097 :returns: True if the operation is completed
1100 ret = rbd_aio_is_complete(self.rbd_comp)
1103 def wait_for_complete_and_cb(self):
1105 Wait for an asynchronous operation to complete
1107 This method waits for the callback to execute, if one was provided.
1108 It will also re-raise any exceptions raised by the callback. You
1109 should call this to "reap" asynchronous completions and ensure that
1110 any exceptions in the callbacks are handled, as an exception internal
1111 to this module may have occurred.
1114 rbd_aio_wait_for_complete(self.rbd_comp)
1117 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
1119 def get_return_value(self):
1121 Get the return value of an asychronous operation
1123 The return value is set when the operation is complete.
1125 :returns: int - return value of the operation
1128 ret = rbd_aio_get_return_value(self.rbd_comp)
1131 def __dealloc__(self):
1133 Release a completion
1135 This is automatically called when the completion object is freed.
1137 ref.Py_XDECREF(self.buf)
1139 if self.rbd_comp != NULL:
1141 rbd_aio_release(self.rbd_comp)
1142 self.rbd_comp = NULL
1144 cdef void _complete(self):
1148 self.oncomplete(self)
1149 # In the event that something raises an exception during the next 2
1150 # lines of code, we will not be able to catch it, and this may result
1151 # in the app not noticing a failed callback. However, this should only
1152 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
1153 # should not be a problem because the callback thread from librbd
1154 # ought to have SIGINT blocked.
1156 self.exc_info = sys.exc_info()
1158 cdef __persist(self):
1159 if self.oncomplete is not None and not self.persisted:
1160 # Increment our own reference count to make sure the completion
1161 # is not freed until the callback is called. The completion is
1162 # allowed to be freed if there is no callback.
1164 self.persisted = True
1166 cdef __unpersist(self):
1169 self.persisted = False
1174 This class wraps librbd CRUD functions.
1178 Get the version number of the ``librbd`` C library.
1180 :returns: a tuple of ``(major, minor, extra)`` components of the
1186 rbd_version(&major, &minor, &extra)
1187 return (major, minor, extra)
1189 def create(self, ioctx, name, size, order=None, old_format=False,
1190 features=None, stripe_unit=None, stripe_count=None,
1193 Create an rbd image.
1195 :param ioctx: the context in which to create the image
1196 :type ioctx: :class:`rados.Ioctx`
1197 :param name: what the image is called
1199 :param size: how big the image is in bytes
1201 :param order: the image is split into (2**order) byte objects
1203 :param old_format: whether to create an old-style image that
1204 is accessible by old clients, but can't
1205 use more advanced features like layering.
1206 :type old_format: bool
1207 :param features: bitmask of features to enable
1209 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1210 :type stripe_unit: int
1211 :param stripe_count: objects to stripe over before looping
1212 :type stripe_count: int
1213 :param data_pool: optional separate pool for data blocks
1214 :type data_pool: str
1215 :raises: :class:`ImageExists`
1216 :raises: :class:`TypeError`
1217 :raises: :class:`InvalidArgument`
1218 :raises: :class:`FunctionNotSupported`
1220 name = cstr(name, 'name')
1221 data_pool = cstr(data_pool, 'data_pool', opt=True)
1223 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1225 uint64_t _size = size
1227 rbd_image_options_t opts
1228 if order is not None:
1232 ((stripe_unit is not None) and stripe_unit != 0) or
1233 ((stripe_count is not None) and stripe_count != 0) or
1235 raise InvalidArgument('format 1 images do not support feature '
1236 'masks, non-default striping, nor data '
1239 ret = rbd_create(_ioctx, _name, _size, &_order)
1241 rbd_image_options_create(&opts)
1243 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
1244 1 if old_format else 2)
1245 if features is not None:
1246 rbd_image_options_set_uint64(opts,
1247 RBD_IMAGE_OPTION_FEATURES,
1249 if order is not None:
1250 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1252 if stripe_unit is not None:
1253 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1255 if stripe_count is not None:
1256 rbd_image_options_set_uint64(opts,
1257 RBD_IMAGE_OPTION_STRIPE_COUNT,
1259 if data_pool is not None:
1260 rbd_image_options_set_string(opts,
1261 RBD_IMAGE_OPTION_DATA_POOL,
1264 ret = rbd_create4(_ioctx, _name, _size, opts)
1266 rbd_image_options_destroy(opts)
1268 raise make_ex(ret, 'error creating image')
1270 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
1271 features=None, order=None, stripe_unit=None, stripe_count=None,
1274 Clone a parent rbd snapshot into a COW sparse child.
1276 :param p_ioctx: the parent context that represents the parent snap
1277 :type ioctx: :class:`rados.Ioctx`
1278 :param p_name: the parent image name
1280 :param p_snapname: the parent image snapshot name
1282 :param c_ioctx: the child context that represents the new clone
1283 :type ioctx: :class:`rados.Ioctx`
1284 :param c_name: the clone (child) name
1286 :param features: bitmask of features to enable; if set, must include layering
1288 :param order: the image is split into (2**order) byte objects
1290 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1291 :type stripe_unit: int
1292 :param stripe_count: objects to stripe over before looping
1293 :type stripe_count: int
1294 :param data_pool: optional separate pool for data blocks
1295 :type data_pool: str
1296 :raises: :class:`TypeError`
1297 :raises: :class:`InvalidArgument`
1298 :raises: :class:`ImageExists`
1299 :raises: :class:`FunctionNotSupported`
1300 :raises: :class:`ArgumentOutOfRange`
1302 p_snapname = cstr(p_snapname, 'p_snapname')
1303 p_name = cstr(p_name, 'p_name')
1304 c_name = cstr(c_name, 'c_name')
1305 data_pool = cstr(data_pool, 'data_pool', opt=True)
1307 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
1308 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
1309 char *_p_name = p_name
1310 char *_p_snapname = p_snapname
1311 char *_c_name = c_name
1312 rbd_image_options_t opts
1314 rbd_image_options_create(&opts)
1316 if features is not None:
1317 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1319 if order is not None:
1320 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1322 if stripe_unit is not None:
1323 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1325 if stripe_count is not None:
1326 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1328 if data_pool is not None:
1329 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1332 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
1333 _c_ioctx, _c_name, opts)
1335 rbd_image_options_destroy(opts)
1337 raise make_ex(ret, 'error creating clone')
1339 def list(self, ioctx):
1343 :param ioctx: determines which RADOS pool is read
1344 :type ioctx: :class:`rados.Ioctx`
1345 :returns: list -- a list of image names
1348 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1350 char *c_names = NULL
1353 c_names = <char *>realloc_chk(c_names, size)
1355 ret = rbd_list(_ioctx, c_names, &size)
1358 elif ret != -errno.ERANGE:
1359 raise make_ex(ret, 'error listing images')
1360 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
1365 def list2(self, ioctx):
1367 Iterate over the images in the pool.
1369 :param ioctx: determines which RADOS pool the image is in
1370 :type ioctx: :class:`rados.Ioctx`
1371 :returns: :class:`ImageIterator`
1373 return ImageIterator(ioctx)
1375 def remove(self, ioctx, name, on_progress=None):
1377 Delete an RBD image. This may take a long time, since it does
1378 not return until every object that comprises the image has
1379 been deleted. Note that all snapshots must be deleted before
1380 the image can be removed. If there are snapshots left,
1381 :class:`ImageHasSnapshots` is raised. If the image is still
1382 open, or the watch from a crashed client has not expired,
1383 :class:`ImageBusy` is raised.
1385 :param ioctx: determines which RADOS pool the image is in
1386 :type ioctx: :class:`rados.Ioctx`
1387 :param name: the name of the image to remove
1389 :param on_progress: optional progress callback function
1390 :type on_progress: callback function
1391 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
1392 :class:`ImageHasSnapshots`
1394 name = cstr(name, 'name')
1396 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1398 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1399 void *_prog_arg = NULL
1401 _prog_cb = &progress_callback
1402 _prog_arg = <void *>on_progress
1404 ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
1406 raise make_ex(ret, 'error removing image')
1408 def rename(self, ioctx, src, dest):
1410 Rename an RBD image.
1412 :param ioctx: determines which RADOS pool the image is in
1413 :type ioctx: :class:`rados.Ioctx`
1414 :param src: the current name of the image
1416 :param dest: the new name of the image
1418 :raises: :class:`ImageNotFound`, :class:`ImageExists`
1420 src = cstr(src, 'src')
1421 dest = cstr(dest, 'dest')
1423 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1427 ret = rbd_rename(_ioctx, _src, _dest)
1429 raise make_ex(ret, 'error renaming image')
1431 def trash_move(self, ioctx, name, delay=0):
1433 Move an RBD image to the trash.
1435 :param ioctx: determines which RADOS pool the image is in
1436 :type ioctx: :class:`rados.Ioctx`
1437 :param name: the name of the image to remove
1439 :param delay: time delay in seconds before the image can be deleted
1442 :raises: :class:`ImageNotFound`
1444 name = cstr(name, 'name')
1446 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1448 uint64_t _delay = delay
1450 ret = rbd_trash_move(_ioctx, _name, _delay)
1452 raise make_ex(ret, 'error moving image to trash')
1454 def trash_purge(self, ioctx, expire_ts=None, threshold=-1):
1456 Delete RBD images from trash in bulk.
1458 By default it removes images with deferment end time less than now.
1460 The timestamp is configurable, e.g. delete images that have expired a
1463 If the threshold is used it deletes images until X% pool usage is met.
1465 :param ioctx: determines which RADOS pool the image is in
1466 :type ioctx: :class:`rados.Ioctx`
1467 :param expire_ts: timestamp for images to be considered as expired (UTC)
1468 :type expire_ts: datetime
1469 :param threshold: percentage of pool usage to be met (0 to 1)
1470 :type threshold: float
1473 expire_epoch_ts = time.mktime(expire_ts.timetuple())
1478 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1479 time_t _expire_ts = expire_epoch_ts
1480 float _threshold = threshold
1482 ret = rbd_trash_purge(_ioctx, _expire_ts, _threshold)
1484 raise make_ex(ret, 'error purging images from trash')
1486 def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
1488 Delete an RBD image from trash. If image deferment time has not
1489 expired :class:`PermissionError` is raised.
1491 :param ioctx: determines which RADOS pool the image is in
1492 :type ioctx: :class:`rados.Ioctx`
1493 :param image_id: the id of the image to remove
1495 :param force: force remove even if deferment time has not expired
1497 :param on_progress: optional progress callback function
1498 :type on_progress: callback function
1499 :raises: :class:`ImageNotFound`, :class:`PermissionError`
1501 image_id = cstr(image_id, 'image_id')
1503 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1504 char *_image_id = image_id
1506 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1507 void *_prog_arg = NULL
1509 _prog_cb = &progress_callback
1510 _prog_arg = <void *>on_progress
1512 ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
1513 _prog_cb, _prog_arg)
1515 raise make_ex(ret, 'error deleting image from trash')
1517 def trash_get(self, ioctx, image_id):
1519 Retrieve RBD image info from trash.
1521 :param ioctx: determines which RADOS pool the image is in
1522 :type ioctx: :class:`rados.Ioctx`
1523 :param image_id: the id of the image to restore
1525 :returns: dict - contains the following keys:
1527 * ``id`` (str) - image id
1529 * ``name`` (str) - image name
1531 * ``source`` (str) - source of deletion
1533 * ``deletion_time`` (datetime) - time of deletion
1535 * ``deferment_end_time`` (datetime) - time that an image is allowed
1536 to be removed from trash
1538 :raises: :class:`ImageNotFound`
1540 image_id = cstr(image_id, 'image_id')
1542 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1543 char *_image_id = image_id
1544 rbd_trash_image_info_t c_info
1546 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
1548 raise make_ex(ret, 'error retrieving image from trash')
1550 __source_string = ['USER', 'MIRRORING', 'MIGRATION', 'REMOVING']
1552 'id' : decode_cstr(c_info.id),
1553 'name' : decode_cstr(c_info.name),
1554 'source' : __source_string[c_info.source],
1555 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
1556 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
1558 rbd_trash_get_cleanup(&c_info)
1561 def trash_list(self, ioctx):
1563 List all entries from trash.
1565 :param ioctx: determines which RADOS pool the image is in
1566 :type ioctx: :class:`rados.Ioctx`
1567 :returns: :class:`TrashIterator`
1569 return TrashIterator(ioctx)
1571 def trash_restore(self, ioctx, image_id, name):
1573 Restore an RBD image from trash.
1575 :param ioctx: determines which RADOS pool the image is in
1576 :type ioctx: :class:`rados.Ioctx`
1577 :param image_id: the id of the image to restore
1579 :param name: the new name of the restored image
1581 :raises: :class:`ImageNotFound`
1583 image_id = cstr(image_id, 'image_id')
1584 name = cstr(name, 'name')
1586 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1587 char *_image_id = image_id
1590 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1592 raise make_ex(ret, 'error restoring image from trash')
1594 def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
1595 features=None, order=None, stripe_unit=None, stripe_count=None,
1598 Prepare an RBD image migration.
1600 :param ioctx: determines which RADOS pool the image is in
1601 :type ioctx: :class:`rados.Ioctx`
1602 :param image_name: the current name of the image
1604 :param dest_ioctx: determines which pool to migration into
1605 :type dest_ioctx: :class:`rados.Ioctx`
1606 :param dest_image_name: the name of the destination image (may be the same image)
1607 :type dest_image_name: str
1608 :param features: bitmask of features to enable; if set, must include layering
1610 :param order: the image is split into (2**order) byte objects
1612 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1613 :type stripe_unit: int
1614 :param stripe_count: objects to stripe over before looping
1615 :type stripe_count: int
1616 :param data_pool: optional separate pool for data blocks
1617 :type data_pool: str
1618 :raises: :class:`TypeError`
1619 :raises: :class:`InvalidArgument`
1620 :raises: :class:`ImageExists`
1621 :raises: :class:`FunctionNotSupported`
1622 :raises: :class:`ArgumentOutOfRange`
1624 image_name = cstr(image_name, 'image_name')
1625 dest_image_name = cstr(dest_image_name, 'dest_image_name')
1627 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1628 char *_image_name = image_name
1629 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1630 char *_dest_image_name = dest_image_name
1631 rbd_image_options_t opts
1633 rbd_image_options_create(&opts)
1635 if features is not None:
1636 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1638 if order is not None:
1639 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1641 if stripe_unit is not None:
1642 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1644 if stripe_count is not None:
1645 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1647 if data_pool is not None:
1648 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1651 ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
1652 _dest_image_name, opts)
1654 rbd_image_options_destroy(opts)
1656 raise make_ex(ret, 'error migrating image %s' % (image_name))
1658 def migration_execute(self, ioctx, image_name, on_progress=None):
1660 Execute a prepared RBD image migration.
1662 :param ioctx: determines which RADOS pool the image is in
1663 :type ioctx: :class:`rados.Ioctx`
1664 :param image_name: the name of the image
1665 :type image_name: str
1666 :param on_progress: optional progress callback function
1667 :type on_progress: callback function
1668 :raises: :class:`ImageNotFound`
1670 image_name = cstr(image_name, 'image_name')
1672 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1673 char *_image_name = image_name
1674 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1675 void *_prog_arg = NULL
1677 _prog_cb = &progress_callback
1678 _prog_arg = <void *>on_progress
1680 ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
1681 _prog_cb, _prog_arg)
1683 raise make_ex(ret, 'error aborting migration')
1685 def migration_commit(self, ioctx, image_name, on_progress=None):
1687 Commit an executed RBD image migration.
1689 :param ioctx: determines which RADOS pool the image is in
1690 :type ioctx: :class:`rados.Ioctx`
1691 :param image_name: the name of the image
1692 :type image_name: str
1693 :param on_progress: optional progress callback function
1694 :type on_progress: callback function
1695 :raises: :class:`ImageNotFound`
1697 image_name = cstr(image_name, 'image_name')
1699 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1700 char *_image_name = image_name
1701 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1702 void *_prog_arg = NULL
1704 _prog_cb = &progress_callback
1705 _prog_arg = <void *>on_progress
1707 ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
1708 _prog_cb, _prog_arg)
1710 raise make_ex(ret, 'error aborting migration')
1712 def migration_abort(self, ioctx, image_name, on_progress=None):
1714 Cancel a previously started but interrupted migration.
1716 :param ioctx: determines which RADOS pool the image is in
1717 :type ioctx: :class:`rados.Ioctx`
1718 :param image_name: the name of the image
1719 :type image_name: str
1720 :param on_progress: optional progress callback function
1721 :type on_progress: callback function
1722 :raises: :class:`ImageNotFound`
1724 image_name = cstr(image_name, 'image_name')
1726 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1727 char *_image_name = image_name
1728 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1729 void *_prog_arg = NULL
1731 _prog_cb = &progress_callback
1732 _prog_arg = <void *>on_progress
1734 ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
1735 _prog_cb, _prog_arg)
1737 raise make_ex(ret, 'error aborting migration')
1739 def migration_status(self, ioctx, image_name):
1741 Return RBD image migration status.
1743 :param ioctx: determines which RADOS pool the image is in
1744 :type ioctx: :class:`rados.Ioctx`
1745 :param image_name: the name of the image
1746 :type image_name: str
1747 :returns: dict - contains the following keys:
1749 * ``source_pool_id`` (int) - source image pool id
1751 * ``source_pool_namespace`` (str) - source image pool namespace
1753 * ``source_image_name`` (str) - source image name
1755 * ``source_image_id`` (str) - source image id
1757 * ``dest_pool_id`` (int) - destination image pool id
1759 * ``dest_pool_namespace`` (str) - destination image pool namespace
1761 * ``dest_image_name`` (str) - destination image name
1763 * ``dest_image_id`` (str) - destination image id
1765 * ``state`` (int) - current migration state
1767 * ``state_description`` (str) - migration state description
1769 :raises: :class:`ImageNotFound`
1771 image_name = cstr(image_name, 'image_name')
1773 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1774 char *_image_name = image_name
1775 rbd_image_migration_status_t c_status
1777 ret = rbd_migration_status(_ioctx, _image_name, &c_status,
1780 raise make_ex(ret, 'error getting migration status')
1783 'source_pool_id' : c_status.source_pool_id,
1784 'source_pool_namespace' : decode_cstr(c_status.source_pool_namespace),
1785 'source_image_name' : decode_cstr(c_status.source_image_name),
1786 'source_image_id' : decode_cstr(c_status.source_image_id),
1787 'dest_pool_id' : c_status.source_pool_id,
1788 'dest_pool_namespace' : decode_cstr(c_status.dest_pool_namespace),
1789 'dest_image_name' : decode_cstr(c_status.dest_image_name),
1790 'dest_image_id' : decode_cstr(c_status.dest_image_id),
1791 'state' : c_status.state,
1792 'state_description' : decode_cstr(c_status.state_description)
1795 rbd_migration_status_cleanup(&c_status)
1799 def mirror_site_name_get(self, rados):
1801 Get the local cluster's friendly site name
1803 :param rados: cluster connection
1804 :type rados: :class: rados.Rados
1805 :returns: str - local site name
1808 rados_t _rados = convert_rados(rados)
1809 char *_site_name = NULL
1810 size_t _max_size = 512
1813 _site_name = <char *>realloc_chk(_site_name, _max_size)
1815 ret = rbd_mirror_site_name_get(_rados, _site_name,
1819 elif ret != -errno.ERANGE:
1820 raise make_ex(ret, 'error getting site name')
1821 return decode_cstr(_site_name)
1825 def mirror_site_name_set(self, rados, site_name):
1827 Set the local cluster's friendly site name
1829 :param rados: cluster connection
1830 :type rados: :class: rados.Rados
1831 :param site_name: friendly site name
1834 site_name = cstr(site_name, 'site_name')
1836 rados_t _rados = convert_rados(rados)
1837 char *_site_name = site_name
1839 ret = rbd_mirror_site_name_set(_rados, _site_name)
1841 raise make_ex(ret, 'error setting mirror site name')
1843 def mirror_mode_get(self, ioctx):
1845 Get pool mirror mode.
1847 :param ioctx: determines which RADOS pool is read
1848 :type ioctx: :class:`rados.Ioctx`
1849 :returns: int - pool mirror mode
1852 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1853 rbd_mirror_mode_t mirror_mode
1855 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1857 raise make_ex(ret, 'error getting mirror mode')
1860 def mirror_mode_set(self, ioctx, mirror_mode):
1862 Set pool mirror mode.
1864 :param ioctx: determines which RADOS pool is written
1865 :type ioctx: :class:`rados.Ioctx`
1866 :param mirror_mode: mirror mode to set
1867 :type mirror_mode: int
1870 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1871 rbd_mirror_mode_t _mirror_mode = mirror_mode
1873 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1875 raise make_ex(ret, 'error setting mirror mode')
1877 def mirror_uuid_get(self, ioctx):
1879 Get pool mirror uuid
1881 :param ioctx: determines which RADOS pool is read
1882 :type ioctx: :class:`rados.Ioctx`
1883 :returns: ste - pool mirror uuid
1886 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1888 size_t _max_size = 512
1891 _uuid = <char *>realloc_chk(_uuid, _max_size)
1893 ret = rbd_mirror_uuid_get(_ioctx, _uuid, &_max_size)
1896 elif ret != -errno.ERANGE:
1897 raise make_ex(ret, 'error retrieving mirror uuid')
1898 return decode_cstr(_uuid)
1902 def mirror_peer_bootstrap_create(self, ioctx):
1904 Creates a new RBD mirroring bootstrap token for an
1907 :param ioctx: determines which RADOS pool is written
1908 :type ioctx: :class:`rados.Ioctx`
1909 :returns: str - bootstrap token
1912 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1914 size_t _max_size = 512
1917 _token = <char *>realloc_chk(_token, _max_size)
1919 ret = rbd_mirror_peer_bootstrap_create(_ioctx, _token,
1923 elif ret != -errno.ERANGE:
1924 raise make_ex(ret, 'error creating bootstrap token')
1925 return decode_cstr(_token)
1929 def mirror_peer_bootstrap_import(self, ioctx, direction, token):
1931 Import a bootstrap token from an external cluster to
1932 auto-configure the mirror peer.
1934 :param ioctx: determines which RADOS pool is written
1935 :type ioctx: :class:`rados.Ioctx`
1936 :param direction: mirror peer direction
1937 :type direction: int
1938 :param token: bootstrap token
1941 token = cstr(token, 'token')
1943 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1944 rbd_mirror_peer_direction_t _direction = direction
1945 char *_token = token
1947 ret = rbd_mirror_peer_bootstrap_import(_ioctx, _direction, _token)
1949 raise make_ex(ret, 'error importing bootstrap token')
1951 def mirror_peer_add(self, ioctx, site_name, client_name,
1952 direction=RBD_MIRROR_PEER_DIRECTION_RX_TX):
1956 :param ioctx: determines which RADOS pool is used
1957 :type ioctx: :class:`rados.Ioctx`
1958 :param site_name: mirror peer site name
1959 :type site_name: str
1960 :param client_name: mirror peer client name
1961 :type client_name: str
1962 :param direction: the direction of the mirroring
1963 :type direction: int
1964 :returns: str - peer uuid
1966 site_name = cstr(site_name, 'site_name')
1967 client_name = cstr(client_name, 'client_name')
1969 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1971 size_t _uuid_max_length = 512
1972 rbd_mirror_peer_direction_t _direction = direction
1973 char *_site_name = site_name
1974 char *_client_name = client_name
1976 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1977 ret = rbd_mirror_peer_site_add(_ioctx, _uuid, _uuid_max_length,
1978 _direction, _site_name, _client_name)
1980 raise make_ex(ret, 'error adding mirror peer')
1981 return decode_cstr(_uuid)
1985 def mirror_peer_remove(self, ioctx, uuid):
1989 :param ioctx: determines which RADOS pool is used
1990 :type ioctx: :class:`rados.Ioctx`
1991 :param uuid: peer uuid
1994 uuid = cstr(uuid, 'uuid')
1996 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1999 ret = rbd_mirror_peer_site_remove(_ioctx, _uuid)
2001 raise make_ex(ret, 'error removing mirror peer')
2003 def mirror_peer_list(self, ioctx):
2005 Iterate over the peers of a pool.
2007 :param ioctx: determines which RADOS pool is read
2008 :type ioctx: :class:`rados.Ioctx`
2009 :returns: :class:`MirrorPeerIterator`
2011 return MirrorPeerIterator(ioctx)
2013 def mirror_peer_set_client(self, ioctx, uuid, client_name):
2015 Set mirror peer client name
2017 :param ioctx: determines which RADOS pool is written
2018 :type ioctx: :class:`rados.Ioctx`
2019 :param uuid: uuid of the mirror peer
2021 :param client_name: client name of the mirror peer to set
2022 :type client_name: str
2024 uuid = cstr(uuid, 'uuid')
2025 client_name = cstr(client_name, 'client_name')
2027 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2029 char *_client_name = client_name
2031 ret = rbd_mirror_peer_site_set_client_name(_ioctx, _uuid,
2034 raise make_ex(ret, 'error setting mirror peer client name')
2036 def mirror_peer_set_name(self, ioctx, uuid, site_name):
2038 Set mirror peer site name
2040 :param ioctx: determines which RADOS pool is written
2041 :type ioctx: :class:`rados.Ioctx`
2042 :param uuid: uuid of the mirror peer
2044 :param site_name: site name of the mirror peer to set
2045 :type site_name: str
2047 uuid = cstr(uuid, 'uuid')
2048 site_name = cstr(site_name, 'site_name')
2050 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2052 char *_site_name = site_name
2054 ret = rbd_mirror_peer_site_set_name(_ioctx, _uuid, _site_name)
2056 raise make_ex(ret, 'error setting mirror peer site name')
2058 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
2059 self.mirror_peer_set_name(ioctx, uuid, cluster_name)
2061 def mirror_peer_get_attributes(self, ioctx, uuid):
2063 Get optional mirror peer attributes
2065 :param ioctx: determines which RADOS pool is written
2066 :type ioctx: :class:`rados.Ioctx`
2067 :param uuid: uuid of the mirror peer
2070 :returns: dict - contains the following keys:
2072 * ``mon_host`` (str) - monitor addresses
2074 * ``key`` (str) - CephX key
2076 uuid = cstr(uuid, 'uuid')
2078 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2082 size_t _keys_size = 512
2083 size_t _vals_size = 512
2087 _keys = <char *>realloc_chk(_keys, _keys_size)
2088 _vals = <char *>realloc_chk(_vals, _vals_size)
2090 ret = rbd_mirror_peer_site_get_attributes(
2091 _ioctx, _uuid, _keys, &_keys_size, _vals, &_vals_size,
2095 elif ret != -errno.ERANGE:
2096 raise make_ex(ret, 'error getting mirror peer attributes')
2097 keys = [decode_cstr(x) for x in _keys[:_keys_size].split(b'\0')[:-1]]
2098 vals = [decode_cstr(x) for x in _vals[:_vals_size].split(b'\0')[:-1]]
2099 return dict(zip(keys, vals))
2104 def mirror_peer_set_attributes(self, ioctx, uuid, attributes):
2106 Set optional mirror peer attributes
2108 :param ioctx: determines which RADOS pool is written
2109 :type ioctx: :class:`rados.Ioctx`
2110 :param uuid: uuid of the mirror peer
2112 :param attributes: 'mon_host' and 'key' attributes
2113 :type attributes: dict
2115 uuid = cstr(uuid, 'uuid')
2116 keys_str = b'\0'.join([cstr(x[0], 'key') for x in attributes.items()])
2117 vals_str = b'\0'.join([cstr(x[1], 'val') for x in attributes.items()])
2119 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2121 char *_keys = keys_str
2122 char *_vals = vals_str
2123 size_t _count = len(attributes)
2126 ret = rbd_mirror_peer_site_set_attributes(_ioctx, _uuid, _keys,
2129 raise make_ex(ret, 'error setting mirror peer attributes')
2131 def mirror_image_status_list(self, ioctx):
2133 Iterate over the mirror image statuses of a pool.
2135 :param ioctx: determines which RADOS pool is read
2136 :type ioctx: :class:`rados.Ioctx`
2137 :returns: :class:`MirrorImageStatusIterator`
2139 return MirrorImageStatusIterator(ioctx)
2141 def mirror_image_status_summary(self, ioctx):
2143 Get mirror image status summary of a pool.
2145 :param ioctx: determines which RADOS pool is read
2146 :type ioctx: :class:`rados.Ioctx`
2147 :returns: list - a list of (state, count) tuples
2150 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2151 rbd_mirror_image_status_state_t *states = NULL
2155 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
2156 sizeof(rbd_mirror_image_status_state_t) * maxlen)
2157 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
2159 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
2162 raise make_ex(ret, 'error getting mirror image status summary')
2163 return [(states[i], counts[i]) for i in range(maxlen)]
2168 def mirror_image_instance_id_list(self, ioctx):
2170 Iterate over the mirror image instance ids of a pool.
2172 :param ioctx: determines which RADOS pool is read
2173 :type ioctx: :class:`rados.Ioctx`
2174 :returns: :class:`MirrorImageInstanceIdIterator`
2176 return MirrorImageInstanceIdIterator(ioctx)
2178 def mirror_image_info_list(self, ioctx, mode_filter=None):
2180 Iterate over the mirror image instance ids of a pool.
2182 :param ioctx: determines which RADOS pool is read
2183 :param mode_filter: list images in this image mirror mode
2184 :type ioctx: :class:`rados.Ioctx`
2185 :returns: :class:`MirrorImageInfoIterator`
2187 return MirrorImageInfoIterator(ioctx, mode_filter)
2189 def pool_metadata_get(self, ioctx, key):
2191 Get pool metadata for the given key.
2193 :param ioctx: determines which RADOS pool is read
2194 :type ioctx: :class:`rados.Ioctx`
2195 :param key: metadata key
2197 :returns: str - metadata value
2199 key = cstr(key, 'key')
2201 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2208 value = <char *>realloc_chk(value, size)
2210 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2211 if ret != -errno.ERANGE:
2213 if ret == -errno.ENOENT:
2214 raise KeyError('no metadata %s' % (key))
2216 raise make_ex(ret, 'error getting metadata %s' % (key))
2217 return decode_cstr(value)
2221 def pool_metadata_set(self, ioctx, key, value):
2223 Set pool metadata for the given key.
2225 :param ioctx: determines which RADOS pool is read
2226 :type ioctx: :class:`rados.Ioctx`
2227 :param key: metadata key
2229 :param value: metadata value
2232 key = cstr(key, 'key')
2233 value = cstr(value, 'value')
2235 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2237 char *_value = value
2239 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2242 raise make_ex(ret, 'error setting metadata %s' % (key))
2244 def pool_metadata_remove(self, ioctx, key):
2246 Remove pool metadata for the given key.
2248 :param ioctx: determines which RADOS pool is read
2249 :type ioctx: :class:`rados.Ioctx`
2250 :param key: metadata key
2252 :returns: str - metadata value
2254 key = cstr(key, 'key')
2256 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2259 ret = rbd_pool_metadata_remove(_ioctx, _key)
2261 if ret == -errno.ENOENT:
2262 raise KeyError('no metadata %s' % (key))
2264 raise make_ex(ret, 'error removing metadata %s' % (key))
2266 def pool_metadata_list(self, ioctx):
2270 :returns: :class:`PoolMetadataIterator`
2272 return PoolMetadataIterator(ioctx)
2274 def config_list(self, ioctx):
2276 List pool-level config overrides.
2278 :returns: :class:`ConfigPoolIterator`
2280 return ConfigPoolIterator(ioctx)
2282 def config_get(self, ioctx, key):
2284 Get a pool-level configuration override.
2286 :param ioctx: determines which RADOS pool is read
2287 :type ioctx: :class:`rados.Ioctx`
2290 :returns: str - value
2292 conf_key = 'conf_' + key
2293 conf_key = cstr(conf_key, 'key')
2295 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2296 char *_key = conf_key
2302 value = <char *>realloc_chk(value, size)
2304 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2305 if ret != -errno.ERANGE:
2307 if ret == -errno.ENOENT:
2308 raise KeyError('no config %s for pool %s' % (key, ioctx.get_pool_name()))
2310 raise make_ex(ret, 'error getting config %s for pool %s' %
2311 (key, ioctx.get_pool_name()))
2312 return decode_cstr(value)
2316 def config_set(self, ioctx, key, value):
2318 Get a pool-level configuration override.
2320 :param ioctx: determines which RADOS pool is read
2321 :type ioctx: :class:`rados.Ioctx`
2327 conf_key = 'conf_' + key
2328 conf_key = cstr(conf_key, 'key')
2329 value = cstr(value, 'value')
2331 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2332 char *_key = conf_key
2333 char *_value = value
2335 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2338 raise make_ex(ret, 'error setting config %s for pool %s' %
2339 (key, ioctx.get_pool_name()))
2341 def config_remove(self, ioctx, key):
2343 Remove a pool-level configuration override.
2345 :param ioctx: determines which RADOS pool is read
2346 :type ioctx: :class:`rados.Ioctx`
2349 :returns: str - value
2351 conf_key = 'conf_' + key
2352 conf_key = cstr(conf_key, 'key')
2354 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2355 char *_key = conf_key
2357 ret = rbd_pool_metadata_remove(_ioctx, _key)
2359 if ret == -errno.ENOENT:
2360 raise KeyError('no config %s for pool %s' %
2361 (key, ioctx.get_pool_name()))
2363 raise make_ex(ret, 'error removing config %s for pool %s' %
2364 (key, ioctx.get_pool_name()))
2366 def group_create(self, ioctx, name):
2370 :param ioctx: determines which RADOS pool is used
2371 :type ioctx: :class:`rados.Ioctx`
2372 :param name: the name of the group
2374 :raises: :class:`ObjectExists`
2375 :raises: :class:`InvalidArgument`
2376 :raises: :class:`FunctionNotSupported`
2378 name = cstr(name, 'name')
2381 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2383 ret = rbd_group_create(_ioctx, _name)
2385 raise make_ex(ret, 'error creating group %s' % name, group_errno_to_exception)
2387 def group_remove(self, ioctx, name):
2389 Delete an RBD group. This may take a long time, since it does
2390 not return until every image in the group has been removed
2393 :param ioctx: determines which RADOS pool the group is in
2394 :type ioctx: :class:`rados.Ioctx`
2395 :param name: the name of the group to remove
2397 :raises: :class:`ObjectNotFound`
2398 :raises: :class:`InvalidArgument`
2399 :raises: :class:`FunctionNotSupported`
2401 name = cstr(name, 'name')
2403 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2406 ret = rbd_group_remove(_ioctx, _name)
2408 raise make_ex(ret, 'error removing group', group_errno_to_exception)
2410 def group_list(self, ioctx):
2414 :param ioctx: determines which RADOS pool is read
2415 :type ioctx: :class:`rados.Ioctx`
2416 :returns: list -- a list of groups names
2417 :raises: :class:`FunctionNotSupported`
2420 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2422 char *c_names = NULL
2425 c_names = <char *>realloc_chk(c_names, size)
2427 ret = rbd_group_list(_ioctx, c_names, &size)
2430 elif ret != -errno.ERANGE:
2431 raise make_ex(ret, 'error listing groups', group_errno_to_exception)
2432 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
2437 def group_rename(self, ioctx, src, dest):
2439 Rename an RBD group.
2441 :param ioctx: determines which RADOS pool the group is in
2442 :type ioctx: :class:`rados.Ioctx`
2443 :param src: the current name of the group
2445 :param dest: the new name of the group
2447 :raises: :class:`ObjectExists`
2448 :raises: :class:`ObjectNotFound`
2449 :raises: :class:`InvalidArgument`
2450 :raises: :class:`FunctionNotSupported`
2452 src = cstr(src, 'src')
2453 dest = cstr(dest, 'dest')
2455 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2459 ret = rbd_group_rename(_ioctx, _src, _dest)
2461 raise make_ex(ret, 'error renaming group')
2463 def namespace_create(self, ioctx, name):
2465 Create an RBD namespace within a pool
2467 :param ioctx: determines which RADOS pool
2468 :type ioctx: :class:`rados.Ioctx`
2469 :param name: namespace name
2472 name = cstr(name, 'name')
2474 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2475 const char *_name = name
2477 ret = rbd_namespace_create(_ioctx, _name)
2479 raise make_ex(ret, 'error creating namespace')
2481 def namespace_remove(self, ioctx, name):
2483 Remove an RBD namespace from a pool
2485 :param ioctx: determines which RADOS pool
2486 :type ioctx: :class:`rados.Ioctx`
2487 :param name: namespace name
2490 name = cstr(name, 'name')
2492 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2493 const char *_name = name
2495 ret = rbd_namespace_remove(_ioctx, _name)
2497 raise make_ex(ret, 'error removing namespace')
2499 def namespace_exists(self, ioctx, name):
2501 Verifies if a namespace exists within a pool
2503 :param ioctx: determines which RADOS pool
2504 :type ioctx: :class:`rados.Ioctx`
2505 :param name: namespace name
2507 :returns: bool - true if namespace exists
2509 name = cstr(name, 'name')
2511 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2512 const char *_name = name
2513 bint _exists = False
2515 ret = rbd_namespace_exists(_ioctx, _name, &_exists)
2517 raise make_ex(ret, 'error verifying namespace')
2518 return bool(_exists != 0)
2520 def namespace_list(self, ioctx):
2522 List all namespaces within a pool
2524 :param ioctx: determines which RADOS pool
2525 :type ioctx: :class:`rados.Ioctx`
2526 :returns: list - collection of namespace names
2529 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2534 _names = <char *>realloc_chk(_names, _size)
2536 ret = rbd_namespace_list(_ioctx, _names, &_size)
2539 elif ret != -errno.ERANGE:
2540 raise make_ex(ret, 'error listing namespaces')
2541 return [decode_cstr(name) for name in _names[:_size].split(b'\0')
2546 def pool_init(self, ioctx, force):
2548 Initialize an RBD pool
2549 :param ioctx: determines which RADOS pool
2550 :type ioctx: :class:`rados.Ioctx`
2551 :param force: force init
2555 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2558 ret = rbd_pool_init(_ioctx, _force)
2560 raise make_ex(ret, 'error initializing pool')
2562 def pool_stats_get(self, ioctx):
2564 Return RBD pool stats
2566 :param ioctx: determines which RADOS pool
2567 :type ioctx: :class:`rados.Ioctx`
2568 :returns: dict - contains the following keys:
2570 * ``image_count`` (int) - image count
2572 * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
2574 * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
2576 * ``image_snap_count`` (int) - image snap count
2578 * ``trash_count`` (int) - trash image count
2580 * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
2582 * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
2584 * ``trash_snap_count`` (int) - trash snap count
2588 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2589 uint64_t _image_count = 0
2590 uint64_t _image_provisioned_bytes = 0
2591 uint64_t _image_max_provisioned_bytes = 0
2592 uint64_t _image_snap_count = 0
2593 uint64_t _trash_count = 0
2594 uint64_t _trash_provisioned_bytes = 0
2595 uint64_t _trash_max_provisioned_bytes = 0
2596 uint64_t _trash_snap_count = 0
2597 rbd_pool_stats_t _stats
2599 rbd_pool_stats_create(&_stats)
2600 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
2602 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
2603 &_image_provisioned_bytes)
2604 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
2605 &_image_max_provisioned_bytes)
2606 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
2608 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
2610 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
2611 &_trash_provisioned_bytes)
2612 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
2613 &_trash_max_provisioned_bytes)
2614 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
2618 ret = rbd_pool_stats_get(_ioctx, _stats)
2620 raise make_ex(ret, 'error retrieving pool stats')
2622 return {'image_count': _image_count,
2623 'image_provisioned_bytes': _image_provisioned_bytes,
2624 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
2625 'image_snap_count': _image_snap_count,
2626 'trash_count': _trash_count,
2627 'trash_provisioned_bytes': _trash_provisioned_bytes,
2628 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
2629 'trash_snap_count': _trash_snap_count}
2631 rbd_pool_stats_destroy(_stats)
2633 def features_to_string(self, features):
2635 Convert features bitmask to str.
2637 :param features: feature bitmask
2639 :returns: str - the features str of the image
2640 :raises: :class:`InvalidArgument`
2643 int ret = -errno.ERANGE
2644 uint64_t _features = features
2646 char *str_features = NULL
2648 while ret == -errno.ERANGE:
2649 str_features = <char *>realloc_chk(str_features, size)
2651 ret = rbd_features_to_string(_features, str_features, &size)
2654 raise make_ex(ret, 'error converting features bitmask to str')
2655 return decode_cstr(str_features)
2659 def features_from_string(self, str_features):
2661 Get features bitmask from str, if str_features is empty, it will return
2662 RBD_FEATURES_DEFAULT.
2664 :param str_features: feature str
2665 :type str_features: str
2666 :returns: int - the features bitmask of the image
2667 :raises: :class:`InvalidArgument`
2669 str_features = cstr(str_features, 'str_features')
2671 const char *_str_features = str_features
2674 ret = rbd_features_from_string(_str_features, &features)
2676 raise make_ex(ret, 'error getting features bitmask from str')
2680 cdef class MirrorPeerIterator(object):
2682 Iterator over mirror peer info for a pool.
2684 Yields a dictionary containing information about a peer.
2688 * ``uuid`` (str) - uuid of the peer
2690 * ``direction`` (int) - direction enum
2692 * ``site_name`` (str) - cluster name of the peer
2694 * ``mirror_uuid`` (str) - mirror uuid of the peer
2696 * ``client_name`` (str) - client name of the peer
2700 rbd_mirror_peer_site_t *peers
2703 def __init__(self, ioctx):
2705 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2709 self.peers = <rbd_mirror_peer_site_t *>realloc_chk(
2710 self.peers, self.num_peers * sizeof(rbd_mirror_peer_site_t))
2712 ret = rbd_mirror_peer_site_list(_ioctx, self.peers,
2715 if ret == -errno.ERANGE:
2718 raise make_ex(ret, 'error listing peers')
2722 for i in range(self.num_peers):
2724 'uuid' : decode_cstr(self.peers[i].uuid),
2725 'direction' : int(self.peers[i].direction),
2726 'site_name' : decode_cstr(self.peers[i].site_name),
2727 'cluster_name' : decode_cstr(self.peers[i].site_name),
2728 'mirror_uuid' : decode_cstr(self.peers[i].mirror_uuid),
2729 'client_name' : decode_cstr(self.peers[i].client_name),
2732 def __dealloc__(self):
2734 rbd_mirror_peer_site_list_cleanup(self.peers, self.num_peers)
2737 cdef class MirrorImageStatusIterator(object):
2739 Iterator over mirror image status for a pool.
2741 Yields a dictionary containing mirror status of an image.
2745 * ``name`` (str) - mirror image name
2747 * ``id`` (str) - mirror image id
2749 * ``info`` (dict) - mirror image info
2751 * ``state`` (int) - status mirror state
2753 * ``description`` (str) - status description
2755 * ``last_update`` (datetime) - last status update time
2757 * ``up`` (bool) - is mirroring agent up
2759 * ``remote_statuses`` (array) -
2761 * ``mirror uuid`` (str) - remote mirror uuid
2763 * ``state`` (int) - status mirror state
2765 * ``description`` (str) - status description
2767 * ``last_update`` (datetime) - last status update time
2769 * ``up`` (bool) - is mirroring agent up
2777 rbd_mirror_image_site_status_t *s_status
2778 rbd_mirror_image_global_status_t *images
2781 def __init__(self, ioctx):
2782 self.ioctx = convert_ioctx(ioctx)
2783 self.max_read = 1024
2784 self.last_read = strdup("")
2785 self.image_ids = <char **>realloc_chk(NULL,
2786 sizeof(char *) * self.max_read)
2787 self.images = <rbd_mirror_image_global_status_t *>realloc_chk(NULL,
2788 sizeof(rbd_mirror_image_global_status_t) * self.max_read)
2790 self.get_next_chunk()
2794 while self.size > 0:
2795 for i in range(self.size):
2799 for x in range(self.images[i].site_statuses_count):
2800 s_status = &self.images[i].site_statuses[x]
2802 'state' : s_status.state,
2803 'description' : decode_cstr(s_status.description),
2804 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
2807 mirror_uuid = decode_cstr(s_status.mirror_uuid)
2808 if mirror_uuid == '':
2809 local_status = site_status
2811 site_status['mirror_uuid'] = mirror_uuid
2812 site_statuses += site_status
2815 'name' : decode_cstr(self.images[i].name),
2816 'id' : decode_cstr(self.image_ids[i]),
2818 'global_id' : decode_cstr(self.images[i].info.global_id),
2819 'state' : self.images[i].info.state,
2821 'remote_statuses': site_statuses,
2824 status.update(local_status)
2826 if self.size < self.max_read:
2828 self.get_next_chunk()
2830 def __dealloc__(self):
2831 rbd_mirror_image_global_status_list_cleanup(self.image_ids, self.images,
2834 free(self.last_read)
2836 free(self.image_ids)
2840 def get_next_chunk(self):
2842 rbd_mirror_image_global_status_list_cleanup(self.image_ids,
2847 ret = rbd_mirror_image_global_status_list(self.ioctx,
2851 self.images, &self.size)
2853 raise make_ex(ret, 'error listing mirror images status')
2855 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2856 free(self.last_read)
2857 self.last_read = strdup(last_read)
2859 free(self.last_read)
2860 self.last_read = strdup("")
2862 cdef class MirrorImageInstanceIdIterator(object):
2864 Iterator over mirror image instance id for a pool.
2866 Yields ``(image_id, instance_id)`` tuple.
2877 def __init__(self, ioctx):
2878 self.ioctx = convert_ioctx(ioctx)
2879 self.max_read = 1024
2880 self.last_read = strdup("")
2881 self.image_ids = <char **>realloc_chk(NULL,
2882 sizeof(char *) * self.max_read)
2883 self.instance_ids = <char **>realloc_chk(NULL,
2884 sizeof(char *) * self.max_read)
2886 self.get_next_chunk()
2889 while self.size > 0:
2890 for i in range(self.size):
2891 yield (decode_cstr(self.image_ids[i]),
2892 decode_cstr(self.instance_ids[i]))
2893 if self.size < self.max_read:
2895 self.get_next_chunk()
2897 def __dealloc__(self):
2898 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2899 self.instance_ids, self.size)
2901 free(self.last_read)
2903 free(self.image_ids)
2904 if self.instance_ids:
2905 free(self.instance_ids)
2907 def get_next_chunk(self):
2909 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2914 ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read,
2920 raise make_ex(ret, 'error listing mirror images instance ids')
2922 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2923 free(self.last_read)
2924 self.last_read = strdup(last_read)
2926 free(self.last_read)
2927 self.last_read = strdup("")
2929 cdef class MirrorImageInfoIterator(object):
2931 Iterator over mirror image info for a pool.
2933 Yields ``(image_id, info)`` tuple.
2938 rbd_mirror_image_mode_t mode_filter
2939 rbd_mirror_image_mode_t *mode_filter_ptr
2943 rbd_mirror_image_info_t *info_entries
2944 rbd_mirror_image_mode_t *mode_entries
2947 def __init__(self, ioctx, mode_filter):
2948 self.ioctx = convert_ioctx(ioctx)
2949 if mode_filter is not None:
2950 self.mode_filter = mode_filter
2951 self.mode_filter_ptr = &self.mode_filter
2953 self.mode_filter_ptr = NULL
2954 self.max_read = 1024
2955 self.last_read = strdup("")
2956 self.image_ids = <char **>realloc_chk(NULL,
2957 sizeof(char *) * self.max_read)
2958 self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
2959 sizeof(rbd_mirror_image_info_t) * self.max_read)
2960 self.mode_entries = <rbd_mirror_image_mode_t *>realloc_chk(NULL,
2961 sizeof(rbd_mirror_image_mode_t) * self.max_read)
2963 self.get_next_chunk()
2966 while self.size > 0:
2967 for i in range(self.size):
2968 yield (decode_cstr(self.image_ids[i]),
2970 'mode' : int(self.mode_entries[i]),
2971 'global_id' : decode_cstr(self.info_entries[i].global_id),
2972 'state' : int(self.info_entries[i].state),
2973 'primary' : self.info_entries[i].primary,
2975 if self.size < self.max_read:
2977 self.get_next_chunk()
2979 def __dealloc__(self):
2980 rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries,
2983 free(self.last_read)
2985 free(self.image_ids)
2986 if self.info_entries:
2987 free(self.info_entries)
2988 if self.mode_entries:
2989 free(self.mode_entries)
2991 def get_next_chunk(self):
2993 rbd_mirror_image_info_list_cleanup(self.image_ids,
2994 self.info_entries, self.size)
2997 ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr,
2998 self.last_read, self.max_read,
2999 self.image_ids, self.mode_entries,
3000 self.info_entries, &self.size)
3002 raise make_ex(ret, 'error listing mirror image info')
3004 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
3005 free(self.last_read)
3006 self.last_read = strdup(last_read)
3008 free(self.last_read)
3009 self.last_read = strdup("")
3011 cdef class PoolMetadataIterator(object):
3013 Iterator over pool metadata list.
3015 Yields ``(key, value)`` tuple.
3017 * ``key`` (str) - metadata key
3018 * ``value`` (str) - metadata value
3027 def __init__(self, ioctx):
3028 self.ioctx = convert_ioctx(ioctx)
3029 self.last_read = strdup("")
3031 self.get_next_chunk()
3034 while len(self.next_chunk) > 0:
3035 for pair in self.next_chunk:
3037 if len(self.next_chunk) < self.max_read:
3039 self.get_next_chunk()
3041 def __dealloc__(self):
3043 free(self.last_read)
3045 def get_next_chunk(self):
3048 size_t keys_size = 4096
3050 size_t vals_size = 4096
3053 c_keys = <char *>realloc_chk(c_keys, keys_size)
3054 c_vals = <char *>realloc_chk(c_vals, vals_size)
3056 ret = rbd_pool_metadata_list(self.ioctx, self.last_read,
3057 self.max_read, c_keys,
3058 &keys_size, c_vals, &vals_size)
3061 elif ret != -errno.ERANGE:
3062 raise make_ex(ret, 'error listing metadata')
3063 keys = [decode_cstr(key) for key in
3064 c_keys[:keys_size].split(b'\0') if key]
3065 vals = [decode_cstr(val) for val in
3066 c_vals[:vals_size].split(b'\0') if val]
3068 last_read = cstr(keys[-1], 'last_read')
3069 free(self.last_read)
3070 self.last_read = strdup(last_read)
3071 self.next_chunk = list(zip(keys, vals))
3076 cdef class ConfigPoolIterator(object):
3078 Iterator over pool-level overrides for a pool.
3080 Yields a dictionary containing information about an override.
3084 * ``name`` (str) - override name
3086 * ``value`` (str) - override value
3088 * ``source`` (str) - override source
3092 rbd_config_option_t *options
3095 def __init__(self, ioctx):
3097 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3099 self.num_options = 32
3101 self.options = <rbd_config_option_t *>realloc_chk(
3102 self.options, self.num_options * sizeof(rbd_config_option_t))
3104 ret = rbd_config_pool_list(_ioctx, self.options, &self.num_options)
3106 if ret == -errno.ERANGE:
3108 self.num_options = 0
3109 raise make_ex(ret, 'error listing config options')
3113 for i in range(self.num_options):
3115 'name' : decode_cstr(self.options[i].name),
3116 'value' : decode_cstr(self.options[i].value),
3117 'source' : self.options[i].source,
3120 def __dealloc__(self):
3122 rbd_config_pool_list_cleanup(self.options, self.num_options)
3125 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
3126 except? -9000 with gil:
3127 # Make sure that if we wound up with an exception from a previous callback,
3128 # we stop calling back (just in case librbd ever fails to bail out on the
3129 # first negative return, as older versions did)
3130 if exc.PyErr_Occurred():
3132 ret = (<object>cb)(offset, length, bool(write))
3137 cdef class Group(object):
3139 This class represents an RBD group. It is used to interact with
3140 snapshots and images members.
3147 cdef rados_ioctx_t _ioctx
3149 def __init__(self, ioctx, name):
3150 name = cstr(name, 'name')
3153 self._ioctx = convert_ioctx(ioctx)
3156 def __enter__(self):
3159 def __exit__(self, type_, value, traceback):
3162 def add_image(self, image_ioctx, image_name):
3164 Add an image to a group.
3166 :param image_ioctx: determines which RADOS pool the image belongs to.
3167 :type ioctx: :class:`rados.Ioctx`
3168 :param name: the name of the image to add
3171 :raises: :class:`ObjectNotFound`
3172 :raises: :class:`ObjectExists`
3173 :raises: :class:`InvalidArgument`
3174 :raises: :class:`FunctionNotSupported`
3176 image_name = cstr(image_name, 'image_name')
3178 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3179 char *_image_name = image_name
3181 ret = rbd_group_image_add(self._ioctx, self._name, _image_ioctx, _image_name)
3183 raise make_ex(ret, 'error adding image to group', group_errno_to_exception)
3185 def remove_image(self, image_ioctx, image_name):
3187 Remove an image from a group.
3189 :param image_ioctx: determines which RADOS pool the image belongs to.
3190 :type ioctx: :class:`rados.Ioctx`
3191 :param name: the name of the image to remove
3194 :raises: :class:`ObjectNotFound`
3195 :raises: :class:`InvalidArgument`
3196 :raises: :class:`FunctionNotSupported`
3198 image_name = cstr(image_name, 'image_name')
3200 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3201 char *_image_name = image_name
3203 ret = rbd_group_image_remove(self._ioctx, self._name, _image_ioctx, _image_name)
3205 raise make_ex(ret, 'error removing image from group', group_errno_to_exception)
3208 def list_images(self):
3210 Iterate over the images of a group.
3212 :returns: :class:`GroupImageIterator`
3214 return GroupImageIterator(self)
3216 def create_snap(self, snap_name):
3218 Create a snapshot for the group.
3220 :param snap_name: the name of the snapshot to create
3223 :raises: :class:`ObjectNotFound`
3224 :raises: :class:`ObjectExists`
3225 :raises: :class:`InvalidArgument`
3226 :raises: :class:`FunctionNotSupported`
3228 snap_name = cstr(snap_name, 'snap_name')
3230 char *_snap_name = snap_name
3232 ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
3234 raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
3236 def remove_snap(self, snap_name):
3238 Remove a snapshot from the group.
3240 :param snap_name: the name of the snapshot to remove
3243 :raises: :class:`ObjectNotFound`
3244 :raises: :class:`InvalidArgument`
3245 :raises: :class:`FunctionNotSupported`
3247 snap_name = cstr(snap_name, 'snap_name')
3249 char *_snap_name = snap_name
3251 ret = rbd_group_snap_remove(self._ioctx, self._name, _snap_name)
3253 raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
3255 def rename_snap(self, old_snap_name, new_snap_name):
3257 Rename group's snapshot.
3259 :raises: :class:`ObjectNotFound`
3260 :raises: :class:`ObjectExists`
3261 :raises: :class:`InvalidArgument`
3262 :raises: :class:`FunctionNotSupported`
3265 old_snap_name = cstr(old_snap_name, 'old_snap_name')
3266 new_snap_name = cstr(new_snap_name, 'new_snap_name')
3268 char *_old_snap_name = old_snap_name
3269 char *_new_snap_name = new_snap_name
3271 ret = rbd_group_snap_rename(self._ioctx, self._name, _old_snap_name,
3274 raise make_ex(ret, 'error renaming group snapshot',
3275 group_errno_to_exception)
3277 def list_snaps(self):
3279 Iterate over the images of a group.
3281 :returns: :class:`GroupSnapIterator`
3283 return GroupSnapIterator(self)
3285 def rollback_to_snap(self, name):
3287 Rollback group to snapshot.
3289 :param name: the group snapshot to rollback to
3291 :raises: :class:`ObjectNotFound`
3292 :raises: :class:`IOError`
3294 name = cstr(name, 'name')
3295 cdef char *_name = name
3297 ret = rbd_group_snap_rollback(self._ioctx, self._name, _name)
3299 raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
3301 def requires_not_closed(f):
3302 def wrapper(self, *args, **kwargs):
3303 self.require_not_closed()
3304 return f(self, *args, **kwargs)
3308 cdef class Image(object):
3310 This class represents an RBD image. It is used to perform I/O on
3311 the image and interact with snapshots.
3313 **Note**: Any method of this class may raise :class:`ImageNotFound`
3314 if the image has been deleted.
3316 cdef rbd_image_t image
3320 cdef rados_ioctx_t _ioctx
3322 def __init__(self, ioctx, name=None, snapshot=None,
3323 read_only=False, image_id=None):
3325 Open the image at the given snapshot.
3326 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
3328 If a snapshot is specified, the image will be read-only, unless
3329 :func:`Image.set_snap` is called later.
3331 If read-only mode is used, metadata for the :class:`Image`
3332 object (such as which snapshots exist) may become obsolete. See
3333 the C api for more details.
3335 To clean up from opening the image, :func:`Image.close` should
3336 be called. For ease of use, this is done automatically when
3337 an :class:`Image` is used as a context manager (see :pep:`343`).
3339 :param ioctx: determines which RADOS pool the image is in
3340 :type ioctx: :class:`rados.Ioctx`
3341 :param name: the name of the image
3343 :param snapshot: which snapshot to read from
3344 :type snaphshot: str
3345 :param read_only: whether to open the image in read-only mode
3346 :type read_only: bool
3347 :param image_id: the id of the image
3350 name = cstr(name, 'name', opt=True)
3351 image_id = cstr(image_id, 'image_id', opt=True)
3352 snapshot = cstr(snapshot, 'snapshot', opt=True)
3354 if name is not None and image_id is not None:
3355 raise InvalidArgument("only need to specify image name or image id")
3356 elif name is None and image_id is None:
3357 raise InvalidArgument("image name or image id was not specified")
3358 elif name is not None:
3361 self.name = image_id
3362 # Keep around a reference to the ioctx, so it won't get deleted
3365 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3366 char *_name = opt_str(name)
3367 char *_image_id = opt_str(image_id)
3368 char *_snapshot = opt_str(snapshot)
3371 if name is not None:
3372 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
3374 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
3377 if name is not None:
3378 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
3380 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
3382 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
3385 self.name = self.get_name()
3387 def __enter__(self):
3390 def __exit__(self, type_, value, traceback):
3392 Closes the image. See :func:`close`
3397 def __get_completion(self, oncomplete):
3399 Constructs a completion to use with asynchronous operations
3401 :param oncomplete: callback for the completion
3403 :raises: :class:`Error`
3404 :returns: completion object
3407 completion_obj = Completion(self, oncomplete)
3410 rbd_completion_t completion
3411 PyObject* p_completion_obj= <PyObject*>completion_obj
3414 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
3417 raise make_ex(ret, "error getting a completion")
3419 completion_obj.rbd_comp = completion
3420 return completion_obj
3422 def require_not_closed(self):
3424 Checks if the Image is not closed
3426 :raises: :class:`InvalidArgument`
3429 raise InvalidArgument("image is closed")
3433 Release the resources used by this image object.
3435 After this is called, this object should not be used.
3440 ret = rbd_close(self.image)
3442 raise make_ex(ret, 'error while closing image %s' % (
3445 def __dealloc__(self):
3449 return "rbd.Image(ioctx, %r)" % self.name
3451 @requires_not_closed
3452 def resize(self, size, allow_shrink=True):
3454 Change the size of the image, allow shrink.
3456 :param size: the new size of the image
3458 :param allow_shrink: permit shrinking
3459 :type allow_shrink: bool
3461 old_size = self.size()
3462 if old_size == size:
3464 if not allow_shrink and old_size > size:
3465 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
3467 uint64_t _size = size
3468 bint _allow_shrink = allow_shrink
3469 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3471 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
3473 raise make_ex(ret, 'error resizing image %s' % self.name)
3475 @requires_not_closed
3478 Get information about the image. Currently parent pool and
3479 parent name are always -1 and ''.
3481 :returns: dict - contains the following keys:
3483 * ``size`` (int) - the size of the image in bytes
3485 * ``obj_size`` (int) - the size of each object that comprises the
3488 * ``num_objs`` (int) - the number of objects in the image
3490 * ``order`` (int) - log_2(object_size)
3492 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
3495 * ``parent_pool`` (int) - deprecated
3497 * ``parent_name`` (str) - deprecated
3499 See also :meth:`format` and :meth:`features`.
3502 cdef rbd_image_info_t info
3504 ret = rbd_stat(self.image, &info, sizeof(info))
3506 raise make_ex(ret, 'error getting info for image %s' % self.name)
3509 'obj_size' : info.obj_size,
3510 'num_objs' : info.num_objs,
3511 'order' : info.order,
3512 'block_name_prefix' : decode_cstr(info.block_name_prefix),
3513 'parent_pool' : info.parent_pool,
3514 'parent_name' : info.parent_name
3517 @requires_not_closed
3520 Get the RBD image name
3522 :returns: str - image name
3525 int ret = -errno.ERANGE
3527 char *image_name = NULL
3529 while ret == -errno.ERANGE:
3530 image_name = <char *>realloc_chk(image_name, size)
3532 ret = rbd_get_name(self.image, image_name, &size)
3535 raise make_ex(ret, 'error getting name for image %s' % self.name)
3536 return decode_cstr(image_name)
3540 @requires_not_closed
3543 Get the RBD v2 internal image id
3545 :returns: str - image id
3548 int ret = -errno.ERANGE
3550 char *image_id = NULL
3552 while ret == -errno.ERANGE and size <= 4096:
3553 image_id = <char *>realloc_chk(image_id, size)
3555 ret = rbd_get_id(self.image, image_id, size)
3556 if ret == -errno.ERANGE:
3560 raise make_ex(ret, 'error getting id for image %s' % self.name)
3561 return decode_cstr(image_id)
3565 @requires_not_closed
3566 def block_name_prefix(self):
3568 Get the RBD block name prefix
3570 :returns: str - block name prefix
3573 int ret = -errno.ERANGE
3577 while ret == -errno.ERANGE and size <= 4096:
3578 prefix = <char *>realloc_chk(prefix, size)
3580 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3581 if ret == -errno.ERANGE:
3585 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3586 return decode_cstr(prefix)
3590 @requires_not_closed
3591 def data_pool_id(self):
3593 Get the pool id of the pool where the data of this RBD image is stored.
3595 :returns: int - the pool id
3597 return rbd_get_data_pool_id(self.image)
3599 @requires_not_closed
3600 def get_parent_image_spec(self):
3602 Get spec of the cloned image's parent
3604 :returns: dict - contains the following keys:
3605 * ``pool_name`` (str) - parent pool name
3606 * ``pool_namespace`` (str) - parent pool namespace
3607 * ``image_name`` (str) - parent image name
3608 * ``snap_name`` (str) - parent snapshot name
3610 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3613 rbd_linked_image_spec_t parent_spec
3614 rbd_snap_spec_t snap_spec
3616 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3618 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3620 result = {'pool_name': decode_cstr(parent_spec.pool_name),
3621 'pool_namespace': decode_cstr(parent_spec.pool_namespace),
3622 'image_name': decode_cstr(parent_spec.image_name),
3623 'snap_name': decode_cstr(snap_spec.name)}
3625 rbd_linked_image_spec_cleanup(&parent_spec)
3626 rbd_snap_spec_cleanup(&snap_spec)
3629 @requires_not_closed
3630 def parent_info(self):
3632 Deprecated. Use `get_parent_image_spec` instead.
3634 Get information about a cloned image's parent (if any)
3636 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3638 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3640 parent = self.get_parent_image_spec()
3641 return (parent['pool_name'], parent['image_name'], parent['snap_name'])
3643 @requires_not_closed
3644 def parent_id(self):
3646 Get image id of a cloned image's parent (if any)
3648 :returns: str - the parent id
3649 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3652 rbd_linked_image_spec_t parent_spec
3653 rbd_snap_spec_t snap_spec
3655 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3657 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3659 result = decode_cstr(parent_spec.image_id)
3661 rbd_linked_image_spec_cleanup(&parent_spec)
3662 rbd_snap_spec_cleanup(&snap_spec)
3665 @requires_not_closed
3666 def old_format(self):
3668 Find out whether the image uses the old RBD format.
3670 :returns: bool - whether the image uses the old RBD format
3674 ret = rbd_get_old_format(self.image, &old)
3676 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3679 @requires_not_closed
3682 Get the size of the image. If open to a snapshot, returns the
3683 size of that snapshot.
3685 :returns: int - the size of the image in bytes
3687 cdef uint64_t image_size
3689 ret = rbd_get_size(self.image, &image_size)
3691 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3694 @requires_not_closed
3697 Get the features bitmask of the image.
3699 :returns: int - the features bitmask of the image
3701 cdef uint64_t features
3703 ret = rbd_get_features(self.image, &features)
3705 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3708 @requires_not_closed
3709 def update_features(self, features, enabled):
3711 Update the features bitmask of the image by enabling/disabling
3712 a single feature. The feature must support the ability to be
3713 dynamically enabled/disabled.
3715 :param features: feature bitmask to enable/disable
3717 :param enabled: whether to enable/disable the feature
3719 :raises: :class:`InvalidArgument`
3722 uint64_t _features = features
3723 uint8_t _enabled = bool(enabled)
3725 ret = rbd_update_features(self.image, _features, _enabled)
3727 raise make_ex(ret, 'error updating features for image %s' %
3730 @requires_not_closed
3731 def op_features(self):
3733 Get the op features bitmask of the image.
3735 :returns: int - the op features bitmask of the image
3737 cdef uint64_t op_features
3739 ret = rbd_get_op_features(self.image, &op_features)
3741 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3744 @requires_not_closed
3747 Get the number of overlapping bytes between the image and its parent
3748 image. If open to a snapshot, returns the overlap between the snapshot
3749 and the parent image.
3751 :returns: int - the overlap in bytes
3752 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3754 cdef uint64_t overlap
3756 ret = rbd_get_overlap(self.image, &overlap)
3758 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3761 @requires_not_closed
3764 Get the flags bitmask of the image.
3766 :returns: int - the flags bitmask of the image
3770 ret = rbd_get_flags(self.image, &flags)
3772 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3775 @requires_not_closed
3778 Get information about the image's group.
3780 :returns: dict - contains the following keys:
3782 * ``pool`` (int) - id of the group pool
3784 * ``name`` (str) - name of the group
3787 cdef rbd_group_info_t info
3789 ret = rbd_get_group(self.image, &info, sizeof(info))
3791 raise make_ex(ret, 'error getting group for image %s' % self.name)
3794 'name' : decode_cstr(info.name)
3796 rbd_group_info_cleanup(&info, sizeof(info))
3799 @requires_not_closed
3800 def is_exclusive_lock_owner(self):
3802 Get the status of the image exclusive lock.
3804 :returns: bool - true if the image is exclusively locked
3808 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3810 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3813 @requires_not_closed
3814 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3815 stripe_unit=None, stripe_count=None, data_pool=None):
3817 Copy the image to another location.
3819 :param dest_ioctx: determines which pool to copy into
3820 :type dest_ioctx: :class:`rados.Ioctx`
3821 :param dest_name: the name of the copy
3822 :type dest_name: str
3823 :param features: bitmask of features to enable; if set, must include layering
3825 :param order: the image is split into (2**order) byte objects
3827 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3828 :type stripe_unit: int
3829 :param stripe_count: objects to stripe over before looping
3830 :type stripe_count: int
3831 :param data_pool: optional separate pool for data blocks
3832 :type data_pool: str
3833 :raises: :class:`TypeError`
3834 :raises: :class:`InvalidArgument`
3835 :raises: :class:`ImageExists`
3836 :raises: :class:`FunctionNotSupported`
3837 :raises: :class:`ArgumentOutOfRange`
3839 dest_name = cstr(dest_name, 'dest_name')
3840 data_pool = cstr(data_pool, 'data_pool', opt=True)
3842 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3843 char *_dest_name = dest_name
3844 rbd_image_options_t opts
3846 rbd_image_options_create(&opts)
3848 if features is not None:
3849 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3851 if order is not None:
3852 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3854 if stripe_unit is not None:
3855 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3857 if stripe_count is not None:
3858 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3860 if data_pool is not None:
3861 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3864 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3866 rbd_image_options_destroy(opts)
3868 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3870 @requires_not_closed
3871 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3872 stripe_unit=None, stripe_count=None, data_pool=None):
3874 Deep copy the image to another location.
3876 :param dest_ioctx: determines which pool to copy into
3877 :type dest_ioctx: :class:`rados.Ioctx`
3878 :param dest_name: the name of the copy
3879 :type dest_name: str
3880 :param features: bitmask of features to enable; if set, must include layering
3882 :param order: the image is split into (2**order) byte objects
3884 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3885 :type stripe_unit: int
3886 :param stripe_count: objects to stripe over before looping
3887 :type stripe_count: int
3888 :param data_pool: optional separate pool for data blocks
3889 :type data_pool: str
3890 :raises: :class:`TypeError`
3891 :raises: :class:`InvalidArgument`
3892 :raises: :class:`ImageExists`
3893 :raises: :class:`FunctionNotSupported`
3894 :raises: :class:`ArgumentOutOfRange`
3896 dest_name = cstr(dest_name, 'dest_name')
3897 data_pool = cstr(data_pool, 'data_pool', opt=True)
3899 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3900 char *_dest_name = dest_name
3901 rbd_image_options_t opts
3903 rbd_image_options_create(&opts)
3905 if features is not None:
3906 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3908 if order is not None:
3909 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3911 if stripe_unit is not None:
3912 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3914 if stripe_count is not None:
3915 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3917 if data_pool is not None:
3918 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3921 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3923 rbd_image_options_destroy(opts)
3925 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3927 @requires_not_closed
3928 def list_snaps(self):
3930 Iterate over the snapshots of an image.
3932 :returns: :class:`SnapIterator`
3934 return SnapIterator(self)
3936 @requires_not_closed
3937 def create_snap(self, name):
3939 Create a snapshot of the image.
3941 :param name: the name of the snapshot
3943 :raises: :class:`ImageExists`
3945 name = cstr(name, 'name')
3946 cdef char *_name = name
3948 ret = rbd_snap_create(self.image, _name)
3950 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3952 @requires_not_closed
3953 def rename_snap(self, srcname, dstname):
3955 rename a snapshot of the image.
3957 :param srcname: the src name of the snapshot
3959 :param dstname: the dst name of the snapshot
3961 :raises: :class:`ImageExists`
3963 srcname = cstr(srcname, 'srcname')
3964 dstname = cstr(dstname, 'dstname')
3966 char *_srcname = srcname
3967 char *_dstname = dstname
3969 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3971 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3973 @requires_not_closed
3974 def remove_snap(self, name):
3976 Delete a snapshot of the image.
3978 :param name: the name of the snapshot
3980 :raises: :class:`IOError`, :class:`ImageBusy`, :class:`ImageNotFound`
3982 name = cstr(name, 'name')
3983 cdef char *_name = name
3985 ret = rbd_snap_remove(self.image, _name)
3987 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3989 @requires_not_closed
3990 def remove_snap2(self, name, flags):
3992 Delete a snapshot of the image.
3994 :param name: the name of the snapshot
3995 :param flags: the flags for removal
3997 :raises: :class:`IOError`, :class:`ImageBusy`
3999 self.require_not_closed()
4001 name = cstr(name, 'name')
4004 uint32_t _flags = flags
4005 librbd_progress_fn_t prog_cb = &no_op_progress_callback
4007 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
4009 raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
4011 @requires_not_closed
4012 def remove_snap_by_id(self, snap_id):
4014 Delete a snapshot of the image by its id.
4016 :param id: the id of the snapshot
4018 :raises: :class:`IOError`, :class:`ImageBusy`
4021 uint64_t _snap_id = snap_id
4023 ret = rbd_snap_remove_by_id(self.image, _snap_id)
4025 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
4027 @requires_not_closed
4028 def rollback_to_snap(self, name):
4030 Revert the image to its contents at a snapshot. This is a
4031 potentially expensive operation, since it rolls back each
4032 object individually.
4034 :param name: the snapshot to rollback to
4036 :raises: :class:`IOError`
4038 name = cstr(name, 'name')
4039 cdef char *_name = name
4041 ret = rbd_snap_rollback(self.image, _name)
4043 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
4045 @requires_not_closed
4046 def protect_snap(self, name):
4048 Mark a snapshot as protected. This means it can't be deleted
4049 until it is unprotected.
4051 :param name: the snapshot to protect
4053 :raises: :class:`IOError`, :class:`ImageNotFound`
4055 name = cstr(name, 'name')
4056 cdef char *_name = name
4058 ret = rbd_snap_protect(self.image, _name)
4060 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
4062 @requires_not_closed
4063 def unprotect_snap(self, name):
4065 Mark a snapshot unprotected. This allows it to be deleted if
4068 :param name: the snapshot to unprotect
4070 :raises: :class:`IOError`, :class:`ImageNotFound`
4072 name = cstr(name, 'name')
4073 cdef char *_name = name
4075 ret = rbd_snap_unprotect(self.image, _name)
4077 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
4079 @requires_not_closed
4080 def is_protected_snap(self, name):
4082 Find out whether a snapshot is protected from deletion.
4084 :param name: the snapshot to check
4086 :returns: bool - whether the snapshot is protected
4087 :raises: :class:`IOError`, :class:`ImageNotFound`
4089 name = cstr(name, 'name')
4094 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
4096 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
4097 return is_protected == 1
4099 @requires_not_closed
4100 def snap_exists(self, name):
4102 Find out whether a snapshot is exists.
4104 :param name: the snapshot to check
4106 :returns: bool - whether the snapshot is exists
4108 name = cstr(name, 'name')
4111 bint _exists = False
4113 ret = rbd_snap_exists(self.image, _name, &_exists)
4115 raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
4116 return bool(_exists != 0)
4118 @requires_not_closed
4119 def get_snap_limit(self):
4121 Get the snapshot limit for an image.
4123 :returns: int - the snapshot limit for an image
4128 ret = rbd_snap_get_limit(self.image, &limit)
4130 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
4133 @requires_not_closed
4134 def set_snap_limit(self, limit):
4136 Set the snapshot limit for an image.
4138 :param limit: the new limit to set
4141 uint64_t _limit = limit
4143 ret = rbd_snap_set_limit(self.image, _limit)
4145 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
4148 @requires_not_closed
4149 def get_snap_timestamp(self, snap_id):
4151 Get the snapshot timestamp for an image.
4152 :param snap_id: the snapshot id of a snap shot
4153 :returns: datetime - the snapshot timestamp for an image
4157 uint64_t _snap_id = snap_id
4159 ret = rbd_snap_get_timestamp(self.image, _snap_id, ×tamp)
4161 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
4162 return datetime.utcfromtimestamp(timestamp.tv_sec)
4164 @requires_not_closed
4165 def remove_snap_limit(self):
4167 Remove the snapshot limit for an image, essentially setting
4168 the limit to the maximum size allowed by the implementation.
4171 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
4173 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
4176 @requires_not_closed
4177 def set_snap(self, name):
4179 Set the snapshot to read from. Writes will raise ReadOnlyImage
4180 while a snapshot is set. Pass None to unset the snapshot
4181 (reads come from the current image) , and allow writing again.
4183 :param name: the snapshot to read from, or None to unset the snapshot
4184 :type name: str or None
4186 name = cstr(name, 'name', opt=True)
4187 cdef char *_name = opt_str(name)
4189 ret = rbd_snap_set(self.image, _name)
4191 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
4193 @requires_not_closed
4194 def set_snap_by_id(self, snap_id):
4196 Set the snapshot to read from. Writes will raise ReadOnlyImage
4197 while a snapshot is set. Pass None to unset the snapshot
4198 (reads come from the current image) , and allow writing again.
4200 :param snap_id: the snapshot to read from, or None to unset the snapshot
4204 snap_id = _LIBRADOS_SNAP_HEAD
4205 cdef int64_t _snap_id = snap_id
4207 ret = rbd_snap_set_by_id(self.image, _snap_id)
4209 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
4211 @requires_not_closed
4212 def snap_get_name(self, snap_id):
4214 Get snapshot name by id.
4216 :param snap_id: the snapshot id
4218 :returns: str - snapshot name
4219 :raises: :class:`ImageNotFound`
4222 int ret = -errno.ERANGE
4223 int64_t _snap_id = snap_id
4225 char *image_name = NULL
4227 while ret == -errno.ERANGE:
4228 image_name = <char *>realloc_chk(image_name, size)
4230 ret = rbd_snap_get_name(self.image, _snap_id, image_name, &size)
4233 raise make_ex(ret, 'error snap_get_name.')
4234 return decode_cstr(image_name)
4238 @requires_not_closed
4239 def snap_get_id(self, snap_name):
4241 Get snapshot id by name.
4243 :param snap_name: the snapshot name
4244 :type snap_name: str
4245 :returns: int - snapshot id
4246 :raises: :class:`ImageNotFound`
4248 snap_name = cstr(snap_name, 'snap_name')
4250 const char *_snap_name = snap_name
4253 ret = rbd_snap_get_id(self.image, _snap_name, &snap_id)
4255 raise make_ex(ret, 'error snap_get_id.')
4258 @requires_not_closed
4259 def read(self, offset, length, fadvise_flags=0):
4261 Read data from the image. Raises :class:`InvalidArgument` if
4262 part of the range specified is outside the image.
4264 :param offset: the offset to start reading at
4266 :param length: how many bytes to read
4268 :param fadvise_flags: fadvise flags for this read
4269 :type fadvise_flags: int
4270 :returns: str - the data read
4271 :raises: :class:`InvalidArgument`, :class:`IOError`
4274 # This usage of the Python API allows us to construct a string
4275 # that librbd directly reads into, avoiding an extra copy. Although
4276 # strings are normally immutable, this usage is explicitly supported
4277 # for freshly created string objects.
4280 uint64_t _offset = offset
4281 size_t _length = length
4282 int _fadvise_flags = fadvise_flags
4283 PyObject* ret_s = NULL
4284 ret_s = PyBytes_FromStringAndSize(NULL, length)
4286 ret_buf = PyBytes_AsString(ret_s)
4288 ret = rbd_read2(self.image, _offset, _length, ret_buf,
4291 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
4293 if ret != <ssize_t>length:
4294 _PyBytes_Resize(&ret_s, ret)
4296 return <object>ret_s
4298 # We DECREF unconditionally: the cast to object above will have
4299 # INCREFed if necessary. This also takes care of exceptions,
4300 # including if _PyString_Resize fails (that will free the string
4301 # itself and set ret_s to NULL, hence XDECREF).
4302 ref.Py_XDECREF(ret_s)
4304 @requires_not_closed
4305 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
4306 include_parent = True, whole_object = False):
4308 Iterate over the changed extents of an image.
4310 This will call iterate_cb with three arguments:
4312 (offset, length, exists)
4314 where the changed extent starts at offset bytes, continues for
4315 length bytes, and is full of data (if exists is True) or zeroes
4316 (if exists is False).
4318 If from_snapshot is None, it is interpreted as the beginning
4319 of time and this generates all allocated extents.
4321 The end version is whatever is currently selected (via set_snap)
4324 iterate_cb may raise an exception, which will abort the diff and will be
4325 propagated to the caller.
4327 Raises :class:`InvalidArgument` if from_snapshot is after
4328 the currently set snapshot.
4330 Raises :class:`ImageNotFound` if from_snapshot is not the name
4331 of a snapshot of the image.
4333 :param offset: start offset in bytes
4335 :param length: size of region to report on, in bytes
4337 :param from_snapshot: starting snapshot name, or None
4338 :type from_snapshot: str or None
4339 :param iterate_cb: function to call for each extent
4340 :type iterate_cb: function acception arguments for offset,
4342 :param include_parent: True if full history diff should include parent
4343 :type include_parent: bool
4344 :param whole_object: True if diff extents should cover whole object
4345 :type whole_object: bool
4346 :raises: :class:`InvalidArgument`, :class:`IOError`,
4347 :class:`ImageNotFound`
4349 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
4351 char *_from_snapshot = opt_str(from_snapshot)
4352 uint64_t _offset = offset, _length = length
4353 uint8_t _include_parent = include_parent
4354 uint8_t _whole_object = whole_object
4356 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
4357 _length, _include_parent, _whole_object,
4358 &diff_iterate_cb, <void *>iterate_cb)
4360 msg = 'error generating diff from snapshot %s' % from_snapshot
4361 raise make_ex(ret, msg)
4363 @requires_not_closed
4364 def write(self, data, offset, fadvise_flags=0):
4366 Write data to the image. Raises :class:`InvalidArgument` if
4367 part of the write would fall outside the image.
4369 :param data: the data to be written
4371 :param offset: where to start writing data
4373 :param fadvise_flags: fadvise flags for this write
4374 :type fadvise_flags: int
4375 :returns: int - the number of bytes written
4376 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
4377 :class:`InvalidArgument`, :class:`IOError`
4379 if not isinstance(data, bytes):
4380 raise TypeError('data must be a byte string')
4382 uint64_t _offset = offset, length = len(data)
4384 int _fadvise_flags = fadvise_flags
4386 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
4388 if ret == <ssize_t>length:
4391 raise make_ex(ret, "error writing to %s" % self.name)
4392 elif ret < <ssize_t>length:
4393 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
4395 raise LogicError("logic error: rbd_write(%s) \
4396 returned %d, but %d was the maximum number of bytes it could have \
4397 written." % (self.name, ret, length))
4399 @requires_not_closed
4400 def discard(self, offset, length):
4402 Trim the range from the image. It will be logically filled
4405 cdef uint64_t _offset = offset, _length = length
4407 ret = rbd_discard(self.image, _offset, _length)
4409 msg = 'error discarding region %d~%d' % (offset, length)
4410 raise make_ex(ret, msg)
4412 @requires_not_closed
4413 def write_zeroes(self, offset, length, zero_flags = 0):
4415 Zero the range from the image. By default it will attempt to
4416 discard/unmap as much space as possible but any unaligned
4417 extent segments will still be zeroed.
4420 uint64_t _offset = offset, _length = length
4421 int _zero_flags = zero_flags
4423 ret = rbd_write_zeroes(self.image, _offset, _length,
4426 msg = 'error zeroing region %d~%d' % (offset, length)
4427 raise make_ex(ret, msg)
4429 @requires_not_closed
4432 Block until all writes are fully flushed if caching is enabled.
4435 ret = rbd_flush(self.image)
4437 raise make_ex(ret, 'error flushing image')
4439 @requires_not_closed
4440 def invalidate_cache(self):
4442 Drop any cached data for the image.
4445 ret = rbd_invalidate_cache(self.image)
4447 raise make_ex(ret, 'error invalidating cache')
4449 @requires_not_closed
4450 def stripe_unit(self):
4452 Return the stripe unit used for the image.
4454 cdef uint64_t stripe_unit
4456 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
4458 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
4461 @requires_not_closed
4462 def stripe_count(self):
4464 Return the stripe count used for the image.
4466 cdef uint64_t stripe_count
4468 ret = rbd_get_stripe_count(self.image, &stripe_count)
4470 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
4473 @requires_not_closed
4474 def create_timestamp(self):
4476 Return the create timestamp for the image.
4481 ret = rbd_get_create_timestamp(self.image, ×tamp)
4483 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
4484 return datetime.utcfromtimestamp(timestamp.tv_sec)
4486 @requires_not_closed
4487 def access_timestamp(self):
4489 Return the access timestamp for the image.
4494 ret = rbd_get_access_timestamp(self.image, ×tamp)
4496 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
4497 return datetime.fromtimestamp(timestamp.tv_sec)
4499 @requires_not_closed
4500 def modify_timestamp(self):
4502 Return the modify timestamp for the image.
4507 ret = rbd_get_modify_timestamp(self.image, ×tamp)
4509 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
4510 return datetime.fromtimestamp(timestamp.tv_sec)
4512 @requires_not_closed
4513 def flatten(self, on_progress=None):
4515 Flatten clone image (copy all blocks from parent to child)
4516 :param on_progress: optional progress callback function
4517 :type on_progress: callback function
4520 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
4521 void *_prog_arg = NULL
4523 _prog_cb = &progress_callback
4524 _prog_arg = <void *>on_progress
4526 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
4528 raise make_ex(ret, "error flattening %s" % self.name)
4530 @requires_not_closed
4531 def sparsify(self, sparse_size):
4533 Reclaim space for zeroed image extents
4536 size_t _sparse_size = sparse_size
4538 ret = rbd_sparsify(self.image, _sparse_size)
4540 raise make_ex(ret, "error sparsifying %s" % self.name)
4542 @requires_not_closed
4543 def rebuild_object_map(self):
4545 Rebuild the object map for the image HEAD or currently set snapshot
4547 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
4549 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
4551 raise make_ex(ret, "error rebuilding object map %s" % self.name)
4553 @requires_not_closed
4554 def list_children(self):
4556 List children of the currently set snapshot (set via set_snap()).
4558 :returns: list - a list of (pool name, image name) tuples
4561 rbd_linked_image_spec_t *children = NULL
4562 size_t num_children = 10
4566 children = <rbd_linked_image_spec_t*>realloc_chk(
4567 children, num_children * sizeof(rbd_linked_image_spec_t))
4569 ret = rbd_list_children3(self.image, children,
4573 elif ret != -errno.ERANGE:
4574 raise make_ex(ret, 'error listing children.')
4576 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
4577 in children[:num_children] if not x.trash]
4580 rbd_linked_image_spec_list_cleanup(children, num_children)
4583 @requires_not_closed
4584 def list_children2(self):
4586 Iterate over the children of the image or its snapshot.
4588 :returns: :class:`ChildIterator`
4590 return ChildIterator(self)
4592 @requires_not_closed
4593 def list_descendants(self):
4595 Iterate over the descendants of the image.
4597 :returns: :class:`ChildIterator`
4599 return ChildIterator(self, True)
4601 @requires_not_closed
4602 def list_lockers(self):
4604 List clients that have locked the image and information
4607 :returns: dict - contains the following keys:
4609 * ``tag`` - the tag associated with the lock (every
4610 additional locker must use the same tag)
4611 * ``exclusive`` - boolean indicating whether the
4612 lock is exclusive or shared
4613 * ``lockers`` - a list of (client, cookie, address)
4617 size_t clients_size = 512, cookies_size = 512
4618 size_t addrs_size = 512, tag_size = 512
4620 char *c_clients = NULL
4621 char *c_cookies = NULL
4622 char *c_addrs = NULL
4627 c_clients = <char *>realloc_chk(c_clients, clients_size)
4628 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
4629 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
4630 c_tag = <char *>realloc_chk(c_tag, tag_size)
4632 ret = rbd_list_lockers(self.image, &exclusive,
4634 c_clients, &clients_size,
4635 c_cookies, &cookies_size,
4636 c_addrs, &addrs_size)
4639 elif ret != -errno.ERANGE:
4640 raise make_ex(ret, 'error listing images')
4643 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
4644 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
4645 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
4647 'tag' : decode_cstr(c_tag),
4648 'exclusive' : exclusive == 1,
4649 'lockers' : list(zip(clients, cookies, addrs)),
4657 @requires_not_closed
4658 def lock_acquire(self, lock_mode):
4660 Acquire a managed lock on the image.
4662 :param lock_mode: lock mode to set
4663 :type lock_mode: int
4664 :raises: :class:`ImageBusy` if the lock could not be acquired
4667 rbd_lock_mode_t _lock_mode = lock_mode
4669 ret = rbd_lock_acquire(self.image, _lock_mode)
4671 raise make_ex(ret, 'error acquiring lock on image')
4673 @requires_not_closed
4674 def lock_release(self):
4676 Release a managed lock on the image that was previously acquired.
4679 ret = rbd_lock_release(self.image)
4681 raise make_ex(ret, 'error releasing lock on image')
4683 @requires_not_closed
4684 def lock_get_owners(self):
4686 Iterate over the lock owners of an image.
4688 :returns: :class:`LockOwnerIterator`
4690 return LockOwnerIterator(self)
4692 @requires_not_closed
4693 def lock_break(self, lock_mode, lock_owner):
4695 Break the image lock held by a another client.
4697 :param lock_owner: the owner of the lock to break
4698 :type lock_owner: str
4700 lock_owner = cstr(lock_owner, 'lock_owner')
4702 rbd_lock_mode_t _lock_mode = lock_mode
4703 char *_lock_owner = lock_owner
4705 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
4707 raise make_ex(ret, 'error breaking lock on image')
4709 @requires_not_closed
4710 def lock_exclusive(self, cookie):
4712 Take an exclusive lock on the image.
4714 :raises: :class:`ImageBusy` if a different client or cookie locked it
4715 :class:`ImageExists` if the same client and cookie locked it
4717 cookie = cstr(cookie, 'cookie')
4718 cdef char *_cookie = cookie
4720 ret = rbd_lock_exclusive(self.image, _cookie)
4722 raise make_ex(ret, 'error acquiring exclusive lock on image')
4724 @requires_not_closed
4725 def lock_shared(self, cookie, tag):
4727 Take a shared lock on the image. The tag must match
4728 that of the existing lockers, if any.
4730 :raises: :class:`ImageBusy` if a different client or cookie locked it
4731 :class:`ImageExists` if the same client and cookie locked it
4733 cookie = cstr(cookie, 'cookie')
4734 tag = cstr(tag, 'tag')
4736 char *_cookie = cookie
4739 ret = rbd_lock_shared(self.image, _cookie, _tag)
4741 raise make_ex(ret, 'error acquiring shared lock on image')
4743 @requires_not_closed
4744 def unlock(self, cookie):
4746 Release a lock on the image that was locked by this rados client.
4748 cookie = cstr(cookie, 'cookie')
4749 cdef char *_cookie = cookie
4751 ret = rbd_unlock(self.image, _cookie)
4753 raise make_ex(ret, 'error unlocking image')
4755 @requires_not_closed
4756 def break_lock(self, client, cookie):
4758 Release a lock held by another rados client.
4760 client = cstr(client, 'client')
4761 cookie = cstr(cookie, 'cookie')
4763 char *_client = client
4764 char *_cookie = cookie
4766 ret = rbd_break_lock(self.image, _client, _cookie)
4768 raise make_ex(ret, 'error unlocking image')
4770 @requires_not_closed
4771 def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
4773 Enable mirroring for the image.
4775 cdef rbd_mirror_image_mode_t c_mode = mode
4777 ret = rbd_mirror_image_enable2(self.image, c_mode)
4779 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4781 @requires_not_closed
4782 def mirror_image_disable(self, force):
4784 Disable mirroring for the image.
4786 :param force: force disabling
4789 cdef bint c_force = force
4791 ret = rbd_mirror_image_disable(self.image, c_force)
4793 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4795 @requires_not_closed
4796 def mirror_image_promote(self, force):
4798 Promote the image to primary for mirroring.
4800 :param force: force promoting
4803 cdef bint c_force = force
4805 ret = rbd_mirror_image_promote(self.image, c_force)
4807 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4809 @requires_not_closed
4810 def mirror_image_demote(self):
4812 Demote the image to secondary for mirroring.
4815 ret = rbd_mirror_image_demote(self.image)
4817 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4819 @requires_not_closed
4820 def mirror_image_resync(self):
4822 Flag the image to resync.
4825 ret = rbd_mirror_image_resync(self.image)
4827 raise make_ex(ret, 'error to resync image %s' % self.name)
4829 @requires_not_closed
4830 def mirror_image_create_snapshot(self):
4832 Create mirror snapshot.
4834 :param force: ignore mirror snapshot limit
4836 :returns: int - the snapshot Id
4841 ret = rbd_mirror_image_create_snapshot(self.image, &snap_id)
4843 raise make_ex(ret, 'error creating mirror snapshot for image %s' %
4847 @requires_not_closed
4848 def mirror_image_get_info(self):
4850 Get mirror info for the image.
4852 :returns: dict - contains the following keys:
4854 * ``global_id`` (str) - image global id
4856 * ``state`` (int) - mirror state
4858 * ``primary`` (bool) - is image primary
4860 cdef rbd_mirror_image_info_t c_info
4862 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4864 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4866 'global_id' : decode_cstr(c_info.global_id),
4867 'state' : int(c_info.state),
4868 'primary' : c_info.primary,
4870 rbd_mirror_image_get_info_cleanup(&c_info)
4873 @requires_not_closed
4874 def mirror_image_get_mode(self):
4876 Get mirror mode for the image.
4878 :returns: int - mirror mode
4880 cdef rbd_mirror_image_mode_t c_mode
4882 ret = rbd_mirror_image_get_mode(self.image, &c_mode)
4884 raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
4887 @requires_not_closed
4888 def mirror_image_get_status(self):
4890 Get mirror status for the image.
4892 :returns: dict - contains the following keys:
4894 * ``name`` (str) - mirror image name
4896 * ``id`` (str) - mirror image id
4898 * ``info`` (dict) - mirror image info
4900 * ``state`` (int) - status mirror state
4902 * ``description`` (str) - status description
4904 * ``last_update`` (datetime) - last status update time
4906 * ``up`` (bool) - is mirroring agent up
4908 * ``remote_statuses`` (array) -
4910 * ``mirror_uuid`` (str) - remote mirror uuid
4912 * ``state`` (int) - status mirror state
4914 * ``description`` (str) - status description
4916 * ``last_update`` (datetime) - last status update time
4918 * ``up`` (bool) - is mirroring agent up
4921 rbd_mirror_image_site_status_t *s_status
4922 rbd_mirror_image_global_status_t c_status
4925 ret = rbd_mirror_image_get_global_status(self.image, &c_status,
4928 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4932 for i in range(c_status.site_statuses_count):
4933 s_status = &c_status.site_statuses[i]
4935 'state' : s_status.state,
4936 'description' : decode_cstr(s_status.description),
4937 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
4940 mirror_uuid = decode_cstr(s_status.mirror_uuid)
4941 if mirror_uuid == '':
4942 local_status = site_status
4944 site_statuses['mirror_uuid'] = mirror_uuid
4945 site_statuses += site_status
4947 'name': decode_cstr(c_status.name),
4950 'global_id' : decode_cstr(c_status.info.global_id),
4951 'state' : int(c_status.info.state),
4952 'primary' : c_status.info.primary,
4954 'remote_statuses': site_statuses,
4957 status.update(local_status)
4959 rbd_mirror_image_global_status_cleanup(&c_status)
4962 @requires_not_closed
4963 def mirror_image_get_instance_id(self):
4965 Get mirror instance id for the image.
4967 :returns: str - instance id
4970 int ret = -errno.ERANGE
4972 char *instance_id = NULL
4974 while ret == -errno.ERANGE and size <= 4096:
4975 instance_id = <char *>realloc_chk(instance_id, size)
4977 ret = rbd_mirror_image_get_instance_id(self.image,
4981 'error getting mirror instance id for image %s' %
4983 return decode_cstr(instance_id)
4987 @requires_not_closed
4988 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4990 Asynchronously read data from the image
4992 Raises :class:`InvalidArgument` if part of the range specified is
4995 oncomplete will be called with the returned read value as
4996 well as the completion:
4998 oncomplete(completion, data_read)
5000 :param offset: the offset to start reading at
5002 :param length: how many bytes to read
5004 :param oncomplete: what to do when the read is complete
5005 :type oncomplete: completion
5006 :param fadvise_flags: fadvise flags for this read
5007 :type fadvise_flags: int
5008 :returns: :class:`Completion` - the completion object
5009 :raises: :class:`InvalidArgument`, :class:`IOError`
5013 uint64_t _offset = offset
5014 size_t _length = length
5015 int _fadvise_flags = fadvise_flags
5016 Completion completion
5018 def oncomplete_(completion_v):
5019 cdef Completion _completion_v = completion_v
5020 return_value = _completion_v.get_return_value()
5021 if return_value > 0 and return_value != length:
5022 _PyBytes_Resize(&_completion_v.buf, return_value)
5023 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
5025 completion = self.__get_completion(oncomplete_)
5026 completion.buf = PyBytes_FromStringAndSize(NULL, length)
5027 ret_buf = PyBytes_AsString(completion.buf)
5029 completion.__persist()
5031 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
5032 completion.rbd_comp, _fadvise_flags)
5034 raise make_ex(ret, 'error reading %s %ld~%ld' %
5035 (self.name, offset, length))
5037 completion.__unpersist()
5042 @requires_not_closed
5043 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
5045 Asynchronously write data to the image
5047 Raises :class:`InvalidArgument` if part of the write would fall outside
5050 oncomplete will be called with the completion:
5052 oncomplete(completion)
5054 :param data: the data to be written
5056 :param offset: the offset to start writing at
5058 :param oncomplete: what to do when the write is complete
5059 :type oncomplete: completion
5060 :param fadvise_flags: fadvise flags for this write
5061 :type fadvise_flags: int
5062 :returns: :class:`Completion` - the completion object
5063 :raises: :class:`InvalidArgument`, :class:`IOError`
5066 uint64_t _offset = offset
5068 size_t _length = len(data)
5069 int _fadvise_flags = fadvise_flags
5070 Completion completion
5072 completion = self.__get_completion(oncomplete)
5074 completion.__persist()
5076 ret = rbd_aio_write2(self.image, _offset, _length, _data,
5077 completion.rbd_comp, _fadvise_flags)
5079 raise make_ex(ret, 'error writing %s %ld~%ld' %
5080 (self.name, offset, _length))
5082 completion.__unpersist()
5087 @requires_not_closed
5088 def aio_discard(self, offset, length, oncomplete):
5090 Asynchronously trim the range from the image. It will be logically
5094 uint64_t _offset = offset
5095 size_t _length = length
5096 Completion completion
5098 completion = self.__get_completion(oncomplete)
5100 completion.__persist()
5102 ret = rbd_aio_discard(self.image, _offset, _length,
5103 completion.rbd_comp)
5105 raise make_ex(ret, 'error discarding %s %ld~%ld' %
5106 (self.name, offset, _length))
5108 completion.__unpersist()
5113 @requires_not_closed
5114 def aio_write_zeroes(self, offset, length, oncomplete, zero_flags = 0):
5116 Asynchronously Zero the range from the image. By default it will attempt
5117 to discard/unmap as much space as possible but any unaligned extent
5118 segments will still be zeroed.
5121 uint64_t _offset = offset
5122 size_t _length = length
5123 int _zero_flags = zero_flags
5124 Completion completion
5126 completion = self.__get_completion(oncomplete)
5128 completion.__persist()
5130 ret = rbd_aio_write_zeroes(self.image, _offset, _length,
5131 completion.rbd_comp, _zero_flags, 0)
5133 raise make_ex(ret, 'error zeroing %s %ld~%ld' %
5134 (self.name, offset, length))
5136 completion.__unpersist()
5141 @requires_not_closed
5142 def aio_flush(self, oncomplete):
5144 Asynchronously wait until all writes are fully flushed if caching is
5147 cdef Completion completion = self.__get_completion(oncomplete)
5149 completion.__persist()
5151 ret = rbd_aio_flush(self.image, completion.rbd_comp)
5153 raise make_ex(ret, 'error flushing')
5155 completion.__unpersist()
5160 @requires_not_closed
5161 def metadata_get(self, key):
5163 Get image metadata for the given key.
5165 :param key: metadata key
5167 :returns: str - metadata value
5169 key = cstr(key, 'key')
5177 value = <char *>realloc_chk(value, size)
5179 ret = rbd_metadata_get(self.image, _key, value, &size)
5180 if ret != -errno.ERANGE:
5182 if ret == -errno.ENOENT:
5183 raise KeyError('no metadata %s for image %s' % (key, self.name))
5185 raise make_ex(ret, 'error getting metadata %s for image %s' %
5187 return decode_cstr(value)
5191 @requires_not_closed
5192 def metadata_set(self, key, value):
5194 Set image metadata for the given key.
5196 :param key: metadata key
5198 :param value: metadata value
5201 key = cstr(key, 'key')
5202 value = cstr(value, 'value')
5205 char *_value = value
5207 ret = rbd_metadata_set(self.image, _key, _value)
5210 raise make_ex(ret, 'error setting metadata %s for image %s' %
5213 @requires_not_closed
5214 def metadata_remove(self, key):
5216 Remove image metadata for the given key.
5218 :param key: metadata key
5221 key = cstr(key, 'key')
5225 ret = rbd_metadata_remove(self.image, _key)
5227 if ret == -errno.ENOENT:
5228 raise KeyError('no metadata %s for image %s' % (key, self.name))
5230 raise make_ex(ret, 'error removing metadata %s for image %s' %
5233 @requires_not_closed
5234 def metadata_list(self):
5236 List image metadata.
5238 :returns: :class:`MetadataIterator`
5240 return MetadataIterator(self)
5242 @requires_not_closed
5243 def watchers_list(self):
5245 List image watchers.
5247 :returns: :class:`WatcherIterator`
5249 return WatcherIterator(self)
5251 @requires_not_closed
5252 def config_list(self):
5254 List image-level config overrides.
5256 :returns: :class:`ConfigImageIterator`
5258 return ConfigImageIterator(self)
5260 @requires_not_closed
5261 def config_set(self, key, value):
5263 Set an image-level configuration override.
5270 conf_key = 'conf_' + key
5271 conf_key = cstr(conf_key, 'key')
5272 value = cstr(value, 'value')
5274 char *_key = conf_key
5275 char *_value = value
5277 ret = rbd_metadata_set(self.image, _key, _value)
5280 raise make_ex(ret, 'error setting config %s for image %s' %
5283 @requires_not_closed
5284 def config_get(self, key):
5286 Get an image-level configuration override.
5290 :returns: str - value
5292 conf_key = 'conf_' + key
5293 conf_key = cstr(conf_key, 'key')
5295 char *_key = conf_key
5301 value = <char *>realloc_chk(value, size)
5303 ret = rbd_metadata_get(self.image, _key, value, &size)
5304 if ret != -errno.ERANGE:
5306 if ret == -errno.ENOENT:
5307 raise KeyError('no config %s for image %s' % (key, self.name))
5309 raise make_ex(ret, 'error getting config %s for image %s' %
5311 return decode_cstr(value)
5315 @requires_not_closed
5316 def config_remove(self, key):
5318 Remove an image-level configuration override.
5323 conf_key = 'conf_' + key
5324 conf_key = cstr(conf_key, 'key')
5326 char *_key = conf_key
5328 ret = rbd_metadata_remove(self.image, _key)
5330 if ret == -errno.ENOENT:
5331 raise KeyError('no config %s for image %s' % (key, self.name))
5333 raise make_ex(ret, 'error removing config %s for image %s' %
5336 @requires_not_closed
5337 def snap_get_namespace_type(self, snap_id):
5339 Get the snapshot namespace type.
5340 :param snap_id: the snapshot id of a snap shot
5344 rbd_snap_namespace_type_t namespace_type
5345 uint64_t _snap_id = snap_id
5347 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
5349 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
5351 return namespace_type
5353 @requires_not_closed
5354 def snap_get_group_namespace(self, snap_id):
5356 get the group namespace details.
5357 :param snap_id: the snapshot id of the group snapshot
5359 :returns: dict - contains the following keys:
5361 * ``pool`` (int) - pool id
5363 * ``name`` (str) - group name
5365 * ``snap_name`` (str) - group snap name
5368 rbd_snap_group_namespace_t group_namespace
5369 uint64_t _snap_id = snap_id
5371 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
5373 sizeof(rbd_snap_group_namespace_t))
5375 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
5378 'pool' : group_namespace.group_pool,
5379 'name' : decode_cstr(group_namespace.group_name),
5380 'snap_name' : decode_cstr(group_namespace.group_snap_name)
5382 rbd_snap_group_namespace_cleanup(&group_namespace,
5383 sizeof(rbd_snap_group_namespace_t))
5386 @requires_not_closed
5387 def snap_get_trash_namespace(self, snap_id):
5389 get the trash namespace details.
5390 :param snap_id: the snapshot id of the trash snapshot
5392 :returns: dict - contains the following keys:
5394 * ``original_name`` (str) - original snap name
5397 uint64_t _snap_id = snap_id
5402 _name = <char*>realloc_chk(_name, _size);
5404 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
5408 elif ret != -errno.ERANGE:
5409 raise make_ex(ret, 'error getting snapshot trash '
5410 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
5412 'original_name' : decode_cstr(_name)
5417 @requires_not_closed
5418 def snap_get_mirror_namespace(self, snap_id):
5420 get the mirror namespace details.
5421 :param snap_id: the snapshot id of the mirror snapshot
5423 :returns: dict - contains the following keys:
5425 * ``state`` (int) - the snapshot state
5427 * ``mirror_peer_uuids`` (list) - mirror peer uuids
5429 * ``complete`` (bool) - True if snapshot is complete
5431 * ``primary_mirror_uuid`` (str) - primary mirror uuid
5433 * ``primary_snap_id`` (int) - primary snapshot Id
5435 * ``last_copied_object_number`` (int) - last copied object number
5438 rbd_snap_mirror_namespace_t sn
5439 uint64_t _snap_id = snap_id
5441 ret = rbd_snap_get_mirror_namespace(
5442 self.image, _snap_id, &sn,
5443 sizeof(rbd_snap_mirror_namespace_t))
5445 raise make_ex(ret, 'error getting snapshot mirror '
5446 'namespace for image: %s, snap_id: %d' %
5447 (self.name, snap_id))
5449 cdef char *p = sn.mirror_peer_uuids
5450 for i in range(sn.mirror_peer_uuids_count):
5451 uuid = decode_cstr(p)
5456 'mirror_peer_uuids' : uuids,
5457 'complete' : sn.complete,
5458 'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
5459 'primary_snap_id' : sn.primary_snap_id,
5460 'last_copied_object_number' : sn.last_copied_object_number,
5462 rbd_snap_mirror_namespace_cleanup(
5463 &sn, sizeof(rbd_snap_mirror_namespace_t))
5467 cdef class ImageIterator(object):
5469 Iterator over RBD images in a pool
5471 Yields a dictionary containing information about the images
5475 * ``id`` (str) - image id
5477 * ``name`` (str) - image name
5479 cdef rados_ioctx_t ioctx
5480 cdef rbd_image_spec_t *images
5481 cdef size_t num_images
5483 def __init__(self, ioctx):
5484 self.ioctx = convert_ioctx(ioctx)
5486 self.num_images = 1024
5488 self.images = <rbd_image_spec_t*>realloc_chk(
5489 self.images, self.num_images * sizeof(rbd_image_spec_t))
5491 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
5494 elif ret == -errno.ERANGE:
5495 self.num_images *= 2
5497 raise make_ex(ret, 'error listing images.')
5500 for i in range(self.num_images):
5502 'id' : decode_cstr(self.images[i].id),
5503 'name' : decode_cstr(self.images[i].name)
5506 def __dealloc__(self):
5508 rbd_image_spec_list_cleanup(self.images, self.num_images)
5512 cdef class LockOwnerIterator(object):
5514 Iterator over managed lock owners for an image
5516 Yields a dictionary containing information about the image's lock
5520 * ``mode`` (int) - active lock mode
5522 * ``owner`` (str) - lock owner name
5526 rbd_lock_mode_t lock_mode
5528 size_t num_lock_owners
5531 def __init__(self, Image image):
5532 image.require_not_closed()
5535 self.lock_owners = NULL
5536 self.num_lock_owners = 8
5538 self.lock_owners = <char**>realloc_chk(self.lock_owners,
5539 self.num_lock_owners *
5542 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
5544 &self.num_lock_owners)
5547 elif ret == -errno.ENOENT:
5548 self.num_lock_owners = 0
5550 elif ret != -errno.ERANGE:
5551 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
5554 for i in range(self.num_lock_owners):
5556 'mode' : int(self.lock_mode),
5557 'owner' : decode_cstr(self.lock_owners[i]),
5560 def __dealloc__(self):
5561 if self.lock_owners:
5562 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
5563 free(self.lock_owners)
5565 cdef class MetadataIterator(object):
5567 Iterator over metadata list for an image.
5569 Yields ``(key, value)`` tuple.
5571 * ``key`` (str) - metadata key
5572 * ``value`` (str) - metadata value
5582 def __init__(self, Image image):
5583 image.require_not_closed()
5586 self.c_image = image.image
5587 self.last_read = strdup("")
5589 self.get_next_chunk()
5592 while len(self.next_chunk) > 0:
5593 for pair in self.next_chunk:
5595 if len(self.next_chunk) < self.max_read:
5597 self.get_next_chunk()
5599 def __dealloc__(self):
5601 free(self.last_read)
5603 def get_next_chunk(self):
5604 self.image.require_not_closed()
5608 size_t keys_size = 4096
5610 size_t vals_size = 4096
5613 c_keys = <char *>realloc_chk(c_keys, keys_size)
5614 c_vals = <char *>realloc_chk(c_vals, vals_size)
5616 ret = rbd_metadata_list(self.c_image, self.last_read,
5617 self.max_read, c_keys, &keys_size,
5621 elif ret != -errno.ERANGE:
5622 raise make_ex(ret, 'error listing metadata for image %s' %
5624 keys = [decode_cstr(key) for key in
5625 c_keys[:keys_size].split(b'\0') if key]
5626 vals = [decode_cstr(val) for val in
5627 c_vals[:vals_size].split(b'\0') if val]
5629 last_read = cstr(keys[-1], 'last_read')
5630 free(self.last_read)
5631 self.last_read = strdup(last_read)
5632 self.next_chunk = list(zip(keys, vals))
5637 cdef class SnapIterator(object):
5639 Iterator over snapshot info for an image.
5641 Yields a dictionary containing information about a snapshot.
5645 * ``id`` (int) - numeric identifier of the snapshot
5647 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
5649 * ``name`` (str) - name of the snapshot
5651 * ``namespace`` (int) - enum for snap namespace
5653 * ``group`` (dict) - optional for group namespace snapshots
5655 * ``trash`` (dict) - optional for trash namespace snapshots
5657 * ``mirror`` (dict) - optional for mirror namespace snapshots
5660 cdef rbd_snap_info_t *snaps
5664 def __init__(self, Image image):
5665 image.require_not_closed()
5671 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
5673 sizeof(rbd_snap_info_t))
5675 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
5677 self.num_snaps = ret
5679 elif ret != -errno.ERANGE:
5680 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
5683 for i in range(self.num_snaps):
5685 'id' : self.snaps[i].id,
5686 'size' : self.snaps[i].size,
5687 'name' : decode_cstr(self.snaps[i].name),
5688 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
5690 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
5692 group = self.image.snap_get_group_namespace(self.snaps[i].id)
5696 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
5698 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
5702 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR:
5704 mirror = self.image.snap_get_mirror_namespace(
5708 s['mirror'] = mirror
5711 def __dealloc__(self):
5713 rbd_snap_list_end(self.snaps)
5716 cdef class TrashIterator(object):
5718 Iterator over trash entries.
5720 Yields a dictionary containing trash info of an image.
5724 * `id` (str) - image id
5726 * `name` (str) - image name
5728 * `source` (str) - source of deletion
5730 * `deletion_time` (datetime) - time of deletion
5732 * `deferment_end_time` (datetime) - time that an image is allowed to be
5739 rbd_trash_image_info_t *entries
5741 def __init__(self, ioctx):
5742 self.ioctx = convert_ioctx(ioctx)
5743 self.num_entries = 1024
5746 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
5748 sizeof(rbd_trash_image_info_t))
5750 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
5752 self.num_entries = ret
5754 elif ret != -errno.ERANGE:
5755 raise make_ex(ret, 'error listing trash entries')
5757 __source_string = ['USER', 'MIRRORING']
5760 for i in range(self.num_entries):
5762 'id' : decode_cstr(self.entries[i].id),
5763 'name' : decode_cstr(self.entries[i].name),
5764 'source' : TrashIterator.__source_string[self.entries[i].source],
5765 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
5766 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
5769 def __dealloc__(self):
5770 rbd_trash_list_cleanup(self.entries, self.num_entries)
5774 cdef class ChildIterator(object):
5776 Iterator over child info for the image or its snapshot.
5778 Yields a dictionary containing information about a child.
5782 * ``pool`` (str) - name of the pool
5784 * ``pool_namespace`` (str) - namespace of the pool
5786 * ``image`` (str) - name of the child
5788 * ``id`` (str) - id of the child
5790 * ``trash`` (bool) - True if child is in trash bin
5793 cdef rbd_linked_image_spec_t *children
5794 cdef size_t num_children
5797 def __init__(self, Image image, descendants=False):
5798 image.require_not_closed()
5801 self.children = NULL
5802 self.num_children = 10
5804 self.children = <rbd_linked_image_spec_t*>realloc_chk(
5805 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
5808 ret = rbd_list_descendants(image.image, self.children,
5812 ret = rbd_list_children3(image.image, self.children,
5816 elif ret != -errno.ERANGE:
5817 raise make_ex(ret, 'error listing children.')
5820 for i in range(self.num_children):
5822 'pool' : decode_cstr(self.children[i].pool_name),
5823 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
5824 'image' : decode_cstr(self.children[i].image_name),
5825 'id' : decode_cstr(self.children[i].image_id),
5826 'trash' : self.children[i].trash
5829 def __dealloc__(self):
5831 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
5834 cdef class WatcherIterator(object):
5836 Iterator over watchers of an image.
5838 Yields a dictionary containing information about a watcher.
5842 * ``addr`` (str) - address of the watcher
5844 * ``id`` (int) - id of the watcher
5846 * ``cookie`` (int) - the watcher's cookie
5849 cdef rbd_image_watcher_t *watchers
5850 cdef size_t num_watchers
5853 def __init__(self, Image image):
5854 image.require_not_closed()
5857 self.watchers = NULL
5858 self.num_watchers = 10
5860 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
5862 sizeof(rbd_image_watcher_t))
5864 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
5867 elif ret != -errno.ERANGE:
5868 raise make_ex(ret, 'error listing watchers.')
5871 for i in range(self.num_watchers):
5873 'addr' : decode_cstr(self.watchers[i].addr),
5874 'id' : self.watchers[i].id,
5875 'cookie' : self.watchers[i].cookie
5878 def __dealloc__(self):
5880 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
5883 cdef class ConfigImageIterator(object):
5885 Iterator over image-level overrides for an image.
5887 Yields a dictionary containing information about an override.
5891 * ``name`` (str) - override name
5893 * ``value`` (str) - override value
5895 * ``source`` (str) - override source
5899 rbd_config_option_t *options
5902 def __init__(self, Image image):
5903 image.require_not_closed()
5906 self.num_options = 32
5908 self.options = <rbd_config_option_t *>realloc_chk(
5909 self.options, self.num_options * sizeof(rbd_config_option_t))
5911 ret = rbd_config_image_list(image.image, self.options,
5914 if ret == -errno.ERANGE:
5916 self.num_options = 0
5917 raise make_ex(ret, 'error listing config options')
5921 for i in range(self.num_options):
5923 'name' : decode_cstr(self.options[i].name),
5924 'value' : decode_cstr(self.options[i].value),
5925 'source' : self.options[i].source,
5928 def __dealloc__(self):
5930 rbd_config_image_list_cleanup(self.options, self.num_options)
5933 cdef class GroupImageIterator(object):
5935 Iterator over image info for a group.
5937 Yields a dictionary containing information about an image.
5941 * ``name`` (str) - name of the image
5943 * ``pool`` (int) - id of the pool this image belongs to
5945 * ``state`` (int) - state of the image
5948 cdef rbd_group_image_info_t *images
5949 cdef size_t num_images
5952 def __init__(self, Group group):
5955 self.num_images = 10
5957 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
5959 sizeof(rbd_group_image_info_t))
5961 ret = rbd_group_image_list(group._ioctx, group._name,
5963 sizeof(rbd_group_image_info_t),
5968 elif ret != -errno.ERANGE:
5969 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
5972 for i in range(self.num_images):
5974 'name' : decode_cstr(self.images[i].name),
5975 'pool' : self.images[i].pool,
5976 'state' : self.images[i].state,
5979 def __dealloc__(self):
5981 rbd_group_image_list_cleanup(self.images,
5982 sizeof(rbd_group_image_info_t),
5986 cdef class GroupSnapIterator(object):
5988 Iterator over snaps specs for a group.
5990 Yields a dictionary containing information about a snapshot.
5994 * ``name`` (str) - name of the snapshot
5996 * ``state`` (int) - state of the snapshot
5999 cdef rbd_group_snap_info_t *snaps
6000 cdef size_t num_snaps
6003 def __init__(self, Group group):
6008 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
6010 sizeof(rbd_group_snap_info_t))
6012 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
6013 sizeof(rbd_group_snap_info_t),
6018 elif ret != -errno.ERANGE:
6019 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
6022 for i in range(self.num_snaps):
6024 'name' : decode_cstr(self.snaps[i].name),
6025 'state' : self.snaps[i].state,
6028 def __dealloc__(self):
6030 rbd_group_snap_list_cleanup(self.snaps,
6031 sizeof(rbd_group_snap_info_t),