]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/rbd/rbd.pyx
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / rbd / rbd.pyx
1 # cython: embedsignature=True
2 """
3 This module is a thin wrapper around librbd.
4
5 It currently provides all the synchronous methods of librbd that do
6 not use callbacks.
7
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
12 method.
13 """
14 # Copyright 2011 Josh Durgin
15 # Copyright 2015 Hector Martin <marcan@marcan.st>
16
17 import cython
18 import sys
19
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
25
26 try:
27 from collections.abc import Iterable
28 except ImportError:
29 from collections import Iterable
30 from datetime import datetime
31 from itertools import chain
32 import time
33
34 cimport rados
35
36
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
45
46 cdef extern from "time.h":
47 ctypedef long int time_t
48 cdef struct timespec:
49 time_t tv_sec
50 long tv_nsec
51
52 cdef extern from "<errno.h>" nogil:
53 enum:
54 _ECANCELED "ECANCELED"
55
56 cdef extern from "rados/librados.h":
57 enum:
58 _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
59
60 cdef extern from "rbd/librbd.h":
61 ctypedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void* ptr)
62
63 cdef extern from "rbd/librbd.h" nogil:
64 enum:
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"
76
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"
82
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"
87
88 _RBD_FLAG_OBJECT_MAP_INVALID "RBD_FLAG_OBJECT_MAP_INVALID"
89 _RBD_FLAG_FAST_DIFF_INVALID "RBD_FLAG_FAST_DIFF_INVALID"
90
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"
97
98 RBD_MAX_BLOCK_NAME_SIZE
99 RBD_MAX_IMAGE_NAME_SIZE
100
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"
104
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
111
112 ctypedef struct rbd_image_info_t:
113 uint64_t size
114 uint64_t obj_size
115 uint64_t num_objs
116 int order
117 char block_name_prefix[RBD_MAX_BLOCK_NAME_SIZE]
118 uint64_t parent_pool
119 char parent_name[RBD_MAX_IMAGE_NAME_SIZE]
120
121 ctypedef struct rbd_snap_info_t:
122 uint64_t id
123 uint64_t size
124 char *name
125
126 ctypedef struct rbd_snap_group_namespace_t:
127 int64_t group_pool
128 char *group_name
129 char *group_snap_name
130
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"
136
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
141 bint complete
142 char *primary_mirror_uuid
143 uint64_t primary_snap_id
144 uint64_t last_copied_object_number
145
146 ctypedef struct rbd_group_info_t:
147 char *name
148 int64_t pool
149
150 ctypedef struct rbd_image_spec_t:
151 char *id
152 char *name
153
154 ctypedef struct rbd_linked_image_spec_t:
155 int64_t pool_id
156 char *pool_name
157 char *pool_namespace
158 char *image_id
159 char *image_name
160 bint trash
161
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"
167
168 ctypedef struct rbd_snap_spec_t:
169 uint64_t id
170 rbd_snap_namespace_type_t namespace_type
171 char *name
172
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"
177
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"
182
183 ctypedef struct rbd_mirror_peer_site_t:
184 char *uuid
185 rbd_mirror_peer_direction_t direction
186 char *site_name
187 char *mirror_uuid
188 char *client_name
189 time_t last_seen
190
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"
193
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"
197
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"
202
203 ctypedef struct rbd_mirror_image_info_t:
204 char *global_id
205 rbd_mirror_image_state_t state
206 bint primary
207
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"
216
217 ctypedef struct rbd_mirror_image_site_status_t:
218 char *mirror_uuid
219 rbd_mirror_image_status_state_t state
220 char *description
221 time_t last_update
222 bint up
223
224 ctypedef struct rbd_mirror_image_global_status_t:
225 char *name
226 rbd_mirror_image_info_t info
227 uint32_t site_statuses_count
228 rbd_mirror_image_site_status_t *site_statuses
229
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"
233
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"
239
240 ctypedef struct rbd_trash_image_info_t:
241 char *id
242 char *name
243 rbd_trash_image_source_t source
244 time_t deletion_time
245 time_t deferment_end_time
246
247 ctypedef struct rbd_image_watcher_t:
248 char *addr
249 int64_t id
250 uint64_t cookie
251
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"
255
256 ctypedef struct rbd_group_image_info_t:
257 char *name
258 int64_t pool
259 rbd_group_image_state_t state
260
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"
264
265 ctypedef struct rbd_group_snap_info_t:
266 char *name
267 rbd_group_snap_state_t state
268
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
277 ctypedef struct rbd_image_migration_status_t:
278 int64_t source_pool_id
279 char *source_pool_namespace
280 char *source_image_name
281 char *source_image_id
282 int64_t dest_pool_id
283 char *dest_pool_namespace
284 char *dest_image_name
285 char *dest_image_id
286 rbd_image_migration_state_t state
287 char *state_description
288
289 ctypedef enum rbd_config_source_t:
290 _RBD_CONFIG_SOURCE_CONFIG "RBD_CONFIG_SOURCE_CONFIG"
291 _RBD_CONFIG_SOURCE_POOL "RBD_CONFIG_SOURCE_POOL"
292 _RBD_CONFIG_SOURCE_IMAGE "RBD_CONFIG_SOURCE_IMAGE"
293
294 ctypedef struct rbd_config_option_t:
295 char *name
296 char *value
297 rbd_config_source_t source
298
299 ctypedef enum rbd_pool_stat_option_t:
300 _RBD_POOL_STAT_OPTION_IMAGES "RBD_POOL_STAT_OPTION_IMAGES"
301 _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES"
302 _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES"
303 _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS "RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS"
304 _RBD_POOL_STAT_OPTION_TRASH_IMAGES "RBD_POOL_STAT_OPTION_TRASH_IMAGES"
305 _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES"
306 _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES "RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES"
307 _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS "RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS"
308
309 ctypedef void (*rbd_callback_t)(rbd_completion_t cb, void *arg)
310
311 void rbd_version(int *major, int *minor, int *extra)
312
313 void rbd_image_spec_list_cleanup(rbd_image_spec_t *image, size_t num_images)
314 void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
315 void rbd_linked_image_spec_list_cleanup(rbd_linked_image_spec_t *images,
316 size_t num_images)
317 void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
318
319 void rbd_image_options_create(rbd_image_options_t* opts)
320 void rbd_image_options_destroy(rbd_image_options_t opts)
321 int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
322 const char* optval)
323 int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
324 uint64_t optval)
325 int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
326 char* optval, size_t maxlen)
327 int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
328 uint64_t* optval)
329 int rbd_image_options_unset(rbd_image_options_t opts, int optname)
330 void rbd_image_options_clear(rbd_image_options_t opts)
331 int rbd_image_options_is_empty(rbd_image_options_t opts)
332
333 int rbd_list(rados_ioctx_t io, char *names, size_t *size)
334 int rbd_list2(rados_ioctx_t io, rbd_image_spec_t *images,
335 size_t *num_images)
336 int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
337 int *order)
338 int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
339 rbd_image_options_t opts)
340 int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
341 const char *p_snapname, rados_ioctx_t c_ioctx,
342 const char *c_name, rbd_image_options_t c_opts)
343 int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
344 librbd_progress_fn_t cb, void *cbdata)
345 int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname,
346 const char *destname)
347
348 int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay)
349 int rbd_trash_get(rados_ioctx_t io, const char *id,
350 rbd_trash_image_info_t *info)
351 void rbd_trash_get_cleanup(rbd_trash_image_info_t *info)
352 int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries,
353 size_t *num_entries)
354 void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries,
355 size_t num_entries)
356 int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts, float threshold)
357 int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id,
358 int force, librbd_progress_fn_t cb,
359 void *cbdata)
360 int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name)
361
362 int rbd_migration_prepare(rados_ioctx_t io_ctx, const char *image_name,
363 rados_ioctx_t dest_io_ctx,
364 const char *dest_image_name,
365 rbd_image_options_t opts)
366 int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
367 const char *image_name,
368 librbd_progress_fn_t cb,
369 void *cbdata)
370 int rbd_migration_commit_with_progress(rados_ioctx_t io_ctx,
371 const char *image_name,
372 librbd_progress_fn_t cb,
373 void *cbdata)
374 int rbd_migration_abort_with_progress(rados_ioctx_t io_ctx,
375 const char *image_name,
376 librbd_progress_fn_t cb, void *cbdata)
377 int rbd_migration_status(rados_ioctx_t io_ctx, const char *image_name,
378 rbd_image_migration_status_t *status,
379 size_t status_size)
380 void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
381
382 int rbd_mirror_site_name_get(rados_t cluster, char *name, size_t *max_len)
383 int rbd_mirror_site_name_set(rados_t cluster, const char *name)
384
385 int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
386 int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
387
388 int rbd_mirror_uuid_get(rados_ioctx_t io_ctx, char *mirror_uuid,
389 size_t *max_len)
390
391 int rbd_mirror_peer_bootstrap_create(rados_ioctx_t io_ctx, char *token,
392 size_t *max_len)
393 int rbd_mirror_peer_bootstrap_import(
394 rados_ioctx_t io_ctx, rbd_mirror_peer_direction_t direction,
395 const char *token)
396
397 int rbd_mirror_peer_site_add(
398 rados_ioctx_t io, char *uuid, size_t uuid_max_length,
399 rbd_mirror_peer_direction_t direction, const char *site_name,
400 const char *client_name)
401 int rbd_mirror_peer_site_remove(rados_ioctx_t io, const char *uuid)
402 int rbd_mirror_peer_site_list(
403 rados_ioctx_t io_ctx, rbd_mirror_peer_site_t *peers,int *max_peers)
404 void rbd_mirror_peer_site_list_cleanup(
405 rbd_mirror_peer_site_t *peers, int max_peers)
406
407 int rbd_mirror_peer_site_set_name(
408 rados_ioctx_t io_ctx, const char *uuid, const char *site_name)
409 int rbd_mirror_peer_site_set_client_name(
410 rados_ioctx_t io_ctx, const char *uuid, const char *client_name)
411
412 int rbd_mirror_peer_site_get_attributes(
413 rados_ioctx_t io_ctx, const char *uuid, char *keys, size_t *max_key_len,
414 char *values, size_t *max_val_length, size_t *key_value_count)
415 int rbd_mirror_peer_site_set_attributes(
416 rados_ioctx_t io_ctx, const char *uuid, const char *keys,
417 const char *values, size_t count)
418
419 int rbd_mirror_image_global_status_list(
420 rados_ioctx_t io, const char *start_id, size_t max, char **image_ids,
421 rbd_mirror_image_global_status_t *images, size_t *len)
422 void rbd_mirror_image_global_status_list_cleanup(
423 char **image_ids, rbd_mirror_image_global_status_t *images, size_t len)
424 int rbd_mirror_image_status_summary(rados_ioctx_t io,
425 rbd_mirror_image_status_state_t *states,
426 int *counts, size_t *maxlen)
427 int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx,
428 const char *start_id,
429 size_t max, char **image_ids,
430 char **instance_ids,
431 size_t *len)
432 void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
433 char **instance_ids,
434 size_t len)
435 int rbd_mirror_image_info_list(rados_ioctx_t io_ctx,
436 rbd_mirror_image_mode_t *mode_filter,
437 const char *start_id, size_t max,
438 char **image_ids,
439 rbd_mirror_image_mode_t *mode_entries,
440 rbd_mirror_image_info_t *info_entries,
441 size_t *num_entries)
442 void rbd_mirror_image_info_list_cleanup(char **image_ids,
443 rbd_mirror_image_info_t *info_entries,
444 size_t num_entries)
445
446 int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
447 char *value, size_t *val_len)
448 int rbd_pool_metadata_set(rados_ioctx_t io_ctx, const char *key,
449 const char *value)
450 int rbd_pool_metadata_remove(rados_ioctx_t io_ctx, const char *key)
451 int rbd_pool_metadata_list(rados_ioctx_t io_ctx, const char *start,
452 uint64_t max, char *keys, size_t *key_len,
453 char *values, size_t *vals_len)
454
455 int rbd_config_pool_list(rados_ioctx_t io_ctx, rbd_config_option_t *options,
456 int *max_options)
457 void rbd_config_pool_list_cleanup(rbd_config_option_t *options,
458 int max_options)
459
460 int rbd_open(rados_ioctx_t io, const char *name,
461 rbd_image_t *image, const char *snap_name)
462 int rbd_open_by_id(rados_ioctx_t io, const char *image_id,
463 rbd_image_t *image, const char *snap_name)
464 int rbd_open_read_only(rados_ioctx_t io, const char *name,
465 rbd_image_t *image, const char *snap_name)
466 int rbd_open_by_id_read_only(rados_ioctx_t io, const char *image_id,
467 rbd_image_t *image, const char *snap_name)
468 int rbd_features_to_string(uint64_t features, char *str_features, size_t *size)
469 int rbd_features_from_string(const char *str_features, uint64_t *features)
470 int rbd_close(rbd_image_t image)
471 int rbd_resize2(rbd_image_t image, uint64_t size, bint allow_shrink,
472 librbd_progress_fn_t cb, void *cbdata)
473 int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
474 int rbd_get_old_format(rbd_image_t image, uint8_t *old)
475 int rbd_get_size(rbd_image_t image, uint64_t *size)
476 int rbd_get_features(rbd_image_t image, uint64_t *features)
477 int rbd_update_features(rbd_image_t image, uint64_t features,
478 uint8_t enabled)
479 int rbd_get_op_features(rbd_image_t image, uint64_t *op_features)
480 int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
481 int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
482 int rbd_get_create_timestamp(rbd_image_t image, timespec *timestamp)
483 int rbd_get_access_timestamp(rbd_image_t image, timespec *timestamp)
484 int rbd_get_modify_timestamp(rbd_image_t image, timespec *timestamp)
485 int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
486 int rbd_get_name(rbd_image_t image, char *name, size_t *name_len)
487 int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
488 int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
489 size_t prefix_len)
490 int64_t rbd_get_data_pool_id(rbd_image_t image)
491 int rbd_get_parent(rbd_image_t image,
492 rbd_linked_image_spec_t *parent_image,
493 rbd_snap_spec_t *parent_snap)
494 int rbd_get_flags(rbd_image_t image, uint64_t *flags)
495 int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
496 size_t group_info_size)
497
498 ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
499 char *buf, int op_flags)
500 ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
501 const char *buf, int op_flags)
502 int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
503 int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
504 const char *destname, rbd_image_options_t dest_opts)
505 int rbd_deep_copy(rbd_image_t src, rados_ioctx_t dest_io_ctx,
506 const char *destname, rbd_image_options_t dest_opts)
507 int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
508 int *max_snaps)
509 void rbd_snap_list_end(rbd_snap_info_t *snaps)
510 int rbd_snap_create(rbd_image_t image, const char *snapname)
511 int rbd_snap_remove(rbd_image_t image, const char *snapname)
512 int rbd_snap_remove2(rbd_image_t image, const char *snapname, uint32_t flags,
513 librbd_progress_fn_t cb, void *cbdata)
514 int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
515 int rbd_snap_rollback(rbd_image_t image, const char *snapname)
516 int rbd_snap_rename(rbd_image_t image, const char *snapname,
517 const char* dstsnapsname)
518 int rbd_snap_protect(rbd_image_t image, const char *snap_name)
519 int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
520 int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
521 int *is_protected)
522 int rbd_snap_exists(rbd_image_t image, const char *snapname, bint *exists)
523 int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
524 int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
525 int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, timespec *timestamp)
526 int rbd_snap_set(rbd_image_t image, const char *snapname)
527 int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
528 int rbd_snap_get_name(rbd_image_t image, uint64_t snap_id,
529 char *snapname, size_t *name_len)
530 int rbd_snap_get_id(rbd_image_t image, const char *snapname,
531 uint64_t *snap_id)
532 int rbd_snap_get_namespace_type(rbd_image_t image,
533 uint64_t snap_id,
534 rbd_snap_namespace_type_t *namespace_type)
535 int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
536 rbd_snap_group_namespace_t *group_info,
537 size_t snap_group_namespace_size)
538 void rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_spec,
539 size_t snap_group_namespace_size)
540 int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
541 char *original_name, size_t max_length)
542 int rbd_snap_get_mirror_namespace(
543 rbd_image_t image, uint64_t snap_id,
544 rbd_snap_mirror_namespace_t *mirror_ns,
545 size_t snap_mirror_namespace_size)
546 void rbd_snap_mirror_namespace_cleanup(
547 rbd_snap_mirror_namespace_t *mirror_ns,
548 size_t snap_mirror_namespace_size)
549
550 int rbd_flatten_with_progress(rbd_image_t image, librbd_progress_fn_t cb,
551 void *cbdata)
552 int rbd_sparsify(rbd_image_t image, size_t sparse_size)
553 int rbd_rebuild_object_map(rbd_image_t image, librbd_progress_fn_t cb,
554 void *cbdata)
555 int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *children,
556 size_t *max_children)
557 int rbd_list_descendants(rbd_image_t image,
558 rbd_linked_image_spec_t *descendants,
559 size_t *max_descendants)
560
561 ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
562 char *tag, size_t *tag_len,
563 char *clients, size_t *clients_len,
564 char *cookies, size_t *cookies_len,
565 char *addrs, size_t *addrs_len)
566 int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
567 int rbd_lock_shared(rbd_image_t image, const char *cookie,
568 const char *tag)
569 int rbd_unlock(rbd_image_t image, const char *cookie)
570 int rbd_break_lock(rbd_image_t image, const char *client,
571 const char *cookie)
572
573 int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
574 int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
575 int rbd_lock_release(rbd_image_t image)
576 int rbd_lock_get_owners(rbd_image_t image, rbd_lock_mode_t *lock_mode,
577 char **lock_owners, size_t *max_lock_owners)
578 void rbd_lock_get_owners_cleanup(char **lock_owners,
579 size_t lock_owner_count)
580 int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
581 char *lock_owner)
582
583 # We use -9000 to propagate Python exceptions. We use except? to make sure
584 # things still work as intended if -9000 happens to be a valid errno value
585 # somewhere.
586 int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
587 uint64_t ofs, uint64_t len,
588 uint8_t include_parent, uint8_t whole_object,
589 int (*cb)(uint64_t, size_t, int, void *)
590 nogil except? -9000,
591 void *arg) except? -9000
592
593 int rbd_flush(rbd_image_t image)
594 int rbd_invalidate_cache(rbd_image_t image)
595
596 int rbd_mirror_image_enable2(rbd_image_t image,
597 rbd_mirror_image_mode_t mode)
598 int rbd_mirror_image_disable(rbd_image_t image, bint force)
599 int rbd_mirror_image_promote(rbd_image_t image, bint force)
600 int rbd_mirror_image_demote(rbd_image_t image)
601 int rbd_mirror_image_resync(rbd_image_t image)
602 int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id)
603 int rbd_mirror_image_get_info(rbd_image_t image,
604 rbd_mirror_image_info_t *mirror_image_info,
605 size_t info_size)
606 void rbd_mirror_image_get_info_cleanup(
607 rbd_mirror_image_info_t *mirror_image_info)
608 int rbd_mirror_image_get_mode(rbd_image_t image,
609 rbd_mirror_image_mode_t *mode)
610 int rbd_mirror_image_get_global_status(
611 rbd_image_t image,
612 rbd_mirror_image_global_status_t *mirror_image_global_status,
613 size_t status_size)
614 void rbd_mirror_image_global_status_cleanup(
615 rbd_mirror_image_global_status_t *mirror_image_global_status)
616 int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id,
617 size_t *id_max_length)
618
619 int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
620 const char *buf, rbd_completion_t c, int op_flags)
621 int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
622 char *buf, rbd_completion_t c, int op_flags)
623 int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
624 rbd_completion_t c)
625
626 int rbd_aio_create_completion(void *cb_arg, rbd_callback_t complete_cb,
627 rbd_completion_t *c)
628 int rbd_aio_is_complete(rbd_completion_t c)
629 int rbd_aio_wait_for_complete(rbd_completion_t c)
630 ssize_t rbd_aio_get_return_value(rbd_completion_t c)
631 void rbd_aio_release(rbd_completion_t c)
632 int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
633
634 int rbd_metadata_get(rbd_image_t image, const char *key, char *value,
635 size_t *val_len)
636 int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
637 int rbd_metadata_remove(rbd_image_t image, const char *key)
638 int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
639 char *keys, size_t *key_len, char *values,
640 size_t *vals_len)
641 int rbd_group_create(rados_ioctx_t p, const char *name)
642 int rbd_group_remove(rados_ioctx_t p, const char *name)
643 int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
644 int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest)
645 void rbd_group_info_cleanup(rbd_group_info_t *group_info,
646 size_t group_info_size)
647 int rbd_group_image_add(rados_ioctx_t group_p, const char *group_name,
648 rados_ioctx_t image_p, const char *image_name)
649 int rbd_group_image_remove(rados_ioctx_t group_p, const char *group_name,
650 rados_ioctx_t image_p, const char *image_name)
651
652 int rbd_group_image_list(rados_ioctx_t group_p,
653 const char *group_name,
654 rbd_group_image_info_t *images,
655 size_t group_image_info_size,
656 size_t *image_size)
657 void rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
658 size_t group_image_info_size, size_t len)
659
660 int rbd_group_snap_create(rados_ioctx_t group_p, const char *group_name,
661 const char *snap_name)
662
663 int rbd_group_snap_remove(rados_ioctx_t group_p, const char *group_name,
664 const char *snap_name)
665
666 int rbd_group_snap_rename(rados_ioctx_t group_p, const char *group_name,
667 const char *old_snap_name,
668 const char *new_snap_name)
669
670 int rbd_group_snap_list(rados_ioctx_t group_p,
671 const char *group_name,
672 rbd_group_snap_info_t *snaps,
673 size_t group_snap_info_size,
674 size_t *snaps_size)
675
676 void rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
677 size_t group_snap_info_size, size_t len)
678 int rbd_group_snap_rollback(rados_ioctx_t group_p, const char *group_name,
679 const char *snap_name)
680
681 int rbd_watchers_list(rbd_image_t image, rbd_image_watcher_t *watchers,
682 size_t *max_watchers)
683 void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
684 size_t num_watchers)
685
686 int rbd_config_image_list(rbd_image_t image, rbd_config_option_t *options,
687 int *max_options)
688 void rbd_config_image_list_cleanup(rbd_config_option_t *options,
689 int max_options)
690
691 int rbd_namespace_create(rados_ioctx_t io, const char *namespace_name)
692 int rbd_namespace_remove(rados_ioctx_t io, const char *namespace_name)
693 int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
694 size_t *size)
695 int rbd_namespace_exists(rados_ioctx_t io, const char *namespace_name,
696 bint *exists)
697
698 int rbd_pool_init(rados_ioctx_t, bint force)
699
700 void rbd_pool_stats_create(rbd_pool_stats_t *stats)
701 void rbd_pool_stats_destroy(rbd_pool_stats_t stats)
702 int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
703 int stat_option, uint64_t* stat_val)
704 int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats)
705
706 ECANCELED = _ECANCELED
707
708 RBD_FEATURE_LAYERING = _RBD_FEATURE_LAYERING
709 RBD_FEATURE_STRIPINGV2 = _RBD_FEATURE_STRIPINGV2
710 RBD_FEATURE_EXCLUSIVE_LOCK = _RBD_FEATURE_EXCLUSIVE_LOCK
711 RBD_FEATURE_OBJECT_MAP = _RBD_FEATURE_OBJECT_MAP
712 RBD_FEATURE_FAST_DIFF = _RBD_FEATURE_FAST_DIFF
713 RBD_FEATURE_DEEP_FLATTEN = _RBD_FEATURE_DEEP_FLATTEN
714 RBD_FEATURE_JOURNALING = _RBD_FEATURE_JOURNALING
715 RBD_FEATURE_DATA_POOL = _RBD_FEATURE_DATA_POOL
716 RBD_FEATURE_OPERATIONS = _RBD_FEATURE_OPERATIONS
717 RBD_FEATURE_MIGRATING = _RBD_FEATURE_MIGRATING
718 RBD_FEATURE_NON_PRIMARY = _RBD_FEATURE_NON_PRIMARY
719
720 RBD_FEATURES_INCOMPATIBLE = _RBD_FEATURES_INCOMPATIBLE
721 RBD_FEATURES_RW_INCOMPATIBLE = _RBD_FEATURES_RW_INCOMPATIBLE
722 RBD_FEATURES_MUTABLE = _RBD_FEATURES_MUTABLE
723 RBD_FEATURES_SINGLE_CLIENT = _RBD_FEATURES_SINGLE_CLIENT
724 RBD_FEATURES_ALL = _RBD_FEATURES_ALL
725
726 RBD_OPERATION_FEATURE_CLONE_PARENT = _RBD_OPERATION_FEATURE_CLONE_PARENT
727 RBD_OPERATION_FEATURE_CLONE_CHILD = _RBD_OPERATION_FEATURE_CLONE_CHILD
728 RBD_OPERATION_FEATURE_GROUP = _RBD_OPERATION_FEATURE_GROUP
729 RBD_OPERATION_FEATURE_SNAP_TRASH = _RBD_OPERATION_FEATURE_SNAP_TRASH
730
731 RBD_FLAG_OBJECT_MAP_INVALID = _RBD_FLAG_OBJECT_MAP_INVALID
732 RBD_FLAG_FAST_DIFF_INVALID = _RBD_FLAG_FAST_DIFF_INVALID
733
734 RBD_MIRROR_MODE_DISABLED = _RBD_MIRROR_MODE_DISABLED
735 RBD_MIRROR_MODE_IMAGE = _RBD_MIRROR_MODE_IMAGE
736 RBD_MIRROR_MODE_POOL = _RBD_MIRROR_MODE_POOL
737
738 RBD_MIRROR_PEER_DIRECTION_RX = _RBD_MIRROR_PEER_DIRECTION_RX
739 RBD_MIRROR_PEER_DIRECTION_TX = _RBD_MIRROR_PEER_DIRECTION_TX
740 RBD_MIRROR_PEER_DIRECTION_RX_TX = _RBD_MIRROR_PEER_DIRECTION_RX_TX
741
742 RBD_MIRROR_IMAGE_MODE_JOURNAL = _RBD_MIRROR_IMAGE_MODE_JOURNAL
743 RBD_MIRROR_IMAGE_MODE_SNAPSHOT = _RBD_MIRROR_IMAGE_MODE_SNAPSHOT
744
745 RBD_MIRROR_IMAGE_DISABLING = _RBD_MIRROR_IMAGE_DISABLING
746 RBD_MIRROR_IMAGE_ENABLED = _RBD_MIRROR_IMAGE_ENABLED
747 RBD_MIRROR_IMAGE_DISABLED = _RBD_MIRROR_IMAGE_DISABLED
748
749 MIRROR_IMAGE_STATUS_STATE_UNKNOWN = _MIRROR_IMAGE_STATUS_STATE_UNKNOWN
750 MIRROR_IMAGE_STATUS_STATE_ERROR = _MIRROR_IMAGE_STATUS_STATE_ERROR
751 MIRROR_IMAGE_STATUS_STATE_SYNCING = _MIRROR_IMAGE_STATUS_STATE_SYNCING
752 MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY
753 MIRROR_IMAGE_STATUS_STATE_REPLAYING = _MIRROR_IMAGE_STATUS_STATE_REPLAYING
754 MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = _MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY
755 MIRROR_IMAGE_STATUS_STATE_STOPPED = _MIRROR_IMAGE_STATUS_STATE_STOPPED
756
757 RBD_LOCK_MODE_EXCLUSIVE = _RBD_LOCK_MODE_EXCLUSIVE
758 RBD_LOCK_MODE_SHARED = _RBD_LOCK_MODE_SHARED
759
760 RBD_IMAGE_OPTION_FORMAT = _RBD_IMAGE_OPTION_FORMAT
761 RBD_IMAGE_OPTION_FEATURES = _RBD_IMAGE_OPTION_FEATURES
762 RBD_IMAGE_OPTION_ORDER = _RBD_IMAGE_OPTION_ORDER
763 RBD_IMAGE_OPTION_STRIPE_UNIT = _RBD_IMAGE_OPTION_STRIPE_UNIT
764 RBD_IMAGE_OPTION_STRIPE_COUNT = _RBD_IMAGE_OPTION_STRIPE_COUNT
765 RBD_IMAGE_OPTION_DATA_POOL = _RBD_IMAGE_OPTION_DATA_POOL
766
767 RBD_SNAP_NAMESPACE_TYPE_USER = _RBD_SNAP_NAMESPACE_TYPE_USER
768 RBD_SNAP_NAMESPACE_TYPE_GROUP = _RBD_SNAP_NAMESPACE_TYPE_GROUP
769 RBD_SNAP_NAMESPACE_TYPE_TRASH = _RBD_SNAP_NAMESPACE_TYPE_TRASH
770 RBD_SNAP_NAMESPACE_TYPE_MIRROR = _RBD_SNAP_NAMESPACE_TYPE_MIRROR
771
772 RBD_SNAP_MIRROR_STATE_PRIMARY = _RBD_SNAP_MIRROR_STATE_PRIMARY
773 RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED
774 RBD_SNAP_MIRROR_STATE_NON_PRIMARY = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY
775 RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED = _RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
776
777 RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
778 RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
779
780 RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
781 RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
782
783 RBD_IMAGE_MIGRATION_STATE_UNKNOWN = _RBD_IMAGE_MIGRATION_STATE_UNKNOWN
784 RBD_IMAGE_MIGRATION_STATE_ERROR = _RBD_IMAGE_MIGRATION_STATE_ERROR
785 RBD_IMAGE_MIGRATION_STATE_PREPARING = _RBD_IMAGE_MIGRATION_STATE_PREPARING
786 RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
787 RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
788 RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
789
790 RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
791 RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
792 RBD_CONFIG_SOURCE_IMAGE = _RBD_CONFIG_SOURCE_IMAGE
793
794 RBD_POOL_STAT_OPTION_IMAGES = _RBD_POOL_STAT_OPTION_IMAGES
795 RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES
796 RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES
797 RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS = _RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS
798 RBD_POOL_STAT_OPTION_TRASH_IMAGES = _RBD_POOL_STAT_OPTION_TRASH_IMAGES
799 RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES
800 RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES = _RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES
801 RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS = _RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS
802
803 RBD_SNAP_REMOVE_UNPROTECT = _RBD_SNAP_REMOVE_UNPROTECT
804 RBD_SNAP_REMOVE_FLATTEN = _RBD_SNAP_REMOVE_FLATTEN
805 RBD_SNAP_REMOVE_FORCE = _RBD_SNAP_REMOVE_FORCE
806
807 class Error(Exception):
808 pass
809
810
811 class OSError(Error):
812 """ `OSError` class, derived from `Error` """
813 def __init__(self, message, errno=None):
814 super(OSError, self).__init__(message)
815 self.errno = errno
816
817 def __str__(self):
818 msg = super(OSError, self).__str__()
819 if self.errno is None:
820 return msg
821 return '[errno {0}] {1}'.format(self.errno, msg)
822
823 def __reduce__(self):
824 return (self.__class__, (self.message, self.errno))
825
826 class PermissionError(OSError):
827 def __init__(self, message, errno=None):
828 super(PermissionError, self).__init__(
829 "RBD permission error (%s)" % message, errno)
830
831
832 class ImageNotFound(OSError):
833 def __init__(self, message, errno=None):
834 super(ImageNotFound, self).__init__(
835 "RBD image not found (%s)" % message, errno)
836
837
838 class ObjectNotFound(OSError):
839 def __init__(self, message, errno=None):
840 super(ObjectNotFound, self).__init__(
841 "RBD object not found (%s)" % message, errno)
842
843
844 class ImageExists(OSError):
845 def __init__(self, message, errno=None):
846 super(ImageExists, self).__init__(
847 "RBD image already exists (%s)" % message, errno)
848
849
850 class ObjectExists(OSError):
851 def __init__(self, message, errno=None):
852 super(ObjectExists, self).__init__(
853 "RBD object already exists (%s)" % message, errno)
854
855
856 class IOError(OSError):
857 def __init__(self, message, errno=None):
858 super(IOError, self).__init__(
859 "RBD I/O error (%s)" % message, errno)
860
861
862 class NoSpace(OSError):
863 def __init__(self, message, errno=None):
864 super(NoSpace, self).__init__(
865 "RBD insufficient space available (%s)" % message, errno)
866
867
868 class IncompleteWriteError(OSError):
869 def __init__(self, message, errno=None):
870 super(IncompleteWriteError, self).__init__(
871 "RBD incomplete write (%s)" % message, errno)
872
873
874 class InvalidArgument(OSError):
875 def __init__(self, message, errno=None):
876 super(InvalidArgument, self).__init__(
877 "RBD invalid argument (%s)" % message, errno)
878
879
880 class LogicError(OSError):
881 def __init__(self, message, errno=None):
882 super(LogicError, self).__init__(
883 "RBD logic error (%s)" % message, errno)
884
885
886 class ReadOnlyImage(OSError):
887 def __init__(self, message, errno=None):
888 super(ReadOnlyImage, self).__init__(
889 "RBD read-only image (%s)" % message, errno)
890
891
892 class ImageBusy(OSError):
893 def __init__(self, message, errno=None):
894 super(ImageBusy, self).__init__(
895 "RBD image is busy (%s)" % message, errno)
896
897
898 class ImageHasSnapshots(OSError):
899 def __init__(self, message, errno=None):
900 super(ImageHasSnapshots, self).__init__(
901 "RBD image has snapshots (%s)" % message, errno)
902
903
904 class FunctionNotSupported(OSError):
905 def __init__(self, message, errno=None):
906 super(FunctionNotSupported, self).__init__(
907 "RBD function not supported (%s)" % message, errno)
908
909
910 class ArgumentOutOfRange(OSError):
911 def __init__(self, message, errno=None):
912 super(ArgumentOutOfRange, self).__init__(
913 "RBD arguments out of range (%s)" % message, errno)
914
915
916 class ConnectionShutdown(OSError):
917 def __init__(self, message, errno=None):
918 super(ConnectionShutdown, self).__init__(
919 "RBD connection was shutdown (%s)" % message, errno)
920
921
922 class Timeout(OSError):
923 def __init__(self, message, errno=None):
924 super(Timeout, self).__init__(
925 "RBD operation timeout (%s)" % message, errno)
926
927
928 class DiskQuotaExceeded(OSError):
929 def __init__(self, message, errno=None):
930 super(DiskQuotaExceeded, self).__init__(
931 "RBD disk quota exceeded (%s)" % message, errno)
932
933 class OperationNotSupported(OSError):
934 def __init__(self, message, errno=None):
935 super(OperationNotSupported, self).__init__(
936 "RBD operation not supported (%s)" % message, errno)
937
938 class OperationCanceled(OSError):
939 def __init__(self, message, errno=None):
940 super(OperationCanceled, self).__init__(
941 "RBD operation canceled (%s)" % message, errno)
942
943 cdef errno_to_exception = {
944 errno.EPERM : PermissionError,
945 errno.ENOENT : ImageNotFound,
946 errno.EIO : IOError,
947 errno.ENOSPC : NoSpace,
948 errno.EEXIST : ImageExists,
949 errno.EINVAL : InvalidArgument,
950 errno.EROFS : ReadOnlyImage,
951 errno.EBUSY : ImageBusy,
952 errno.ENOTEMPTY : ImageHasSnapshots,
953 errno.ENOSYS : FunctionNotSupported,
954 errno.EDOM : ArgumentOutOfRange,
955 errno.ESHUTDOWN : ConnectionShutdown,
956 errno.ETIMEDOUT : Timeout,
957 errno.EDQUOT : DiskQuotaExceeded,
958 errno.EOPNOTSUPP : OperationNotSupported,
959 ECANCELED : OperationCanceled,
960 }
961
962 cdef group_errno_to_exception = {
963 errno.EPERM : PermissionError,
964 errno.ENOENT : ObjectNotFound,
965 errno.EIO : IOError,
966 errno.ENOSPC : NoSpace,
967 errno.EEXIST : ObjectExists,
968 errno.EINVAL : InvalidArgument,
969 errno.EROFS : ReadOnlyImage,
970 errno.EBUSY : ImageBusy,
971 errno.ENOTEMPTY : ImageHasSnapshots,
972 errno.ENOSYS : FunctionNotSupported,
973 errno.EDOM : ArgumentOutOfRange,
974 errno.ESHUTDOWN : ConnectionShutdown,
975 errno.ETIMEDOUT : Timeout,
976 errno.EDQUOT : DiskQuotaExceeded,
977 errno.EOPNOTSUPP : OperationNotSupported,
978 ECANCELED : OperationCanceled,
979 }
980
981 cdef make_ex(ret, msg, exception_map=errno_to_exception):
982 """
983 Translate a librbd return code into an exception.
984
985 :param ret: the return code
986 :type ret: int
987 :param msg: the error message to use
988 :type msg: str
989 :returns: a subclass of :class:`Error`
990 """
991 ret = abs(ret)
992 if ret in exception_map:
993 return exception_map[ret](msg, errno=ret)
994 else:
995 return OSError(msg, errno=ret)
996
997
998 cdef rados_t convert_rados(rados.Rados rados) except? NULL:
999 return <rados_t>rados.cluster
1000
1001 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
1002 return <rados_ioctx_t>ioctx.io
1003
1004 cdef int progress_callback(uint64_t offset, uint64_t total, void* ptr) with gil:
1005 return (<object>ptr)(offset, total)
1006
1007 cdef int no_op_progress_callback(uint64_t offset, uint64_t total, void* ptr):
1008 return 0
1009
1010 def cstr(val, name, encoding="utf-8", opt=False):
1011 """
1012 Create a byte string from a Python string
1013
1014 :param basestring val: Python string
1015 :param str name: Name of the string parameter, for exceptions
1016 :param str encoding: Encoding to use
1017 :param bool opt: If True, None is allowed
1018 :rtype: bytes
1019 :raises: :class:`InvalidArgument`
1020 """
1021 if opt and val is None:
1022 return None
1023 if isinstance(val, bytes):
1024 return val
1025 elif isinstance(val, str):
1026 return val.encode(encoding)
1027 elif sys.version_info < (3, 0) and isinstance(val, unicode):
1028 return val.encode(encoding)
1029 else:
1030 raise InvalidArgument('%s must be a string' % name)
1031
1032 def decode_cstr(val, encoding="utf-8"):
1033 """
1034 Decode a byte string into a Python string.
1035
1036 :param bytes val: byte string
1037 :rtype: unicode or None
1038 """
1039 if val is None:
1040 return None
1041
1042 return val.decode(encoding)
1043
1044
1045 cdef char* opt_str(s) except? NULL:
1046 if s is None:
1047 return NULL
1048 return s
1049
1050 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
1051 cdef void *ret = realloc(ptr, size)
1052 if ret == NULL:
1053 raise MemoryError("realloc failed")
1054 return ret
1055
1056 RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST)
1057 RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY = decode_cstr(_RBD_MIRROR_PEER_ATTRIBUTE_NAME_KEY)
1058
1059 cdef class Completion
1060
1061 cdef void __aio_complete_cb(rbd_completion_t completion, void *args) with gil:
1062 """
1063 Callback to oncomplete() for asynchronous operations
1064 """
1065 cdef Completion cb = <Completion>args
1066 cb._complete()
1067
1068
1069 cdef class Completion(object):
1070 """completion object"""
1071
1072 cdef:
1073 object image
1074 object oncomplete
1075 rbd_completion_t rbd_comp
1076 PyObject* buf
1077 bint persisted
1078 object exc_info
1079
1080 def __cinit__(self, image, object oncomplete):
1081 self.oncomplete = oncomplete
1082 self.image = image
1083 self.persisted = False
1084
1085 def is_complete(self):
1086 """
1087 Has an asynchronous operation completed?
1088
1089 This does not imply that the callback has finished.
1090
1091 :returns: True if the operation is completed
1092 """
1093 with nogil:
1094 ret = rbd_aio_is_complete(self.rbd_comp)
1095 return ret == 1
1096
1097 def wait_for_complete_and_cb(self):
1098 """
1099 Wait for an asynchronous operation to complete
1100
1101 This method waits for the callback to execute, if one was provided.
1102 It will also re-raise any exceptions raised by the callback. You
1103 should call this to "reap" asynchronous completions and ensure that
1104 any exceptions in the callbacks are handled, as an exception internal
1105 to this module may have occurred.
1106 """
1107 with nogil:
1108 rbd_aio_wait_for_complete(self.rbd_comp)
1109
1110 if self.exc_info:
1111 raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
1112
1113 def get_return_value(self):
1114 """
1115 Get the return value of an asychronous operation
1116
1117 The return value is set when the operation is complete.
1118
1119 :returns: int - return value of the operation
1120 """
1121 with nogil:
1122 ret = rbd_aio_get_return_value(self.rbd_comp)
1123 return ret
1124
1125 def __dealloc__(self):
1126 """
1127 Release a completion
1128
1129 This is automatically called when the completion object is freed.
1130 """
1131 ref.Py_XDECREF(self.buf)
1132 self.buf = NULL
1133 if self.rbd_comp != NULL:
1134 with nogil:
1135 rbd_aio_release(self.rbd_comp)
1136 self.rbd_comp = NULL
1137
1138 cdef void _complete(self):
1139 try:
1140 self.__unpersist()
1141 if self.oncomplete:
1142 self.oncomplete(self)
1143 # In the event that something raises an exception during the next 2
1144 # lines of code, we will not be able to catch it, and this may result
1145 # in the app not noticing a failed callback. However, this should only
1146 # happen in extreme circumstances (OOM, etc.). KeyboardInterrupt
1147 # should not be a problem because the callback thread from librbd
1148 # ought to have SIGINT blocked.
1149 except:
1150 self.exc_info = sys.exc_info()
1151
1152 cdef __persist(self):
1153 if self.oncomplete is not None and not self.persisted:
1154 # Increment our own reference count to make sure the completion
1155 # is not freed until the callback is called. The completion is
1156 # allowed to be freed if there is no callback.
1157 ref.Py_INCREF(self)
1158 self.persisted = True
1159
1160 cdef __unpersist(self):
1161 if self.persisted:
1162 ref.Py_DECREF(self)
1163 self.persisted = False
1164
1165
1166 class RBD(object):
1167 """
1168 This class wraps librbd CRUD functions.
1169 """
1170 def version(self):
1171 """
1172 Get the version number of the ``librbd`` C library.
1173
1174 :returns: a tuple of ``(major, minor, extra)`` components of the
1175 librbd version
1176 """
1177 cdef int major = 0
1178 cdef int minor = 0
1179 cdef int extra = 0
1180 rbd_version(&major, &minor, &extra)
1181 return (major, minor, extra)
1182
1183 def create(self, ioctx, name, size, order=None, old_format=True,
1184 features=None, stripe_unit=None, stripe_count=None,
1185 data_pool=None):
1186 """
1187 Create an rbd image.
1188
1189 :param ioctx: the context in which to create the image
1190 :type ioctx: :class:`rados.Ioctx`
1191 :param name: what the image is called
1192 :type name: str
1193 :param size: how big the image is in bytes
1194 :type size: int
1195 :param order: the image is split into (2**order) byte objects
1196 :type order: int
1197 :param old_format: whether to create an old-style image that
1198 is accessible by old clients, but can't
1199 use more advanced features like layering.
1200 :type old_format: bool
1201 :param features: bitmask of features to enable
1202 :type features: int
1203 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1204 :type stripe_unit: int
1205 :param stripe_count: objects to stripe over before looping
1206 :type stripe_count: int
1207 :param data_pool: optional separate pool for data blocks
1208 :type data_pool: str
1209 :raises: :class:`ImageExists`
1210 :raises: :class:`TypeError`
1211 :raises: :class:`InvalidArgument`
1212 :raises: :class:`FunctionNotSupported`
1213 """
1214 name = cstr(name, 'name')
1215 data_pool = cstr(data_pool, 'data_pool', opt=True)
1216 cdef:
1217 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1218 char *_name = name
1219 uint64_t _size = size
1220 int _order = 0
1221 rbd_image_options_t opts
1222 if order is not None:
1223 _order = order
1224 if old_format:
1225 if (features or
1226 ((stripe_unit is not None) and stripe_unit != 0) or
1227 ((stripe_count is not None) and stripe_count != 0) or
1228 data_pool):
1229 raise InvalidArgument('format 1 images do not support feature '
1230 'masks, non-default striping, nor data '
1231 'pool')
1232 with nogil:
1233 ret = rbd_create(_ioctx, _name, _size, &_order)
1234 else:
1235 rbd_image_options_create(&opts)
1236 try:
1237 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FORMAT,
1238 1 if old_format else 2)
1239 if features is not None:
1240 rbd_image_options_set_uint64(opts,
1241 RBD_IMAGE_OPTION_FEATURES,
1242 features)
1243 if order is not None:
1244 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1245 _order)
1246 if stripe_unit is not None:
1247 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1248 stripe_unit)
1249 if stripe_count is not None:
1250 rbd_image_options_set_uint64(opts,
1251 RBD_IMAGE_OPTION_STRIPE_COUNT,
1252 stripe_count)
1253 if data_pool is not None:
1254 rbd_image_options_set_string(opts,
1255 RBD_IMAGE_OPTION_DATA_POOL,
1256 data_pool)
1257 with nogil:
1258 ret = rbd_create4(_ioctx, _name, _size, opts)
1259 finally:
1260 rbd_image_options_destroy(opts)
1261 if ret < 0:
1262 raise make_ex(ret, 'error creating image')
1263
1264 def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
1265 features=None, order=None, stripe_unit=None, stripe_count=None,
1266 data_pool=None):
1267 """
1268 Clone a parent rbd snapshot into a COW sparse child.
1269
1270 :param p_ioctx: the parent context that represents the parent snap
1271 :type ioctx: :class:`rados.Ioctx`
1272 :param p_name: the parent image name
1273 :type name: str
1274 :param p_snapname: the parent image snapshot name
1275 :type name: str
1276 :param c_ioctx: the child context that represents the new clone
1277 :type ioctx: :class:`rados.Ioctx`
1278 :param c_name: the clone (child) name
1279 :type name: str
1280 :param features: bitmask of features to enable; if set, must include layering
1281 :type features: int
1282 :param order: the image is split into (2**order) byte objects
1283 :type order: int
1284 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1285 :type stripe_unit: int
1286 :param stripe_count: objects to stripe over before looping
1287 :type stripe_count: int
1288 :param data_pool: optional separate pool for data blocks
1289 :type data_pool: str
1290 :raises: :class:`TypeError`
1291 :raises: :class:`InvalidArgument`
1292 :raises: :class:`ImageExists`
1293 :raises: :class:`FunctionNotSupported`
1294 :raises: :class:`ArgumentOutOfRange`
1295 """
1296 p_snapname = cstr(p_snapname, 'p_snapname')
1297 p_name = cstr(p_name, 'p_name')
1298 c_name = cstr(c_name, 'c_name')
1299 data_pool = cstr(data_pool, 'data_pool', opt=True)
1300 cdef:
1301 rados_ioctx_t _p_ioctx = convert_ioctx(p_ioctx)
1302 rados_ioctx_t _c_ioctx = convert_ioctx(c_ioctx)
1303 char *_p_name = p_name
1304 char *_p_snapname = p_snapname
1305 char *_c_name = c_name
1306 rbd_image_options_t opts
1307
1308 rbd_image_options_create(&opts)
1309 try:
1310 if features is not None:
1311 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1312 features)
1313 if order is not None:
1314 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1315 order)
1316 if stripe_unit is not None:
1317 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1318 stripe_unit)
1319 if stripe_count is not None:
1320 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1321 stripe_count)
1322 if data_pool is not None:
1323 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1324 data_pool)
1325 with nogil:
1326 ret = rbd_clone3(_p_ioctx, _p_name, _p_snapname,
1327 _c_ioctx, _c_name, opts)
1328 finally:
1329 rbd_image_options_destroy(opts)
1330 if ret < 0:
1331 raise make_ex(ret, 'error creating clone')
1332
1333 def list(self, ioctx):
1334 """
1335 List image names.
1336
1337 :param ioctx: determines which RADOS pool is read
1338 :type ioctx: :class:`rados.Ioctx`
1339 :returns: list -- a list of image names
1340 """
1341 cdef:
1342 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1343 size_t size = 512
1344 char *c_names = NULL
1345 try:
1346 while True:
1347 c_names = <char *>realloc_chk(c_names, size)
1348 with nogil:
1349 ret = rbd_list(_ioctx, c_names, &size)
1350 if ret >= 0:
1351 break
1352 elif ret != -errno.ERANGE:
1353 raise make_ex(ret, 'error listing images')
1354 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
1355 if name]
1356 finally:
1357 free(c_names)
1358
1359 def list2(self, ioctx):
1360 """
1361 Iterate over the images in the pool.
1362
1363 :param ioctx: determines which RADOS pool the image is in
1364 :type ioctx: :class:`rados.Ioctx`
1365 :returns: :class:`ImageIterator`
1366 """
1367 return ImageIterator(ioctx)
1368
1369 def remove(self, ioctx, name, on_progress=None):
1370 """
1371 Delete an RBD image. This may take a long time, since it does
1372 not return until every object that comprises the image has
1373 been deleted. Note that all snapshots must be deleted before
1374 the image can be removed. If there are snapshots left,
1375 :class:`ImageHasSnapshots` is raised. If the image is still
1376 open, or the watch from a crashed client has not expired,
1377 :class:`ImageBusy` is raised.
1378
1379 :param ioctx: determines which RADOS pool the image is in
1380 :type ioctx: :class:`rados.Ioctx`
1381 :param name: the name of the image to remove
1382 :type name: str
1383 :param on_progress: optional progress callback function
1384 :type on_progress: callback function
1385 :raises: :class:`ImageNotFound`, :class:`ImageBusy`,
1386 :class:`ImageHasSnapshots`
1387 """
1388 name = cstr(name, 'name')
1389 cdef:
1390 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1391 char *_name = name
1392 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1393 void *_prog_arg = NULL
1394 if on_progress:
1395 _prog_cb = &progress_callback
1396 _prog_arg = <void *>on_progress
1397 with nogil:
1398 ret = rbd_remove_with_progress(_ioctx, _name, _prog_cb, _prog_arg)
1399 if ret != 0:
1400 raise make_ex(ret, 'error removing image')
1401
1402 def rename(self, ioctx, src, dest):
1403 """
1404 Rename an RBD image.
1405
1406 :param ioctx: determines which RADOS pool the image is in
1407 :type ioctx: :class:`rados.Ioctx`
1408 :param src: the current name of the image
1409 :type src: str
1410 :param dest: the new name of the image
1411 :type dest: str
1412 :raises: :class:`ImageNotFound`, :class:`ImageExists`
1413 """
1414 src = cstr(src, 'src')
1415 dest = cstr(dest, 'dest')
1416 cdef:
1417 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1418 char *_src = src
1419 char *_dest = dest
1420 with nogil:
1421 ret = rbd_rename(_ioctx, _src, _dest)
1422 if ret != 0:
1423 raise make_ex(ret, 'error renaming image')
1424
1425 def trash_move(self, ioctx, name, delay=0):
1426 """
1427 Move an RBD image to the trash.
1428
1429 :param ioctx: determines which RADOS pool the image is in
1430 :type ioctx: :class:`rados.Ioctx`
1431 :param name: the name of the image to remove
1432 :type name: str
1433 :param delay: time delay in seconds before the image can be deleted
1434 from trash
1435 :type delay: int
1436 :raises: :class:`ImageNotFound`
1437 """
1438 name = cstr(name, 'name')
1439 cdef:
1440 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1441 char *_name = name
1442 uint64_t _delay = delay
1443 with nogil:
1444 ret = rbd_trash_move(_ioctx, _name, _delay)
1445 if ret != 0:
1446 raise make_ex(ret, 'error moving image to trash')
1447
1448 def trash_purge(self, ioctx, expire_ts=None, threshold=-1):
1449 """
1450 Delete RBD images from trash in bulk.
1451
1452 By default it removes images with deferment end time less than now.
1453
1454 The timestamp is configurable, e.g. delete images that have expired a
1455 week ago.
1456
1457 If the threshold is used it deletes images until X% pool usage is met.
1458
1459 :param ioctx: determines which RADOS pool the image is in
1460 :type ioctx: :class:`rados.Ioctx`
1461 :param expire_ts: timestamp for images to be considered as expired (UTC)
1462 :type expire_ts: datetime
1463 :param threshold: percentage of pool usage to be met (0 to 1)
1464 :type threshold: float
1465 """
1466 if expire_ts:
1467 expire_epoch_ts = time.mktime(expire_ts.timetuple())
1468 else:
1469 expire_epoch_ts = 0
1470
1471 cdef:
1472 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1473 time_t _expire_ts = expire_epoch_ts
1474 float _threshold = threshold
1475 with nogil:
1476 ret = rbd_trash_purge(_ioctx, _expire_ts, _threshold)
1477 if ret != 0:
1478 raise make_ex(ret, 'error purging images from trash')
1479
1480 def trash_remove(self, ioctx, image_id, force=False, on_progress=None):
1481 """
1482 Delete an RBD image from trash. If image deferment time has not
1483 expired :class:`PermissionError` is raised.
1484
1485 :param ioctx: determines which RADOS pool the image is in
1486 :type ioctx: :class:`rados.Ioctx`
1487 :param image_id: the id of the image to remove
1488 :type image_id: str
1489 :param force: force remove even if deferment time has not expired
1490 :type force: bool
1491 :param on_progress: optional progress callback function
1492 :type on_progress: callback function
1493 :raises: :class:`ImageNotFound`, :class:`PermissionError`
1494 """
1495 image_id = cstr(image_id, 'image_id')
1496 cdef:
1497 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1498 char *_image_id = image_id
1499 int _force = force
1500 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1501 void *_prog_arg = NULL
1502 if on_progress:
1503 _prog_cb = &progress_callback
1504 _prog_arg = <void *>on_progress
1505 with nogil:
1506 ret = rbd_trash_remove_with_progress(_ioctx, _image_id, _force,
1507 _prog_cb, _prog_arg)
1508 if ret != 0:
1509 raise make_ex(ret, 'error deleting image from trash')
1510
1511 def trash_get(self, ioctx, image_id):
1512 """
1513 Retrieve RBD image info from trash.
1514
1515 :param ioctx: determines which RADOS pool the image is in
1516 :type ioctx: :class:`rados.Ioctx`
1517 :param image_id: the id of the image to restore
1518 :type image_id: str
1519 :returns: dict - contains the following keys:
1520
1521 * ``id`` (str) - image id
1522
1523 * ``name`` (str) - image name
1524
1525 * ``source`` (str) - source of deletion
1526
1527 * ``deletion_time`` (datetime) - time of deletion
1528
1529 * ``deferment_end_time`` (datetime) - time that an image is allowed
1530 to be removed from trash
1531
1532 :raises: :class:`ImageNotFound`
1533 """
1534 image_id = cstr(image_id, 'image_id')
1535 cdef:
1536 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1537 char *_image_id = image_id
1538 rbd_trash_image_info_t c_info
1539 with nogil:
1540 ret = rbd_trash_get(_ioctx, _image_id, &c_info)
1541 if ret != 0:
1542 raise make_ex(ret, 'error retrieving image from trash')
1543
1544 __source_string = ['USER', 'MIRRORING', 'MIGRATION', 'REMOVING']
1545 info = {
1546 'id' : decode_cstr(c_info.id),
1547 'name' : decode_cstr(c_info.name),
1548 'source' : __source_string[c_info.source],
1549 'deletion_time' : datetime.utcfromtimestamp(c_info.deletion_time),
1550 'deferment_end_time' : datetime.utcfromtimestamp(c_info.deferment_end_time)
1551 }
1552 rbd_trash_get_cleanup(&c_info)
1553 return info
1554
1555 def trash_list(self, ioctx):
1556 """
1557 List all entries from trash.
1558
1559 :param ioctx: determines which RADOS pool the image is in
1560 :type ioctx: :class:`rados.Ioctx`
1561 :returns: :class:`TrashIterator`
1562 """
1563 return TrashIterator(ioctx)
1564
1565 def trash_restore(self, ioctx, image_id, name):
1566 """
1567 Restore an RBD image from trash.
1568
1569 :param ioctx: determines which RADOS pool the image is in
1570 :type ioctx: :class:`rados.Ioctx`
1571 :param image_id: the id of the image to restore
1572 :type image_id: str
1573 :param name: the new name of the restored image
1574 :type name: str
1575 :raises: :class:`ImageNotFound`
1576 """
1577 image_id = cstr(image_id, 'image_id')
1578 name = cstr(name, 'name')
1579 cdef:
1580 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1581 char *_image_id = image_id
1582 char *_name = name
1583 with nogil:
1584 ret = rbd_trash_restore(_ioctx, _image_id, _name)
1585 if ret != 0:
1586 raise make_ex(ret, 'error restoring image from trash')
1587
1588 def migration_prepare(self, ioctx, image_name, dest_ioctx, dest_image_name,
1589 features=None, order=None, stripe_unit=None, stripe_count=None,
1590 data_pool=None):
1591 """
1592 Prepare an RBD image migration.
1593
1594 :param ioctx: determines which RADOS pool the image is in
1595 :type ioctx: :class:`rados.Ioctx`
1596 :param image_name: the current name of the image
1597 :type src: str
1598 :param dest_ioctx: determines which pool to migration into
1599 :type dest_ioctx: :class:`rados.Ioctx`
1600 :param dest_image_name: the name of the destination image (may be the same image)
1601 :type dest_image_name: str
1602 :param features: bitmask of features to enable; if set, must include layering
1603 :type features: int
1604 :param order: the image is split into (2**order) byte objects
1605 :type order: int
1606 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
1607 :type stripe_unit: int
1608 :param stripe_count: objects to stripe over before looping
1609 :type stripe_count: int
1610 :param data_pool: optional separate pool for data blocks
1611 :type data_pool: str
1612 :raises: :class:`TypeError`
1613 :raises: :class:`InvalidArgument`
1614 :raises: :class:`ImageExists`
1615 :raises: :class:`FunctionNotSupported`
1616 :raises: :class:`ArgumentOutOfRange`
1617 """
1618 image_name = cstr(image_name, 'image_name')
1619 dest_image_name = cstr(dest_image_name, 'dest_image_name')
1620 cdef:
1621 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1622 char *_image_name = image_name
1623 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
1624 char *_dest_image_name = dest_image_name
1625 rbd_image_options_t opts
1626
1627 rbd_image_options_create(&opts)
1628 try:
1629 if features is not None:
1630 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
1631 features)
1632 if order is not None:
1633 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
1634 order)
1635 if stripe_unit is not None:
1636 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
1637 stripe_unit)
1638 if stripe_count is not None:
1639 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
1640 stripe_count)
1641 if data_pool is not None:
1642 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
1643 data_pool)
1644 with nogil:
1645 ret = rbd_migration_prepare(_ioctx, _image_name, _dest_ioctx,
1646 _dest_image_name, opts)
1647 finally:
1648 rbd_image_options_destroy(opts)
1649 if ret < 0:
1650 raise make_ex(ret, 'error migrating image %s' % (image_name))
1651
1652 def migration_execute(self, ioctx, image_name, on_progress=None):
1653 """
1654 Execute a prepared RBD image migration.
1655
1656 :param ioctx: determines which RADOS pool the image is in
1657 :type ioctx: :class:`rados.Ioctx`
1658 :param image_name: the name of the image
1659 :type image_name: str
1660 :param on_progress: optional progress callback function
1661 :type on_progress: callback function
1662 :raises: :class:`ImageNotFound`
1663 """
1664 image_name = cstr(image_name, 'image_name')
1665 cdef:
1666 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1667 char *_image_name = image_name
1668 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1669 void *_prog_arg = NULL
1670 if on_progress:
1671 _prog_cb = &progress_callback
1672 _prog_arg = <void *>on_progress
1673 with nogil:
1674 ret = rbd_migration_execute_with_progress(_ioctx, _image_name,
1675 _prog_cb, _prog_arg)
1676 if ret != 0:
1677 raise make_ex(ret, 'error aborting migration')
1678
1679 def migration_commit(self, ioctx, image_name, on_progress=None):
1680 """
1681 Commit an executed RBD image migration.
1682
1683 :param ioctx: determines which RADOS pool the image is in
1684 :type ioctx: :class:`rados.Ioctx`
1685 :param image_name: the name of the image
1686 :type image_name: str
1687 :param on_progress: optional progress callback function
1688 :type on_progress: callback function
1689 :raises: :class:`ImageNotFound`
1690 """
1691 image_name = cstr(image_name, 'image_name')
1692 cdef:
1693 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1694 char *_image_name = image_name
1695 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1696 void *_prog_arg = NULL
1697 if on_progress:
1698 _prog_cb = &progress_callback
1699 _prog_arg = <void *>on_progress
1700 with nogil:
1701 ret = rbd_migration_commit_with_progress(_ioctx, _image_name,
1702 _prog_cb, _prog_arg)
1703 if ret != 0:
1704 raise make_ex(ret, 'error aborting migration')
1705
1706 def migration_abort(self, ioctx, image_name, on_progress=None):
1707 """
1708 Cancel a previously started but interrupted migration.
1709
1710 :param ioctx: determines which RADOS pool the image is in
1711 :type ioctx: :class:`rados.Ioctx`
1712 :param image_name: the name of the image
1713 :type image_name: str
1714 :param on_progress: optional progress callback function
1715 :type on_progress: callback function
1716 :raises: :class:`ImageNotFound`
1717 """
1718 image_name = cstr(image_name, 'image_name')
1719 cdef:
1720 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1721 char *_image_name = image_name
1722 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
1723 void *_prog_arg = NULL
1724 if on_progress:
1725 _prog_cb = &progress_callback
1726 _prog_arg = <void *>on_progress
1727 with nogil:
1728 ret = rbd_migration_abort_with_progress(_ioctx, _image_name,
1729 _prog_cb, _prog_arg)
1730 if ret != 0:
1731 raise make_ex(ret, 'error aborting migration')
1732
1733 def migration_status(self, ioctx, image_name):
1734 """
1735 Return RBD image migration status.
1736
1737 :param ioctx: determines which RADOS pool the image is in
1738 :type ioctx: :class:`rados.Ioctx`
1739 :param image_name: the name of the image
1740 :type image_name: str
1741 :returns: dict - contains the following keys:
1742
1743 * ``source_pool_id`` (int) - source image pool id
1744
1745 * ``source_pool_namespace`` (str) - source image pool namespace
1746
1747 * ``source_image_name`` (str) - source image name
1748
1749 * ``source_image_id`` (str) - source image id
1750
1751 * ``dest_pool_id`` (int) - destination image pool id
1752
1753 * ``dest_pool_namespace`` (str) - destination image pool namespace
1754
1755 * ``dest_image_name`` (str) - destination image name
1756
1757 * ``dest_image_id`` (str) - destination image id
1758
1759 * ``state`` (int) - current migration state
1760
1761 * ``state_description`` (str) - migration state description
1762
1763 :raises: :class:`ImageNotFound`
1764 """
1765 image_name = cstr(image_name, 'image_name')
1766 cdef:
1767 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1768 char *_image_name = image_name
1769 rbd_image_migration_status_t c_status
1770 with nogil:
1771 ret = rbd_migration_status(_ioctx, _image_name, &c_status,
1772 sizeof(c_status))
1773 if ret != 0:
1774 raise make_ex(ret, 'error getting migration status')
1775
1776 status = {
1777 'source_pool_id' : c_status.source_pool_id,
1778 'source_pool_namespace' : decode_cstr(c_status.source_pool_namespace),
1779 'source_image_name' : decode_cstr(c_status.source_image_name),
1780 'source_image_id' : decode_cstr(c_status.source_image_id),
1781 'dest_pool_id' : c_status.source_pool_id,
1782 'dest_pool_namespace' : decode_cstr(c_status.dest_pool_namespace),
1783 'dest_image_name' : decode_cstr(c_status.dest_image_name),
1784 'dest_image_id' : decode_cstr(c_status.dest_image_id),
1785 'state' : c_status.state,
1786 'state_description' : decode_cstr(c_status.state_description)
1787 }
1788
1789 rbd_migration_status_cleanup(&c_status)
1790
1791 return status
1792
1793 def mirror_site_name_get(self, rados):
1794 """
1795 Get the local cluster's friendly site name
1796
1797 :param rados: cluster connection
1798 :type rados: :class: rados.Rados
1799 :returns: str - local site name
1800 """
1801 cdef:
1802 rados_t _rados = convert_rados(rados)
1803 char *_site_name = NULL
1804 size_t _max_size = 512
1805 try:
1806 while True:
1807 _site_name = <char *>realloc_chk(_site_name, _max_size)
1808 with nogil:
1809 ret = rbd_mirror_site_name_get(_rados, _site_name,
1810 &_max_size)
1811 if ret >= 0:
1812 break
1813 elif ret != -errno.ERANGE:
1814 raise make_ex(ret, 'error getting site name')
1815 return decode_cstr(_site_name)
1816 finally:
1817 free(_site_name)
1818
1819 def mirror_site_name_set(self, rados, site_name):
1820 """
1821 Set the local cluster's friendly site name
1822
1823 :param rados: cluster connection
1824 :type rados: :class: rados.Rados
1825 :param site_name: friendly site name
1826 :type str:
1827 """
1828 site_name = cstr(site_name, 'site_name')
1829 cdef:
1830 rados_t _rados = convert_rados(rados)
1831 char *_site_name = site_name
1832 with nogil:
1833 ret = rbd_mirror_site_name_set(_rados, _site_name)
1834 if ret != 0:
1835 raise make_ex(ret, 'error setting mirror site name')
1836
1837 def mirror_mode_get(self, ioctx):
1838 """
1839 Get pool mirror mode.
1840
1841 :param ioctx: determines which RADOS pool is read
1842 :type ioctx: :class:`rados.Ioctx`
1843 :returns: int - pool mirror mode
1844 """
1845 cdef:
1846 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1847 rbd_mirror_mode_t mirror_mode
1848 with nogil:
1849 ret = rbd_mirror_mode_get(_ioctx, &mirror_mode)
1850 if ret != 0:
1851 raise make_ex(ret, 'error getting mirror mode')
1852 return mirror_mode
1853
1854 def mirror_mode_set(self, ioctx, mirror_mode):
1855 """
1856 Set pool mirror mode.
1857
1858 :param ioctx: determines which RADOS pool is written
1859 :type ioctx: :class:`rados.Ioctx`
1860 :param mirror_mode: mirror mode to set
1861 :type mirror_mode: int
1862 """
1863 cdef:
1864 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1865 rbd_mirror_mode_t _mirror_mode = mirror_mode
1866 with nogil:
1867 ret = rbd_mirror_mode_set(_ioctx, _mirror_mode)
1868 if ret != 0:
1869 raise make_ex(ret, 'error setting mirror mode')
1870
1871 def mirror_uuid_get(self, ioctx):
1872 """
1873 Get pool mirror uuid
1874
1875 :param ioctx: determines which RADOS pool is read
1876 :type ioctx: :class:`rados.Ioctx`
1877 :returns: ste - pool mirror uuid
1878 """
1879 cdef:
1880 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1881 char *_uuid = NULL
1882 size_t _max_size = 512
1883 try:
1884 while True:
1885 _uuid = <char *>realloc_chk(_uuid, _max_size)
1886 with nogil:
1887 ret = rbd_mirror_uuid_get(_ioctx, _uuid, &_max_size)
1888 if ret >= 0:
1889 break
1890 elif ret != -errno.ERANGE:
1891 raise make_ex(ret, 'error retrieving mirror uuid')
1892 return decode_cstr(_uuid)
1893 finally:
1894 free(_uuid)
1895
1896 def mirror_peer_bootstrap_create(self, ioctx):
1897 """
1898 Creates a new RBD mirroring bootstrap token for an
1899 external cluster.
1900
1901 :param ioctx: determines which RADOS pool is written
1902 :type ioctx: :class:`rados.Ioctx`
1903 :returns: str - bootstrap token
1904 """
1905 cdef:
1906 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1907 char *_token = NULL
1908 size_t _max_size = 512
1909 try:
1910 while True:
1911 _token = <char *>realloc_chk(_token, _max_size)
1912 with nogil:
1913 ret = rbd_mirror_peer_bootstrap_create(_ioctx, _token,
1914 &_max_size)
1915 if ret >= 0:
1916 break
1917 elif ret != -errno.ERANGE:
1918 raise make_ex(ret, 'error creating bootstrap token')
1919 return decode_cstr(_token)
1920 finally:
1921 free(_token)
1922
1923 def mirror_peer_bootstrap_import(self, ioctx, direction, token):
1924 """
1925 Import a bootstrap token from an external cluster to
1926 auto-configure the mirror peer.
1927
1928 :param ioctx: determines which RADOS pool is written
1929 :type ioctx: :class:`rados.Ioctx`
1930 :param direction: mirror peer direction
1931 :type direction: int
1932 :param token: bootstrap token
1933 :type token: str
1934 """
1935 token = cstr(token, 'token')
1936 cdef:
1937 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1938 rbd_mirror_peer_direction_t _direction = direction
1939 char *_token = token
1940 with nogil:
1941 ret = rbd_mirror_peer_bootstrap_import(_ioctx, _direction, _token)
1942 if ret != 0:
1943 raise make_ex(ret, 'error importing bootstrap token')
1944
1945 def mirror_peer_add(self, ioctx, site_name, client_name,
1946 direction=RBD_MIRROR_PEER_DIRECTION_RX_TX):
1947 """
1948 Add mirror peer.
1949
1950 :param ioctx: determines which RADOS pool is used
1951 :type ioctx: :class:`rados.Ioctx`
1952 :param site_name: mirror peer site name
1953 :type site_name: str
1954 :param client_name: mirror peer client name
1955 :type client_name: str
1956 :param direction: the direction of the mirroring
1957 :type direction: int
1958 :returns: str - peer uuid
1959 """
1960 site_name = cstr(site_name, 'site_name')
1961 client_name = cstr(client_name, 'client_name')
1962 cdef:
1963 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1964 char *_uuid = NULL
1965 size_t _uuid_max_length = 512
1966 rbd_mirror_peer_direction_t _direction = direction
1967 char *_site_name = site_name
1968 char *_client_name = client_name
1969 try:
1970 _uuid = <char *>realloc_chk(_uuid, _uuid_max_length)
1971 ret = rbd_mirror_peer_site_add(_ioctx, _uuid, _uuid_max_length,
1972 _direction, _site_name, _client_name)
1973 if ret != 0:
1974 raise make_ex(ret, 'error adding mirror peer')
1975 return decode_cstr(_uuid)
1976 finally:
1977 free(_uuid)
1978
1979 def mirror_peer_remove(self, ioctx, uuid):
1980 """
1981 Remove mirror peer.
1982
1983 :param ioctx: determines which RADOS pool is used
1984 :type ioctx: :class:`rados.Ioctx`
1985 :param uuid: peer uuid
1986 :type uuid: str
1987 """
1988 uuid = cstr(uuid, 'uuid')
1989 cdef:
1990 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
1991 char *_uuid = uuid
1992 with nogil:
1993 ret = rbd_mirror_peer_site_remove(_ioctx, _uuid)
1994 if ret != 0:
1995 raise make_ex(ret, 'error removing mirror peer')
1996
1997 def mirror_peer_list(self, ioctx):
1998 """
1999 Iterate over the peers of a pool.
2000
2001 :param ioctx: determines which RADOS pool is read
2002 :type ioctx: :class:`rados.Ioctx`
2003 :returns: :class:`MirrorPeerIterator`
2004 """
2005 return MirrorPeerIterator(ioctx)
2006
2007 def mirror_peer_set_client(self, ioctx, uuid, client_name):
2008 """
2009 Set mirror peer client name
2010
2011 :param ioctx: determines which RADOS pool is written
2012 :type ioctx: :class:`rados.Ioctx`
2013 :param uuid: uuid of the mirror peer
2014 :type uuid: str
2015 :param client_name: client name of the mirror peer to set
2016 :type client_name: str
2017 """
2018 uuid = cstr(uuid, 'uuid')
2019 client_name = cstr(client_name, 'client_name')
2020 cdef:
2021 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2022 char *_uuid = uuid
2023 char *_client_name = client_name
2024 with nogil:
2025 ret = rbd_mirror_peer_site_set_client_name(_ioctx, _uuid,
2026 _client_name)
2027 if ret != 0:
2028 raise make_ex(ret, 'error setting mirror peer client name')
2029
2030 def mirror_peer_set_name(self, ioctx, uuid, site_name):
2031 """
2032 Set mirror peer site name
2033
2034 :param ioctx: determines which RADOS pool is written
2035 :type ioctx: :class:`rados.Ioctx`
2036 :param uuid: uuid of the mirror peer
2037 :type uuid: str
2038 :param site_name: site name of the mirror peer to set
2039 :type site_name: str
2040 """
2041 uuid = cstr(uuid, 'uuid')
2042 site_name = cstr(site_name, 'site_name')
2043 cdef:
2044 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2045 char *_uuid = uuid
2046 char *_site_name = site_name
2047 with nogil:
2048 ret = rbd_mirror_peer_site_set_name(_ioctx, _uuid, _site_name)
2049 if ret != 0:
2050 raise make_ex(ret, 'error setting mirror peer site name')
2051
2052 def mirror_peer_set_cluster(self, ioctx, uuid, cluster_name):
2053 self.mirror_peer_set_name(ioctx, uuid, cluster_name)
2054
2055 def mirror_peer_get_attributes(self, ioctx, uuid):
2056 """
2057 Get optional mirror peer attributes
2058
2059 :param ioctx: determines which RADOS pool is written
2060 :type ioctx: :class:`rados.Ioctx`
2061 :param uuid: uuid of the mirror peer
2062 :type uuid: str
2063
2064 :returns: dict - contains the following keys:
2065
2066 * ``mon_host`` (str) - monitor addresses
2067
2068 * ``key`` (str) - CephX key
2069 """
2070 uuid = cstr(uuid, 'uuid')
2071 cdef:
2072 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2073 char *_uuid = uuid
2074 char *_keys = NULL
2075 char *_vals = NULL
2076 size_t _keys_size = 512
2077 size_t _vals_size = 512
2078 size_t _count = 0
2079 try:
2080 while True:
2081 _keys = <char *>realloc_chk(_keys, _keys_size)
2082 _vals = <char *>realloc_chk(_vals, _vals_size)
2083 with nogil:
2084 ret = rbd_mirror_peer_site_get_attributes(
2085 _ioctx, _uuid, _keys, &_keys_size, _vals, &_vals_size,
2086 &_count)
2087 if ret >= 0:
2088 break
2089 elif ret != -errno.ERANGE:
2090 raise make_ex(ret, 'error getting mirror peer attributes')
2091 keys = [decode_cstr(x) for x in _keys[:_keys_size].split(b'\0')[:-1]]
2092 vals = [decode_cstr(x) for x in _vals[:_vals_size].split(b'\0')[:-1]]
2093 return dict(zip(keys, vals))
2094 finally:
2095 free(_keys)
2096 free(_vals)
2097
2098 def mirror_peer_set_attributes(self, ioctx, uuid, attributes):
2099 """
2100 Set optional mirror peer attributes
2101
2102 :param ioctx: determines which RADOS pool is written
2103 :type ioctx: :class:`rados.Ioctx`
2104 :param uuid: uuid of the mirror peer
2105 :type uuid: str
2106 :param attributes: 'mon_host' and 'key' attributes
2107 :type attributes: dict
2108 """
2109 uuid = cstr(uuid, 'uuid')
2110 keys_str = b'\0'.join([cstr(x[0], 'key') for x in attributes.items()])
2111 vals_str = b'\0'.join([cstr(x[1], 'val') for x in attributes.items()])
2112 cdef:
2113 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2114 char *_uuid = uuid
2115 char *_keys = keys_str
2116 char *_vals = vals_str
2117 size_t _count = len(attributes)
2118
2119 with nogil:
2120 ret = rbd_mirror_peer_site_set_attributes(_ioctx, _uuid, _keys,
2121 _vals, _count)
2122 if ret != 0:
2123 raise make_ex(ret, 'error setting mirror peer attributes')
2124
2125 def mirror_image_status_list(self, ioctx):
2126 """
2127 Iterate over the mirror image statuses of a pool.
2128
2129 :param ioctx: determines which RADOS pool is read
2130 :type ioctx: :class:`rados.Ioctx`
2131 :returns: :class:`MirrorImageStatusIterator`
2132 """
2133 return MirrorImageStatusIterator(ioctx)
2134
2135 def mirror_image_status_summary(self, ioctx):
2136 """
2137 Get mirror image status summary of a pool.
2138
2139 :param ioctx: determines which RADOS pool is read
2140 :type ioctx: :class:`rados.Ioctx`
2141 :returns: list - a list of (state, count) tuples
2142 """
2143 cdef:
2144 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2145 rbd_mirror_image_status_state_t *states = NULL
2146 int *counts = NULL
2147 size_t maxlen = 32
2148 try:
2149 states = <rbd_mirror_image_status_state_t *>realloc_chk(states,
2150 sizeof(rbd_mirror_image_status_state_t) * maxlen)
2151 counts = <int *>realloc_chk(counts, sizeof(int) * maxlen)
2152 with nogil:
2153 ret = rbd_mirror_image_status_summary(_ioctx, states, counts,
2154 &maxlen)
2155 if ret < 0:
2156 raise make_ex(ret, 'error getting mirror image status summary')
2157 return [(states[i], counts[i]) for i in range(maxlen)]
2158 finally:
2159 free(states)
2160 free(counts)
2161
2162 def mirror_image_instance_id_list(self, ioctx):
2163 """
2164 Iterate over the mirror image instance ids of a pool.
2165
2166 :param ioctx: determines which RADOS pool is read
2167 :type ioctx: :class:`rados.Ioctx`
2168 :returns: :class:`MirrorImageInstanceIdIterator`
2169 """
2170 return MirrorImageInstanceIdIterator(ioctx)
2171
2172 def mirror_image_info_list(self, ioctx, mode_filter=None):
2173 """
2174 Iterate over the mirror image instance ids of a pool.
2175
2176 :param ioctx: determines which RADOS pool is read
2177 :param mode_filter: list images in this image mirror mode
2178 :type ioctx: :class:`rados.Ioctx`
2179 :returns: :class:`MirrorImageInfoIterator`
2180 """
2181 return MirrorImageInfoIterator(ioctx, mode_filter)
2182
2183 def pool_metadata_get(self, ioctx, key):
2184 """
2185 Get pool metadata for the given key.
2186
2187 :param ioctx: determines which RADOS pool is read
2188 :type ioctx: :class:`rados.Ioctx`
2189 :param key: metadata key
2190 :type key: str
2191 :returns: str - metadata value
2192 """
2193 key = cstr(key, 'key')
2194 cdef:
2195 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2196 char *_key = key
2197 size_t size = 4096
2198 char *value = NULL
2199 int ret
2200 try:
2201 while True:
2202 value = <char *>realloc_chk(value, size)
2203 with nogil:
2204 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2205 if ret != -errno.ERANGE:
2206 break
2207 if ret == -errno.ENOENT:
2208 raise KeyError('no metadata %s' % (key))
2209 if ret != 0:
2210 raise make_ex(ret, 'error getting metadata %s' % (key))
2211 return decode_cstr(value)
2212 finally:
2213 free(value)
2214
2215 def pool_metadata_set(self, ioctx, key, value):
2216 """
2217 Set pool metadata for the given key.
2218
2219 :param ioctx: determines which RADOS pool is read
2220 :type ioctx: :class:`rados.Ioctx`
2221 :param key: metadata key
2222 :type key: str
2223 :param value: metadata value
2224 :type value: str
2225 """
2226 key = cstr(key, 'key')
2227 value = cstr(value, 'value')
2228 cdef:
2229 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2230 char *_key = key
2231 char *_value = value
2232 with nogil:
2233 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2234
2235 if ret != 0:
2236 raise make_ex(ret, 'error setting metadata %s' % (key))
2237
2238 def pool_metadata_remove(self, ioctx, key):
2239 """
2240 Remove pool metadata for the given key.
2241
2242 :param ioctx: determines which RADOS pool is read
2243 :type ioctx: :class:`rados.Ioctx`
2244 :param key: metadata key
2245 :type key: str
2246 :returns: str - metadata value
2247 """
2248 key = cstr(key, 'key')
2249 cdef:
2250 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2251 char *_key = key
2252 with nogil:
2253 ret = rbd_pool_metadata_remove(_ioctx, _key)
2254
2255 if ret == -errno.ENOENT:
2256 raise KeyError('no metadata %s' % (key))
2257 if ret != 0:
2258 raise make_ex(ret, 'error removing metadata %s' % (key))
2259
2260 def pool_metadata_list(self, ioctx):
2261 """
2262 List pool metadata.
2263
2264 :returns: :class:`PoolMetadataIterator`
2265 """
2266 return PoolMetadataIterator(ioctx)
2267
2268 def config_list(self, ioctx):
2269 """
2270 List pool-level config overrides.
2271
2272 :returns: :class:`ConfigPoolIterator`
2273 """
2274 return ConfigPoolIterator(ioctx)
2275
2276 def config_get(self, ioctx, key):
2277 """
2278 Get a pool-level configuration override.
2279
2280 :param ioctx: determines which RADOS pool is read
2281 :type ioctx: :class:`rados.Ioctx`
2282 :param key: key
2283 :type key: str
2284 :returns: str - value
2285 """
2286 conf_key = 'conf_' + key
2287 conf_key = cstr(conf_key, 'key')
2288 cdef:
2289 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2290 char *_key = conf_key
2291 size_t size = 4096
2292 char *value = NULL
2293 int ret
2294 try:
2295 while True:
2296 value = <char *>realloc_chk(value, size)
2297 with nogil:
2298 ret = rbd_pool_metadata_get(_ioctx, _key, value, &size)
2299 if ret != -errno.ERANGE:
2300 break
2301 if ret == -errno.ENOENT:
2302 raise KeyError('no config %s for pool %s' % (key, ioctx.get_pool_name()))
2303 if ret != 0:
2304 raise make_ex(ret, 'error getting config %s for pool %s' %
2305 (key, ioctx.get_pool_name()))
2306 return decode_cstr(value)
2307 finally:
2308 free(value)
2309
2310 def config_set(self, ioctx, key, value):
2311 """
2312 Get a pool-level configuration override.
2313
2314 :param ioctx: determines which RADOS pool is read
2315 :type ioctx: :class:`rados.Ioctx`
2316 :param key: key
2317 :type key: str
2318 :param value: value
2319 :type value: str
2320 """
2321 conf_key = 'conf_' + key
2322 conf_key = cstr(conf_key, 'key')
2323 value = cstr(value, 'value')
2324 cdef:
2325 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2326 char *_key = conf_key
2327 char *_value = value
2328 with nogil:
2329 ret = rbd_pool_metadata_set(_ioctx, _key, _value)
2330
2331 if ret != 0:
2332 raise make_ex(ret, 'error setting config %s for pool %s' %
2333 (key, ioctx.get_pool_name()))
2334
2335 def config_remove(self, ioctx, key):
2336 """
2337 Remove a pool-level configuration override.
2338
2339 :param ioctx: determines which RADOS pool is read
2340 :type ioctx: :class:`rados.Ioctx`
2341 :param key: key
2342 :type key: str
2343 :returns: str - value
2344 """
2345 conf_key = 'conf_' + key
2346 conf_key = cstr(conf_key, 'key')
2347 cdef:
2348 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2349 char *_key = conf_key
2350 with nogil:
2351 ret = rbd_pool_metadata_remove(_ioctx, _key)
2352
2353 if ret == -errno.ENOENT:
2354 raise KeyError('no config %s for pool %s' %
2355 (key, ioctx.get_pool_name()))
2356 if ret != 0:
2357 raise make_ex(ret, 'error removing config %s for pool %s' %
2358 (key, ioctx.get_pool_name()))
2359
2360 def group_create(self, ioctx, name):
2361 """
2362 Create a group.
2363
2364 :param ioctx: determines which RADOS pool is used
2365 :type ioctx: :class:`rados.Ioctx`
2366 :param name: the name of the group
2367 :type name: str
2368 :raises: :class:`ObjectExists`
2369 :raises: :class:`InvalidArgument`
2370 :raises: :class:`FunctionNotSupported`
2371 """
2372 name = cstr(name, 'name')
2373 cdef:
2374 char *_name = name
2375 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2376 with nogil:
2377 ret = rbd_group_create(_ioctx, _name)
2378 if ret != 0:
2379 raise make_ex(ret, 'error creating group %s' % name, group_errno_to_exception)
2380
2381 def group_remove(self, ioctx, name):
2382 """
2383 Delete an RBD group. This may take a long time, since it does
2384 not return until every image in the group has been removed
2385 from the group.
2386
2387 :param ioctx: determines which RADOS pool the group is in
2388 :type ioctx: :class:`rados.Ioctx`
2389 :param name: the name of the group to remove
2390 :type name: str
2391 :raises: :class:`ObjectNotFound`
2392 :raises: :class:`InvalidArgument`
2393 :raises: :class:`FunctionNotSupported`
2394 """
2395 name = cstr(name, 'name')
2396 cdef:
2397 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2398 char *_name = name
2399 with nogil:
2400 ret = rbd_group_remove(_ioctx, _name)
2401 if ret != 0:
2402 raise make_ex(ret, 'error removing group', group_errno_to_exception)
2403
2404 def group_list(self, ioctx):
2405 """
2406 List groups.
2407
2408 :param ioctx: determines which RADOS pool is read
2409 :type ioctx: :class:`rados.Ioctx`
2410 :returns: list -- a list of groups names
2411 :raises: :class:`FunctionNotSupported`
2412 """
2413 cdef:
2414 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2415 size_t size = 512
2416 char *c_names = NULL
2417 try:
2418 while True:
2419 c_names = <char *>realloc_chk(c_names, size)
2420 with nogil:
2421 ret = rbd_group_list(_ioctx, c_names, &size)
2422 if ret >= 0:
2423 break
2424 elif ret != -errno.ERANGE:
2425 raise make_ex(ret, 'error listing groups', group_errno_to_exception)
2426 return [decode_cstr(name) for name in c_names[:ret].split(b'\0')
2427 if name]
2428 finally:
2429 free(c_names)
2430
2431 def group_rename(self, ioctx, src, dest):
2432 """
2433 Rename an RBD group.
2434
2435 :param ioctx: determines which RADOS pool the group is in
2436 :type ioctx: :class:`rados.Ioctx`
2437 :param src: the current name of the group
2438 :type src: str
2439 :param dest: the new name of the group
2440 :type dest: str
2441 :raises: :class:`ObjectExists`
2442 :raises: :class:`ObjectNotFound`
2443 :raises: :class:`InvalidArgument`
2444 :raises: :class:`FunctionNotSupported`
2445 """
2446 src = cstr(src, 'src')
2447 dest = cstr(dest, 'dest')
2448 cdef:
2449 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2450 char *_src = src
2451 char *_dest = dest
2452 with nogil:
2453 ret = rbd_group_rename(_ioctx, _src, _dest)
2454 if ret != 0:
2455 raise make_ex(ret, 'error renaming group')
2456
2457 def namespace_create(self, ioctx, name):
2458 """
2459 Create an RBD namespace within a pool
2460
2461 :param ioctx: determines which RADOS pool
2462 :type ioctx: :class:`rados.Ioctx`
2463 :param name: namespace name
2464 :type name: str
2465 """
2466 name = cstr(name, 'name')
2467 cdef:
2468 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2469 const char *_name = name
2470 with nogil:
2471 ret = rbd_namespace_create(_ioctx, _name)
2472 if ret != 0:
2473 raise make_ex(ret, 'error creating namespace')
2474
2475 def namespace_remove(self, ioctx, name):
2476 """
2477 Remove an RBD namespace from a pool
2478
2479 :param ioctx: determines which RADOS pool
2480 :type ioctx: :class:`rados.Ioctx`
2481 :param name: namespace name
2482 :type name: str
2483 """
2484 name = cstr(name, 'name')
2485 cdef:
2486 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2487 const char *_name = name
2488 with nogil:
2489 ret = rbd_namespace_remove(_ioctx, _name)
2490 if ret != 0:
2491 raise make_ex(ret, 'error removing namespace')
2492
2493 def namespace_exists(self, ioctx, name):
2494 """
2495 Verifies if a namespace exists within a pool
2496
2497 :param ioctx: determines which RADOS pool
2498 :type ioctx: :class:`rados.Ioctx`
2499 :param name: namespace name
2500 :type name: str
2501 :returns: bool - true if namespace exists
2502 """
2503 name = cstr(name, 'name')
2504 cdef:
2505 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2506 const char *_name = name
2507 bint _exists = False
2508 with nogil:
2509 ret = rbd_namespace_exists(_ioctx, _name, &_exists)
2510 if ret != 0:
2511 raise make_ex(ret, 'error verifying namespace')
2512 return bool(_exists != 0)
2513
2514 def namespace_list(self, ioctx):
2515 """
2516 List all namespaces within a pool
2517
2518 :param ioctx: determines which RADOS pool
2519 :type ioctx: :class:`rados.Ioctx`
2520 :returns: list - collection of namespace names
2521 """
2522 cdef:
2523 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2524 char *_names = NULL
2525 size_t _size = 512
2526 try:
2527 while True:
2528 _names = <char *>realloc_chk(_names, _size)
2529 with nogil:
2530 ret = rbd_namespace_list(_ioctx, _names, &_size)
2531 if ret >= 0:
2532 break
2533 elif ret != -errno.ERANGE:
2534 raise make_ex(ret, 'error listing namespaces')
2535 return [decode_cstr(name) for name in _names[:_size].split(b'\0')
2536 if name]
2537 finally:
2538 free(_names)
2539
2540 def pool_init(self, ioctx, force):
2541 """
2542 Initialize an RBD pool
2543 :param ioctx: determines which RADOS pool
2544 :type ioctx: :class:`rados.Ioctx`
2545 :param force: force init
2546 :type force: bool
2547 """
2548 cdef:
2549 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2550 bint _force = force
2551 with nogil:
2552 ret = rbd_pool_init(_ioctx, _force)
2553 if ret != 0:
2554 raise make_ex(ret, 'error initializing pool')
2555
2556 def pool_stats_get(self, ioctx):
2557 """
2558 Return RBD pool stats
2559
2560 :param ioctx: determines which RADOS pool
2561 :type ioctx: :class:`rados.Ioctx`
2562 :returns: dict - contains the following keys:
2563
2564 * ``image_count`` (int) - image count
2565
2566 * ``image_provisioned_bytes`` (int) - image total HEAD provisioned bytes
2567
2568 * ``image_max_provisioned_bytes`` (int) - image total max provisioned bytes
2569
2570 * ``image_snap_count`` (int) - image snap count
2571
2572 * ``trash_count`` (int) - trash image count
2573
2574 * ``trash_provisioned_bytes`` (int) - trash total HEAD provisioned bytes
2575
2576 * ``trash_max_provisioned_bytes`` (int) - trash total max provisioned bytes
2577
2578 * ``trash_snap_count`` (int) - trash snap count
2579
2580 """
2581 cdef:
2582 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2583 uint64_t _image_count = 0
2584 uint64_t _image_provisioned_bytes = 0
2585 uint64_t _image_max_provisioned_bytes = 0
2586 uint64_t _image_snap_count = 0
2587 uint64_t _trash_count = 0
2588 uint64_t _trash_provisioned_bytes = 0
2589 uint64_t _trash_max_provisioned_bytes = 0
2590 uint64_t _trash_snap_count = 0
2591 rbd_pool_stats_t _stats
2592
2593 rbd_pool_stats_create(&_stats)
2594 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGES,
2595 &_image_count)
2596 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
2597 &_image_provisioned_bytes)
2598 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
2599 &_image_max_provisioned_bytes)
2600 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS,
2601 &_image_snap_count)
2602 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_IMAGES,
2603 &_trash_count)
2604 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
2605 &_trash_provisioned_bytes)
2606 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
2607 &_trash_max_provisioned_bytes)
2608 rbd_pool_stats_option_add_uint64(_stats, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS,
2609 &_trash_snap_count)
2610 try:
2611 with nogil:
2612 ret = rbd_pool_stats_get(_ioctx, _stats)
2613 if ret != 0:
2614 raise make_ex(ret, 'error retrieving pool stats')
2615 else:
2616 return {'image_count': _image_count,
2617 'image_provisioned_bytes': _image_provisioned_bytes,
2618 'image_max_provisioned_bytes': _image_max_provisioned_bytes,
2619 'image_snap_count': _image_snap_count,
2620 'trash_count': _trash_count,
2621 'trash_provisioned_bytes': _trash_provisioned_bytes,
2622 'trash_max_provisioned_bytes': _trash_max_provisioned_bytes,
2623 'trash_snap_count': _trash_snap_count}
2624 finally:
2625 rbd_pool_stats_destroy(_stats)
2626
2627 def features_to_string(self, features):
2628 """
2629 Convert features bitmask to str.
2630
2631 :param features: feature bitmask
2632 :type features: int
2633 :returns: str - the features str of the image
2634 :raises: :class:`InvalidArgument`
2635 """
2636 cdef:
2637 int ret = -errno.ERANGE
2638 uint64_t _features = features
2639 size_t size = 1024
2640 char *str_features = NULL
2641 try:
2642 while ret == -errno.ERANGE:
2643 str_features = <char *>realloc_chk(str_features, size)
2644 with nogil:
2645 ret = rbd_features_to_string(_features, str_features, &size)
2646
2647 if ret != 0:
2648 raise make_ex(ret, 'error converting features bitmask to str')
2649 return decode_cstr(str_features)
2650 finally:
2651 free(str_features)
2652
2653 def features_from_string(self, str_features):
2654 """
2655 Get features bitmask from str, if str_features is empty, it will return
2656 RBD_FEATURES_DEFAULT.
2657
2658 :param str_features: feature str
2659 :type str_features: str
2660 :returns: int - the features bitmask of the image
2661 :raises: :class:`InvalidArgument`
2662 """
2663 str_features = cstr(str_features, 'str_features')
2664 cdef:
2665 const char *_str_features = str_features
2666 uint64_t features
2667 with nogil:
2668 ret = rbd_features_from_string(_str_features, &features)
2669 if ret != 0:
2670 raise make_ex(ret, 'error getting features bitmask from str')
2671 return features
2672
2673
2674 cdef class MirrorPeerIterator(object):
2675 """
2676 Iterator over mirror peer info for a pool.
2677
2678 Yields a dictionary containing information about a peer.
2679
2680 Keys are:
2681
2682 * ``uuid`` (str) - uuid of the peer
2683
2684 * ``direction`` (int) - direction enum
2685
2686 * ``site_name`` (str) - cluster name of the peer
2687
2688 * ``mirror_uuid`` (str) - mirror uuid of the peer
2689
2690 * ``client_name`` (str) - client name of the peer
2691 """
2692
2693 cdef:
2694 rbd_mirror_peer_site_t *peers
2695 int num_peers
2696
2697 def __init__(self, ioctx):
2698 cdef:
2699 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
2700 self.peers = NULL
2701 self.num_peers = 10
2702 while True:
2703 self.peers = <rbd_mirror_peer_site_t *>realloc_chk(
2704 self.peers, self.num_peers * sizeof(rbd_mirror_peer_site_t))
2705 with nogil:
2706 ret = rbd_mirror_peer_site_list(_ioctx, self.peers,
2707 &self.num_peers)
2708 if ret < 0:
2709 if ret == -errno.ERANGE:
2710 continue
2711 self.num_peers = 0
2712 raise make_ex(ret, 'error listing peers')
2713 break
2714
2715 def __iter__(self):
2716 for i in range(self.num_peers):
2717 yield {
2718 'uuid' : decode_cstr(self.peers[i].uuid),
2719 'direction' : int(self.peers[i].direction),
2720 'site_name' : decode_cstr(self.peers[i].site_name),
2721 'cluster_name' : decode_cstr(self.peers[i].site_name),
2722 'mirror_uuid' : decode_cstr(self.peers[i].mirror_uuid),
2723 'client_name' : decode_cstr(self.peers[i].client_name),
2724 }
2725
2726 def __dealloc__(self):
2727 if self.peers:
2728 rbd_mirror_peer_site_list_cleanup(self.peers, self.num_peers)
2729 free(self.peers)
2730
2731 cdef class MirrorImageStatusIterator(object):
2732 """
2733 Iterator over mirror image status for a pool.
2734
2735 Yields a dictionary containing mirror status of an image.
2736
2737 Keys are:
2738
2739 * ``name`` (str) - mirror image name
2740
2741 * ``id`` (str) - mirror image id
2742
2743 * ``info`` (dict) - mirror image info
2744
2745 * ``state`` (int) - status mirror state
2746
2747 * ``description`` (str) - status description
2748
2749 * ``last_update`` (datetime) - last status update time
2750
2751 * ``up`` (bool) - is mirroring agent up
2752
2753 * ``remote_statuses`` (array) -
2754
2755 * ``mirror uuid`` (str) - remote mirror uuid
2756
2757 * ``state`` (int) - status mirror state
2758
2759 * ``description`` (str) - status description
2760
2761 * ``last_update`` (datetime) - last status update time
2762
2763 * ``up`` (bool) - is mirroring agent up
2764 """
2765
2766 cdef:
2767 rados_ioctx_t ioctx
2768 size_t max_read
2769 char *last_read
2770 char **image_ids
2771 rbd_mirror_image_site_status_t *s_status
2772 rbd_mirror_image_global_status_t *images
2773 size_t size
2774
2775 def __init__(self, ioctx):
2776 self.ioctx = convert_ioctx(ioctx)
2777 self.max_read = 1024
2778 self.last_read = strdup("")
2779 self.image_ids = <char **>realloc_chk(NULL,
2780 sizeof(char *) * self.max_read)
2781 self.images = <rbd_mirror_image_global_status_t *>realloc_chk(NULL,
2782 sizeof(rbd_mirror_image_global_status_t) * self.max_read)
2783 self.size = 0
2784 self.get_next_chunk()
2785
2786
2787 def __iter__(self):
2788 while self.size > 0:
2789 for i in range(self.size):
2790 local_status = None
2791 site_statuses = []
2792
2793 for x in range(self.images[i].site_statuses_count):
2794 s_status = &self.images[i].site_statuses[x]
2795 site_status = {
2796 'state' : s_status.state,
2797 'description' : decode_cstr(s_status.description),
2798 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
2799 'up' : s_status.up,
2800 }
2801 mirror_uuid = decode_cstr(s_status.mirror_uuid)
2802 if mirror_uuid == '':
2803 local_status = site_status
2804 else:
2805 site_status['mirror_uuid'] = mirror_uuid
2806 site_statuses += site_status
2807
2808 status = {
2809 'name' : decode_cstr(self.images[i].name),
2810 'id' : decode_cstr(self.image_ids[i]),
2811 'info' : {
2812 'global_id' : decode_cstr(self.images[i].info.global_id),
2813 'state' : self.images[i].info.state,
2814 },
2815 'remote_statuses': site_statuses,
2816 }
2817 if local_status:
2818 status.update(local_status)
2819 yield status
2820 if self.size < self.max_read:
2821 break
2822 self.get_next_chunk()
2823
2824 def __dealloc__(self):
2825 rbd_mirror_image_global_status_list_cleanup(self.image_ids, self.images,
2826 self.size)
2827 if self.last_read:
2828 free(self.last_read)
2829 if self.image_ids:
2830 free(self.image_ids)
2831 if self.images:
2832 free(self.images)
2833
2834 def get_next_chunk(self):
2835 if self.size > 0:
2836 rbd_mirror_image_global_status_list_cleanup(self.image_ids,
2837 self.images,
2838 self.size)
2839 self.size = 0
2840 with nogil:
2841 ret = rbd_mirror_image_global_status_list(self.ioctx,
2842 self.last_read,
2843 self.max_read,
2844 self.image_ids,
2845 self.images, &self.size)
2846 if ret < 0:
2847 raise make_ex(ret, 'error listing mirror images status')
2848 if self.size > 0:
2849 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2850 free(self.last_read)
2851 self.last_read = strdup(last_read)
2852 else:
2853 free(self.last_read)
2854 self.last_read = strdup("")
2855
2856 cdef class MirrorImageInstanceIdIterator(object):
2857 """
2858 Iterator over mirror image instance id for a pool.
2859
2860 Yields ``(image_id, instance_id)`` tuple.
2861 """
2862
2863 cdef:
2864 rados_ioctx_t ioctx
2865 size_t max_read
2866 char *last_read
2867 char **image_ids
2868 char **instance_ids
2869 size_t size
2870
2871 def __init__(self, ioctx):
2872 self.ioctx = convert_ioctx(ioctx)
2873 self.max_read = 1024
2874 self.last_read = strdup("")
2875 self.image_ids = <char **>realloc_chk(NULL,
2876 sizeof(char *) * self.max_read)
2877 self.instance_ids = <char **>realloc_chk(NULL,
2878 sizeof(char *) * self.max_read)
2879 self.size = 0
2880 self.get_next_chunk()
2881
2882 def __iter__(self):
2883 while self.size > 0:
2884 for i in range(self.size):
2885 yield (decode_cstr(self.image_ids[i]),
2886 decode_cstr(self.instance_ids[i]))
2887 if self.size < self.max_read:
2888 break
2889 self.get_next_chunk()
2890
2891 def __dealloc__(self):
2892 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2893 self.instance_ids, self.size)
2894 if self.last_read:
2895 free(self.last_read)
2896 if self.image_ids:
2897 free(self.image_ids)
2898 if self.instance_ids:
2899 free(self.instance_ids)
2900
2901 def get_next_chunk(self):
2902 if self.size > 0:
2903 rbd_mirror_image_instance_id_list_cleanup(self.image_ids,
2904 self.instance_ids,
2905 self.size)
2906 self.size = 0
2907 with nogil:
2908 ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read,
2909 self.max_read,
2910 self.image_ids,
2911 self.instance_ids,
2912 &self.size)
2913 if ret < 0:
2914 raise make_ex(ret, 'error listing mirror images instance ids')
2915 if self.size > 0:
2916 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2917 free(self.last_read)
2918 self.last_read = strdup(last_read)
2919 else:
2920 free(self.last_read)
2921 self.last_read = strdup("")
2922
2923 cdef class MirrorImageInfoIterator(object):
2924 """
2925 Iterator over mirror image info for a pool.
2926
2927 Yields ``(image_id, info)`` tuple.
2928 """
2929
2930 cdef:
2931 rados_ioctx_t ioctx
2932 rbd_mirror_image_mode_t mode_filter
2933 rbd_mirror_image_mode_t *mode_filter_ptr
2934 size_t max_read
2935 char *last_read
2936 char **image_ids
2937 rbd_mirror_image_info_t *info_entries
2938 rbd_mirror_image_mode_t *mode_entries
2939 size_t size
2940
2941 def __init__(self, ioctx, mode_filter):
2942 self.ioctx = convert_ioctx(ioctx)
2943 if mode_filter is not None:
2944 self.mode_filter = mode_filter
2945 self.mode_filter_ptr = &self.mode_filter
2946 else:
2947 self.mode_filter_ptr = NULL
2948 self.max_read = 1024
2949 self.last_read = strdup("")
2950 self.image_ids = <char **>realloc_chk(NULL,
2951 sizeof(char *) * self.max_read)
2952 self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
2953 sizeof(rbd_mirror_image_info_t) * self.max_read)
2954 self.mode_entries = <rbd_mirror_image_mode_t *>realloc_chk(NULL,
2955 sizeof(rbd_mirror_image_mode_t) * self.max_read)
2956 self.size = 0
2957 self.get_next_chunk()
2958
2959 def __iter__(self):
2960 while self.size > 0:
2961 for i in range(self.size):
2962 yield (decode_cstr(self.image_ids[i]),
2963 {
2964 'mode' : int(self.mode_entries[i]),
2965 'global_id' : decode_cstr(self.info_entries[i].global_id),
2966 'state' : int(self.info_entries[i].state),
2967 'primary' : self.info_entries[i].primary,
2968 })
2969 if self.size < self.max_read:
2970 break
2971 self.get_next_chunk()
2972
2973 def __dealloc__(self):
2974 rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries,
2975 self.size)
2976 if self.last_read:
2977 free(self.last_read)
2978 if self.image_ids:
2979 free(self.image_ids)
2980 if self.info_entries:
2981 free(self.info_entries)
2982 if self.mode_entries:
2983 free(self.mode_entries)
2984
2985 def get_next_chunk(self):
2986 if self.size > 0:
2987 rbd_mirror_image_info_list_cleanup(self.image_ids,
2988 self.info_entries, self.size)
2989 self.size = 0
2990 with nogil:
2991 ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr,
2992 self.last_read, self.max_read,
2993 self.image_ids, self.mode_entries,
2994 self.info_entries, &self.size)
2995 if ret < 0:
2996 raise make_ex(ret, 'error listing mirror image info')
2997 if self.size > 0:
2998 last_read = cstr(self.image_ids[self.size - 1], 'last_read')
2999 free(self.last_read)
3000 self.last_read = strdup(last_read)
3001 else:
3002 free(self.last_read)
3003 self.last_read = strdup("")
3004
3005 cdef class PoolMetadataIterator(object):
3006 """
3007 Iterator over pool metadata list.
3008
3009 Yields ``(key, value)`` tuple.
3010
3011 * ``key`` (str) - metadata key
3012 * ``value`` (str) - metadata value
3013 """
3014
3015 cdef:
3016 rados_ioctx_t ioctx
3017 char *last_read
3018 uint64_t max_read
3019 object next_chunk
3020
3021 def __init__(self, ioctx):
3022 self.ioctx = convert_ioctx(ioctx)
3023 self.last_read = strdup("")
3024 self.max_read = 32
3025 self.get_next_chunk()
3026
3027 def __iter__(self):
3028 while len(self.next_chunk) > 0:
3029 for pair in self.next_chunk:
3030 yield pair
3031 if len(self.next_chunk) < self.max_read:
3032 break
3033 self.get_next_chunk()
3034
3035 def __dealloc__(self):
3036 if self.last_read:
3037 free(self.last_read)
3038
3039 def get_next_chunk(self):
3040 cdef:
3041 char *c_keys = NULL
3042 size_t keys_size = 4096
3043 char *c_vals = NULL
3044 size_t vals_size = 4096
3045 try:
3046 while True:
3047 c_keys = <char *>realloc_chk(c_keys, keys_size)
3048 c_vals = <char *>realloc_chk(c_vals, vals_size)
3049 with nogil:
3050 ret = rbd_pool_metadata_list(self.ioctx, self.last_read,
3051 self.max_read, c_keys,
3052 &keys_size, c_vals, &vals_size)
3053 if ret >= 0:
3054 break
3055 elif ret != -errno.ERANGE:
3056 raise make_ex(ret, 'error listing metadata')
3057 keys = [decode_cstr(key) for key in
3058 c_keys[:keys_size].split(b'\0') if key]
3059 vals = [decode_cstr(val) for val in
3060 c_vals[:vals_size].split(b'\0') if val]
3061 if len(keys) > 0:
3062 last_read = cstr(keys[-1], 'last_read')
3063 free(self.last_read)
3064 self.last_read = strdup(last_read)
3065 self.next_chunk = list(zip(keys, vals))
3066 finally:
3067 free(c_keys)
3068 free(c_vals)
3069
3070 cdef class ConfigPoolIterator(object):
3071 """
3072 Iterator over pool-level overrides for a pool.
3073
3074 Yields a dictionary containing information about an override.
3075
3076 Keys are:
3077
3078 * ``name`` (str) - override name
3079
3080 * ``value`` (str) - override value
3081
3082 * ``source`` (str) - override source
3083 """
3084
3085 cdef:
3086 rbd_config_option_t *options
3087 int num_options
3088
3089 def __init__(self, ioctx):
3090 cdef:
3091 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3092 self.options = NULL
3093 self.num_options = 32
3094 while True:
3095 self.options = <rbd_config_option_t *>realloc_chk(
3096 self.options, self.num_options * sizeof(rbd_config_option_t))
3097 with nogil:
3098 ret = rbd_config_pool_list(_ioctx, self.options, &self.num_options)
3099 if ret < 0:
3100 if ret == -errno.ERANGE:
3101 continue
3102 self.num_options = 0
3103 raise make_ex(ret, 'error listing config options')
3104 break
3105
3106 def __iter__(self):
3107 for i in range(self.num_options):
3108 yield {
3109 'name' : decode_cstr(self.options[i].name),
3110 'value' : decode_cstr(self.options[i].value),
3111 'source' : self.options[i].source,
3112 }
3113
3114 def __dealloc__(self):
3115 if self.options:
3116 rbd_config_pool_list_cleanup(self.options, self.num_options)
3117 free(self.options)
3118
3119 cdef int diff_iterate_cb(uint64_t offset, size_t length, int write, void *cb) \
3120 except? -9000 with gil:
3121 # Make sure that if we wound up with an exception from a previous callback,
3122 # we stop calling back (just in case librbd ever fails to bail out on the
3123 # first negative return, as older versions did)
3124 if exc.PyErr_Occurred():
3125 return -9000
3126 ret = (<object>cb)(offset, length, bool(write))
3127 if ret is None:
3128 return 0
3129 return ret
3130
3131 cdef class Group(object):
3132 """
3133 This class represents an RBD group. It is used to interact with
3134 snapshots and images members.
3135 """
3136
3137 cdef object name
3138 cdef char *_name
3139 cdef object ioctx
3140
3141 cdef rados_ioctx_t _ioctx
3142
3143 def __init__(self, ioctx, name):
3144 name = cstr(name, 'name')
3145 self.name = name
3146
3147 self._ioctx = convert_ioctx(ioctx)
3148 self._name = name
3149
3150 def __enter__(self):
3151 return self
3152
3153 def __exit__(self, type_, value, traceback):
3154 return False
3155
3156 def add_image(self, image_ioctx, image_name):
3157 """
3158 Add an image to a group.
3159
3160 :param image_ioctx: determines which RADOS pool the image belongs to.
3161 :type ioctx: :class:`rados.Ioctx`
3162 :param name: the name of the image to add
3163 :type name: str
3164
3165 :raises: :class:`ObjectNotFound`
3166 :raises: :class:`ObjectExists`
3167 :raises: :class:`InvalidArgument`
3168 :raises: :class:`FunctionNotSupported`
3169 """
3170 image_name = cstr(image_name, 'image_name')
3171 cdef:
3172 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3173 char *_image_name = image_name
3174 with nogil:
3175 ret = rbd_group_image_add(self._ioctx, self._name, _image_ioctx, _image_name)
3176 if ret != 0:
3177 raise make_ex(ret, 'error adding image to group', group_errno_to_exception)
3178
3179 def remove_image(self, image_ioctx, image_name):
3180 """
3181 Remove an image from a group.
3182
3183 :param image_ioctx: determines which RADOS pool the image belongs to.
3184 :type ioctx: :class:`rados.Ioctx`
3185 :param name: the name of the image to remove
3186 :type name: str
3187
3188 :raises: :class:`ObjectNotFound`
3189 :raises: :class:`InvalidArgument`
3190 :raises: :class:`FunctionNotSupported`
3191 """
3192 image_name = cstr(image_name, 'image_name')
3193 cdef:
3194 rados_ioctx_t _image_ioctx = convert_ioctx(image_ioctx)
3195 char *_image_name = image_name
3196 with nogil:
3197 ret = rbd_group_image_remove(self._ioctx, self._name, _image_ioctx, _image_name)
3198 if ret != 0:
3199 raise make_ex(ret, 'error removing image from group', group_errno_to_exception)
3200
3201
3202 def list_images(self):
3203 """
3204 Iterate over the images of a group.
3205
3206 :returns: :class:`GroupImageIterator`
3207 """
3208 return GroupImageIterator(self)
3209
3210 def create_snap(self, snap_name):
3211 """
3212 Create a snapshot for the group.
3213
3214 :param snap_name: the name of the snapshot to create
3215 :type name: str
3216
3217 :raises: :class:`ObjectNotFound`
3218 :raises: :class:`ObjectExists`
3219 :raises: :class:`InvalidArgument`
3220 :raises: :class:`FunctionNotSupported`
3221 """
3222 snap_name = cstr(snap_name, 'snap_name')
3223 cdef:
3224 char *_snap_name = snap_name
3225 with nogil:
3226 ret = rbd_group_snap_create(self._ioctx, self._name, _snap_name)
3227 if ret != 0:
3228 raise make_ex(ret, 'error creating group snapshot', group_errno_to_exception)
3229
3230 def remove_snap(self, snap_name):
3231 """
3232 Remove a snapshot from the group.
3233
3234 :param snap_name: the name of the snapshot to remove
3235 :type name: str
3236
3237 :raises: :class:`ObjectNotFound`
3238 :raises: :class:`InvalidArgument`
3239 :raises: :class:`FunctionNotSupported`
3240 """
3241 snap_name = cstr(snap_name, 'snap_name')
3242 cdef:
3243 char *_snap_name = snap_name
3244 with nogil:
3245 ret = rbd_group_snap_remove(self._ioctx, self._name, _snap_name)
3246 if ret != 0:
3247 raise make_ex(ret, 'error removing group snapshot', group_errno_to_exception)
3248
3249 def rename_snap(self, old_snap_name, new_snap_name):
3250 """
3251 Rename group's snapshot.
3252
3253 :raises: :class:`ObjectNotFound`
3254 :raises: :class:`ObjectExists`
3255 :raises: :class:`InvalidArgument`
3256 :raises: :class:`FunctionNotSupported`
3257 """
3258
3259 old_snap_name = cstr(old_snap_name, 'old_snap_name')
3260 new_snap_name = cstr(new_snap_name, 'new_snap_name')
3261 cdef:
3262 char *_old_snap_name = old_snap_name
3263 char *_new_snap_name = new_snap_name
3264 with nogil:
3265 ret = rbd_group_snap_rename(self._ioctx, self._name, _old_snap_name,
3266 _new_snap_name)
3267 if ret != 0:
3268 raise make_ex(ret, 'error renaming group snapshot',
3269 group_errno_to_exception)
3270
3271 def list_snaps(self):
3272 """
3273 Iterate over the images of a group.
3274
3275 :returns: :class:`GroupSnapIterator`
3276 """
3277 return GroupSnapIterator(self)
3278
3279 def rollback_to_snap(self, name):
3280 """
3281 Rollback group to snapshot.
3282
3283 :param name: the group snapshot to rollback to
3284 :type name: str
3285 :raises: :class:`ObjectNotFound`
3286 :raises: :class:`IOError`
3287 """
3288 name = cstr(name, 'name')
3289 cdef char *_name = name
3290 with nogil:
3291 ret = rbd_group_snap_rollback(self._ioctx, self._name, _name)
3292 if ret != 0:
3293 raise make_ex(ret, 'error rolling back group to snapshot', group_errno_to_exception)
3294
3295 cdef class Image(object):
3296 """
3297 This class represents an RBD image. It is used to perform I/O on
3298 the image and interact with snapshots.
3299
3300 **Note**: Any method of this class may raise :class:`ImageNotFound`
3301 if the image has been deleted.
3302 """
3303 cdef rbd_image_t image
3304 cdef bint closed
3305 cdef object name
3306 cdef object ioctx
3307 cdef rados_ioctx_t _ioctx
3308
3309 def __init__(self, ioctx, name=None, snapshot=None,
3310 read_only=False, image_id=None):
3311 """
3312 Open the image at the given snapshot.
3313 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
3314
3315 If a snapshot is specified, the image will be read-only, unless
3316 :func:`Image.set_snap` is called later.
3317
3318 If read-only mode is used, metadata for the :class:`Image`
3319 object (such as which snapshots exist) may become obsolete. See
3320 the C api for more details.
3321
3322 To clean up from opening the image, :func:`Image.close` should
3323 be called. For ease of use, this is done automatically when
3324 an :class:`Image` is used as a context manager (see :pep:`343`).
3325
3326 :param ioctx: determines which RADOS pool the image is in
3327 :type ioctx: :class:`rados.Ioctx`
3328 :param name: the name of the image
3329 :type name: str
3330 :param snapshot: which snapshot to read from
3331 :type snaphshot: str
3332 :param read_only: whether to open the image in read-only mode
3333 :type read_only: bool
3334 :param image_id: the id of the image
3335 :type image_id: str
3336 """
3337 name = cstr(name, 'name', opt=True)
3338 image_id = cstr(image_id, 'image_id', opt=True)
3339 snapshot = cstr(snapshot, 'snapshot', opt=True)
3340 self.closed = True
3341 if name is not None and image_id is not None:
3342 raise InvalidArgument("only need to specify image name or image id")
3343 elif name is None and image_id is None:
3344 raise InvalidArgument("image name or image id was not specified")
3345 elif name is not None:
3346 self.name = name
3347 else:
3348 self.name = image_id
3349 # Keep around a reference to the ioctx, so it won't get deleted
3350 self.ioctx = ioctx
3351 cdef:
3352 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3353 char *_name = opt_str(name)
3354 char *_image_id = opt_str(image_id)
3355 char *_snapshot = opt_str(snapshot)
3356 if read_only:
3357 with nogil:
3358 if name is not None:
3359 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
3360 else:
3361 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
3362 else:
3363 with nogil:
3364 if name is not None:
3365 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
3366 else:
3367 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
3368 if ret != 0:
3369 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
3370 self.closed = False
3371 if name is None:
3372 self.name = self.get_name()
3373
3374 def __enter__(self):
3375 return self
3376
3377 def __exit__(self, type_, value, traceback):
3378 """
3379 Closes the image. See :func:`close`
3380 """
3381 self.close()
3382 return False
3383
3384 def __get_completion(self, oncomplete):
3385 """
3386 Constructs a completion to use with asynchronous operations
3387
3388 :param oncomplete: callback for the completion
3389
3390 :raises: :class:`Error`
3391 :returns: completion object
3392 """
3393
3394 completion_obj = Completion(self, oncomplete)
3395
3396 cdef:
3397 rbd_completion_t completion
3398 PyObject* p_completion_obj= <PyObject*>completion_obj
3399
3400 with nogil:
3401 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
3402 &completion)
3403 if ret < 0:
3404 raise make_ex(ret, "error getting a completion")
3405
3406 completion_obj.rbd_comp = completion
3407 return completion_obj
3408
3409 def close(self):
3410 """
3411 Release the resources used by this image object.
3412
3413 After this is called, this object should not be used.
3414 """
3415 if not self.closed:
3416 self.closed = True
3417 with nogil:
3418 ret = rbd_close(self.image)
3419 if ret < 0:
3420 raise make_ex(ret, 'error while closing image %s' % (
3421 self.name,))
3422
3423 def __dealloc__(self):
3424 self.close()
3425
3426 def __repr__(self):
3427 return "rbd.Image(ioctx, %r)" % self.name
3428
3429 def resize(self, size, allow_shrink=True):
3430 """
3431 Change the size of the image, allow shrink.
3432
3433 :param size: the new size of the image
3434 :type size: int
3435 :param allow_shrink: permit shrinking
3436 :type allow_shrink: bool
3437 """
3438 old_size = self.size()
3439 if old_size == size:
3440 return
3441 if not allow_shrink and old_size > size:
3442 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
3443 cdef:
3444 uint64_t _size = size
3445 bint _allow_shrink = allow_shrink
3446 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3447 with nogil:
3448 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
3449 if ret < 0:
3450 raise make_ex(ret, 'error resizing image %s' % self.name)
3451
3452 def stat(self):
3453 """
3454 Get information about the image. Currently parent pool and
3455 parent name are always -1 and ''.
3456
3457 :returns: dict - contains the following keys:
3458
3459 * ``size`` (int) - the size of the image in bytes
3460
3461 * ``obj_size`` (int) - the size of each object that comprises the
3462 image
3463
3464 * ``num_objs`` (int) - the number of objects in the image
3465
3466 * ``order`` (int) - log_2(object_size)
3467
3468 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
3469 to store the image
3470
3471 * ``parent_pool`` (int) - deprecated
3472
3473 * ``parent_name`` (str) - deprecated
3474
3475 See also :meth:`format` and :meth:`features`.
3476
3477 """
3478 cdef rbd_image_info_t info
3479 with nogil:
3480 ret = rbd_stat(self.image, &info, sizeof(info))
3481 if ret != 0:
3482 raise make_ex(ret, 'error getting info for image %s' % self.name)
3483 return {
3484 'size' : info.size,
3485 'obj_size' : info.obj_size,
3486 'num_objs' : info.num_objs,
3487 'order' : info.order,
3488 'block_name_prefix' : decode_cstr(info.block_name_prefix),
3489 'parent_pool' : info.parent_pool,
3490 'parent_name' : info.parent_name
3491 }
3492
3493 def get_name(self):
3494 """
3495 Get the RBD image name
3496
3497 :returns: str - image name
3498 """
3499 cdef:
3500 int ret = -errno.ERANGE
3501 size_t size = 64
3502 char *image_name = NULL
3503 try:
3504 while ret == -errno.ERANGE:
3505 image_name = <char *>realloc_chk(image_name, size)
3506 with nogil:
3507 ret = rbd_get_name(self.image, image_name, &size)
3508
3509 if ret != 0:
3510 raise make_ex(ret, 'error getting name for image %s' % self.name)
3511 return decode_cstr(image_name)
3512 finally:
3513 free(image_name)
3514
3515 def id(self):
3516 """
3517 Get the RBD v2 internal image id
3518
3519 :returns: str - image id
3520 """
3521 cdef:
3522 int ret = -errno.ERANGE
3523 size_t size = 32
3524 char *image_id = NULL
3525 try:
3526 while ret == -errno.ERANGE and size <= 4096:
3527 image_id = <char *>realloc_chk(image_id, size)
3528 with nogil:
3529 ret = rbd_get_id(self.image, image_id, size)
3530 if ret == -errno.ERANGE:
3531 size *= 2
3532
3533 if ret != 0:
3534 raise make_ex(ret, 'error getting id for image %s' % self.name)
3535 return decode_cstr(image_id)
3536 finally:
3537 free(image_id)
3538
3539 def block_name_prefix(self):
3540 """
3541 Get the RBD block name prefix
3542
3543 :returns: str - block name prefix
3544 """
3545 cdef:
3546 int ret = -errno.ERANGE
3547 size_t size = 32
3548 char *prefix = NULL
3549 try:
3550 while ret == -errno.ERANGE and size <= 4096:
3551 prefix = <char *>realloc_chk(prefix, size)
3552 with nogil:
3553 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3554 if ret == -errno.ERANGE:
3555 size *= 2
3556
3557 if ret != 0:
3558 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3559 return decode_cstr(prefix)
3560 finally:
3561 free(prefix)
3562
3563 def data_pool_id(self):
3564 """
3565 Get the pool id of the pool where the data of this RBD image is stored.
3566
3567 :returns: int - the pool id
3568 """
3569 return rbd_get_data_pool_id(self.image)
3570
3571 def get_parent_image_spec(self):
3572 """
3573 Get spec of the cloned image's parent
3574
3575 :returns: dict - contains the following keys:
3576 * ``pool_name`` (str) - parent pool name
3577 * ``pool_namespace`` (str) - parent pool namespace
3578 * ``image_name`` (str) - parent image name
3579 * ``snap_name`` (str) - parent snapshot name
3580
3581 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3582 """
3583 cdef:
3584 rbd_linked_image_spec_t parent_spec
3585 rbd_snap_spec_t snap_spec
3586 with nogil:
3587 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3588 if ret != 0:
3589 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3590
3591 result = {'pool_name': decode_cstr(parent_spec.pool_name),
3592 'pool_namespace': decode_cstr(parent_spec.pool_namespace),
3593 'image_name': decode_cstr(parent_spec.image_name),
3594 'snap_name': decode_cstr(snap_spec.name)}
3595
3596 rbd_linked_image_spec_cleanup(&parent_spec)
3597 rbd_snap_spec_cleanup(&snap_spec)
3598 return result
3599
3600 def parent_info(self):
3601 """
3602 Deprecated. Use `get_parent_image_spec` instead.
3603
3604 Get information about a cloned image's parent (if any)
3605
3606 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3607 of the parent image
3608 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3609 """
3610 parent = self.get_parent_image_spec()
3611 return (parent['pool_name'], parent['image_name'], parent['snap_name'])
3612
3613 def parent_id(self):
3614 """
3615 Get image id of a cloned image's parent (if any)
3616
3617 :returns: str - the parent id
3618 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3619 """
3620 cdef:
3621 rbd_linked_image_spec_t parent_spec
3622 rbd_snap_spec_t snap_spec
3623 with nogil:
3624 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3625 if ret != 0:
3626 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3627
3628 result = decode_cstr(parent_spec.image_id)
3629
3630 rbd_linked_image_spec_cleanup(&parent_spec)
3631 rbd_snap_spec_cleanup(&snap_spec)
3632 return result
3633
3634 def old_format(self):
3635 """
3636 Find out whether the image uses the old RBD format.
3637
3638 :returns: bool - whether the image uses the old RBD format
3639 """
3640 cdef uint8_t old
3641 with nogil:
3642 ret = rbd_get_old_format(self.image, &old)
3643 if ret != 0:
3644 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3645 return old != 0
3646
3647 def size(self):
3648 """
3649 Get the size of the image. If open to a snapshot, returns the
3650 size of that snapshot.
3651
3652 :returns: int - the size of the image in bytes
3653 """
3654 cdef uint64_t image_size
3655 with nogil:
3656 ret = rbd_get_size(self.image, &image_size)
3657 if ret != 0:
3658 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3659 return image_size
3660
3661 def features(self):
3662 """
3663 Get the features bitmask of the image.
3664
3665 :returns: int - the features bitmask of the image
3666 """
3667 cdef uint64_t features
3668 with nogil:
3669 ret = rbd_get_features(self.image, &features)
3670 if ret != 0:
3671 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3672 return features
3673
3674 def update_features(self, features, enabled):
3675 """
3676 Update the features bitmask of the image by enabling/disabling
3677 a single feature. The feature must support the ability to be
3678 dynamically enabled/disabled.
3679
3680 :param features: feature bitmask to enable/disable
3681 :type features: int
3682 :param enabled: whether to enable/disable the feature
3683 :type enabled: bool
3684 :raises: :class:`InvalidArgument`
3685 """
3686 cdef:
3687 uint64_t _features = features
3688 uint8_t _enabled = bool(enabled)
3689 with nogil:
3690 ret = rbd_update_features(self.image, _features, _enabled)
3691 if ret != 0:
3692 raise make_ex(ret, 'error updating features for image %s' %
3693 (self.name))
3694
3695 def op_features(self):
3696 """
3697 Get the op features bitmask of the image.
3698
3699 :returns: int - the op features bitmask of the image
3700 """
3701 cdef uint64_t op_features
3702 with nogil:
3703 ret = rbd_get_op_features(self.image, &op_features)
3704 if ret != 0:
3705 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3706 return op_features
3707
3708 def overlap(self):
3709 """
3710 Get the number of overlapping bytes between the image and its parent
3711 image. If open to a snapshot, returns the overlap between the snapshot
3712 and the parent image.
3713
3714 :returns: int - the overlap in bytes
3715 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3716 """
3717 cdef uint64_t overlap
3718 with nogil:
3719 ret = rbd_get_overlap(self.image, &overlap)
3720 if ret != 0:
3721 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3722 return overlap
3723
3724 def flags(self):
3725 """
3726 Get the flags bitmask of the image.
3727
3728 :returns: int - the flags bitmask of the image
3729 """
3730 cdef uint64_t flags
3731 with nogil:
3732 ret = rbd_get_flags(self.image, &flags)
3733 if ret != 0:
3734 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3735 return flags
3736
3737 def group(self):
3738 """
3739 Get information about the image's group.
3740
3741 :returns: dict - contains the following keys:
3742
3743 * ``pool`` (int) - id of the group pool
3744
3745 * ``name`` (str) - name of the group
3746
3747 """
3748 cdef rbd_group_info_t info
3749 with nogil:
3750 ret = rbd_get_group(self.image, &info, sizeof(info))
3751 if ret != 0:
3752 raise make_ex(ret, 'error getting group for image %s' % self.name)
3753 result = {
3754 'pool' : info.pool,
3755 'name' : decode_cstr(info.name)
3756 }
3757 rbd_group_info_cleanup(&info, sizeof(info))
3758 return result
3759
3760 def is_exclusive_lock_owner(self):
3761 """
3762 Get the status of the image exclusive lock.
3763
3764 :returns: bool - true if the image is exclusively locked
3765 """
3766 cdef int owner
3767 with nogil:
3768 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3769 if ret != 0:
3770 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3771 return owner == 1
3772
3773 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3774 stripe_unit=None, stripe_count=None, data_pool=None):
3775 """
3776 Copy the image to another location.
3777
3778 :param dest_ioctx: determines which pool to copy into
3779 :type dest_ioctx: :class:`rados.Ioctx`
3780 :param dest_name: the name of the copy
3781 :type dest_name: str
3782 :param features: bitmask of features to enable; if set, must include layering
3783 :type features: int
3784 :param order: the image is split into (2**order) byte objects
3785 :type order: int
3786 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3787 :type stripe_unit: int
3788 :param stripe_count: objects to stripe over before looping
3789 :type stripe_count: int
3790 :param data_pool: optional separate pool for data blocks
3791 :type data_pool: str
3792 :raises: :class:`TypeError`
3793 :raises: :class:`InvalidArgument`
3794 :raises: :class:`ImageExists`
3795 :raises: :class:`FunctionNotSupported`
3796 :raises: :class:`ArgumentOutOfRange`
3797 """
3798 dest_name = cstr(dest_name, 'dest_name')
3799 data_pool = cstr(data_pool, 'data_pool', opt=True)
3800 cdef:
3801 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3802 char *_dest_name = dest_name
3803 rbd_image_options_t opts
3804
3805 rbd_image_options_create(&opts)
3806 try:
3807 if features is not None:
3808 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3809 features)
3810 if order is not None:
3811 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3812 order)
3813 if stripe_unit is not None:
3814 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3815 stripe_unit)
3816 if stripe_count is not None:
3817 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3818 stripe_count)
3819 if data_pool is not None:
3820 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3821 data_pool)
3822 with nogil:
3823 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3824 finally:
3825 rbd_image_options_destroy(opts)
3826 if ret < 0:
3827 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3828
3829 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3830 stripe_unit=None, stripe_count=None, data_pool=None):
3831 """
3832 Deep copy the image to another location.
3833
3834 :param dest_ioctx: determines which pool to copy into
3835 :type dest_ioctx: :class:`rados.Ioctx`
3836 :param dest_name: the name of the copy
3837 :type dest_name: str
3838 :param features: bitmask of features to enable; if set, must include layering
3839 :type features: int
3840 :param order: the image is split into (2**order) byte objects
3841 :type order: int
3842 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3843 :type stripe_unit: int
3844 :param stripe_count: objects to stripe over before looping
3845 :type stripe_count: int
3846 :param data_pool: optional separate pool for data blocks
3847 :type data_pool: str
3848 :raises: :class:`TypeError`
3849 :raises: :class:`InvalidArgument`
3850 :raises: :class:`ImageExists`
3851 :raises: :class:`FunctionNotSupported`
3852 :raises: :class:`ArgumentOutOfRange`
3853 """
3854 dest_name = cstr(dest_name, 'dest_name')
3855 data_pool = cstr(data_pool, 'data_pool', opt=True)
3856 cdef:
3857 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3858 char *_dest_name = dest_name
3859 rbd_image_options_t opts
3860
3861 rbd_image_options_create(&opts)
3862 try:
3863 if features is not None:
3864 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3865 features)
3866 if order is not None:
3867 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3868 order)
3869 if stripe_unit is not None:
3870 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3871 stripe_unit)
3872 if stripe_count is not None:
3873 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3874 stripe_count)
3875 if data_pool is not None:
3876 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3877 data_pool)
3878 with nogil:
3879 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3880 finally:
3881 rbd_image_options_destroy(opts)
3882 if ret < 0:
3883 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3884
3885 def list_snaps(self):
3886 """
3887 Iterate over the snapshots of an image.
3888
3889 :returns: :class:`SnapIterator`
3890 """
3891 return SnapIterator(self)
3892
3893 def create_snap(self, name):
3894 """
3895 Create a snapshot of the image.
3896
3897 :param name: the name of the snapshot
3898 :type name: str
3899 :raises: :class:`ImageExists`
3900 """
3901 name = cstr(name, 'name')
3902 cdef char *_name = name
3903 with nogil:
3904 ret = rbd_snap_create(self.image, _name)
3905 if ret != 0:
3906 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3907
3908 def rename_snap(self, srcname, dstname):
3909 """
3910 rename a snapshot of the image.
3911
3912 :param srcname: the src name of the snapshot
3913 :type srcname: str
3914 :param dstname: the dst name of the snapshot
3915 :type dstname: str
3916 :raises: :class:`ImageExists`
3917 """
3918 srcname = cstr(srcname, 'srcname')
3919 dstname = cstr(dstname, 'dstname')
3920 cdef:
3921 char *_srcname = srcname
3922 char *_dstname = dstname
3923 with nogil:
3924 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3925 if ret != 0:
3926 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3927
3928 def remove_snap(self, name):
3929 """
3930 Delete a snapshot of the image.
3931
3932 :param name: the name of the snapshot
3933 :type name: str
3934 :raises: :class:`IOError`, :class:`ImageBusy`, :class:`ImageNotFound`
3935 """
3936 name = cstr(name, 'name')
3937 cdef char *_name = name
3938 with nogil:
3939 ret = rbd_snap_remove(self.image, _name)
3940 if ret != 0:
3941 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3942
3943 def remove_snap2(self, name, flags):
3944 """
3945 Delete a snapshot of the image.
3946
3947 :param name: the name of the snapshot
3948 :param flags: the flags for removal
3949 :type name: str
3950 :raises: :class:`IOError`, :class:`ImageBusy`
3951 """
3952 name = cstr(name, 'name')
3953 cdef:
3954 char *_name = name
3955 uint32_t _flags = flags
3956 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3957 with nogil:
3958 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
3959 if ret != 0:
3960 raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
3961
3962 def remove_snap_by_id(self, snap_id):
3963 """
3964 Delete a snapshot of the image by its id.
3965
3966 :param id: the id of the snapshot
3967 :type name: int
3968 :raises: :class:`IOError`, :class:`ImageBusy`
3969 """
3970 cdef:
3971 uint64_t _snap_id = snap_id
3972 with nogil:
3973 ret = rbd_snap_remove_by_id(self.image, _snap_id)
3974 if ret != 0:
3975 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
3976
3977 def rollback_to_snap(self, name):
3978 """
3979 Revert the image to its contents at a snapshot. This is a
3980 potentially expensive operation, since it rolls back each
3981 object individually.
3982
3983 :param name: the snapshot to rollback to
3984 :type name: str
3985 :raises: :class:`IOError`
3986 """
3987 name = cstr(name, 'name')
3988 cdef char *_name = name
3989 with nogil:
3990 ret = rbd_snap_rollback(self.image, _name)
3991 if ret != 0:
3992 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
3993
3994 def protect_snap(self, name):
3995 """
3996 Mark a snapshot as protected. This means it can't be deleted
3997 until it is unprotected.
3998
3999 :param name: the snapshot to protect
4000 :type name: str
4001 :raises: :class:`IOError`, :class:`ImageNotFound`
4002 """
4003 name = cstr(name, 'name')
4004 cdef char *_name = name
4005 with nogil:
4006 ret = rbd_snap_protect(self.image, _name)
4007 if ret != 0:
4008 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
4009
4010 def unprotect_snap(self, name):
4011 """
4012 Mark a snapshot unprotected. This allows it to be deleted if
4013 it was protected.
4014
4015 :param name: the snapshot to unprotect
4016 :type name: str
4017 :raises: :class:`IOError`, :class:`ImageNotFound`
4018 """
4019 name = cstr(name, 'name')
4020 cdef char *_name = name
4021 with nogil:
4022 ret = rbd_snap_unprotect(self.image, _name)
4023 if ret != 0:
4024 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
4025
4026 def is_protected_snap(self, name):
4027 """
4028 Find out whether a snapshot is protected from deletion.
4029
4030 :param name: the snapshot to check
4031 :type name: str
4032 :returns: bool - whether the snapshot is protected
4033 :raises: :class:`IOError`, :class:`ImageNotFound`
4034 """
4035 name = cstr(name, 'name')
4036 cdef:
4037 char *_name = name
4038 int is_protected
4039 with nogil:
4040 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
4041 if ret != 0:
4042 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
4043 return is_protected == 1
4044
4045 def snap_exists(self, name):
4046 """
4047 Find out whether a snapshot is exists.
4048
4049 :param name: the snapshot to check
4050 :type name: str
4051 :returns: bool - whether the snapshot is exists
4052 """
4053 name = cstr(name, 'name')
4054 cdef:
4055 char *_name = name
4056 bint _exists = False
4057 with nogil:
4058 ret = rbd_snap_exists(self.image, _name, &_exists)
4059 if ret != 0:
4060 raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
4061 return bool(_exists != 0)
4062
4063 def get_snap_limit(self):
4064 """
4065 Get the snapshot limit for an image.
4066
4067 :returns: int - the snapshot limit for an image
4068 """
4069
4070 cdef:
4071 uint64_t limit
4072 with nogil:
4073 ret = rbd_snap_get_limit(self.image, &limit)
4074 if ret != 0:
4075 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
4076 return limit
4077
4078 def set_snap_limit(self, limit):
4079 """
4080 Set the snapshot limit for an image.
4081
4082 :param limit: the new limit to set
4083 """
4084
4085 cdef:
4086 uint64_t _limit = limit
4087 with nogil:
4088 ret = rbd_snap_set_limit(self.image, _limit)
4089 if ret != 0:
4090 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
4091 return ret
4092
4093 def get_snap_timestamp(self, snap_id):
4094 """
4095 Get the snapshot timestamp for an image.
4096 :param snap_id: the snapshot id of a snap shot
4097 :returns: datetime - the snapshot timestamp for an image
4098 """
4099 cdef:
4100 timespec timestamp
4101 uint64_t _snap_id = snap_id
4102 with nogil:
4103 ret = rbd_snap_get_timestamp(self.image, _snap_id, &timestamp)
4104 if ret != 0:
4105 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
4106 return datetime.utcfromtimestamp(timestamp.tv_sec)
4107
4108 def remove_snap_limit(self):
4109 """
4110 Remove the snapshot limit for an image, essentially setting
4111 the limit to the maximum size allowed by the implementation.
4112 """
4113 with nogil:
4114 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
4115 if ret != 0:
4116 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
4117 return ret
4118
4119 def set_snap(self, name):
4120 """
4121 Set the snapshot to read from. Writes will raise ReadOnlyImage
4122 while a snapshot is set. Pass None to unset the snapshot
4123 (reads come from the current image) , and allow writing again.
4124
4125 :param name: the snapshot to read from, or None to unset the snapshot
4126 :type name: str or None
4127 """
4128 name = cstr(name, 'name', opt=True)
4129 cdef char *_name = opt_str(name)
4130 with nogil:
4131 ret = rbd_snap_set(self.image, _name)
4132 if ret != 0:
4133 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
4134
4135 def set_snap_by_id(self, snap_id):
4136 """
4137 Set the snapshot to read from. Writes will raise ReadOnlyImage
4138 while a snapshot is set. Pass None to unset the snapshot
4139 (reads come from the current image) , and allow writing again.
4140
4141 :param snap_id: the snapshot to read from, or None to unset the snapshot
4142 :type snap_id: int
4143 """
4144 if not snap_id:
4145 snap_id = _LIBRADOS_SNAP_HEAD
4146 cdef int64_t _snap_id = snap_id
4147 with nogil:
4148 ret = rbd_snap_set_by_id(self.image, _snap_id)
4149 if ret != 0:
4150 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
4151
4152 def snap_get_name(self, snap_id):
4153 """
4154 Get snapshot name by id.
4155
4156 :param snap_id: the snapshot id
4157 :type snap_id: int
4158 :returns: str - snapshot name
4159 :raises: :class:`ImageNotFound`
4160 """
4161 cdef:
4162 int ret = -errno.ERANGE
4163 int64_t _snap_id = snap_id
4164 size_t size = 512
4165 char *image_name = NULL
4166 try:
4167 while ret == -errno.ERANGE:
4168 image_name = <char *>realloc_chk(image_name, size)
4169 with nogil:
4170 ret = rbd_snap_get_name(self.image, _snap_id, image_name, &size)
4171
4172 if ret != 0:
4173 raise make_ex(ret, 'error snap_get_name.')
4174 return decode_cstr(image_name)
4175 finally:
4176 free(image_name)
4177
4178 def snap_get_id(self, snap_name):
4179 """
4180 Get snapshot id by name.
4181
4182 :param snap_name: the snapshot name
4183 :type snap_name: str
4184 :returns: int - snapshot id
4185 :raises: :class:`ImageNotFound`
4186 """
4187
4188 snap_name = cstr(snap_name, 'snap_name')
4189 cdef:
4190 const char *_snap_name = snap_name
4191 uint64_t snap_id
4192 with nogil:
4193 ret = rbd_snap_get_id(self.image, _snap_name, &snap_id)
4194 if ret != 0:
4195 raise make_ex(ret, 'error snap_get_id.')
4196 return snap_id
4197
4198 def read(self, offset, length, fadvise_flags=0):
4199 """
4200 Read data from the image. Raises :class:`InvalidArgument` if
4201 part of the range specified is outside the image.
4202
4203 :param offset: the offset to start reading at
4204 :type offset: int
4205 :param length: how many bytes to read
4206 :type length: int
4207 :param fadvise_flags: fadvise flags for this read
4208 :type fadvise_flags: int
4209 :returns: str - the data read
4210 :raises: :class:`InvalidArgument`, :class:`IOError`
4211 """
4212
4213 # This usage of the Python API allows us to construct a string
4214 # that librbd directly reads into, avoiding an extra copy. Although
4215 # strings are normally immutable, this usage is explicitly supported
4216 # for freshly created string objects.
4217 cdef:
4218 char *ret_buf
4219 uint64_t _offset = offset
4220 size_t _length = length
4221 int _fadvise_flags = fadvise_flags
4222 PyObject* ret_s = NULL
4223 ret_s = PyBytes_FromStringAndSize(NULL, length)
4224 try:
4225 ret_buf = PyBytes_AsString(ret_s)
4226 with nogil:
4227 ret = rbd_read2(self.image, _offset, _length, ret_buf,
4228 _fadvise_flags)
4229 if ret < 0:
4230 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
4231
4232 if ret != <ssize_t>length:
4233 _PyBytes_Resize(&ret_s, ret)
4234
4235 return <object>ret_s
4236 finally:
4237 # We DECREF unconditionally: the cast to object above will have
4238 # INCREFed if necessary. This also takes care of exceptions,
4239 # including if _PyString_Resize fails (that will free the string
4240 # itself and set ret_s to NULL, hence XDECREF).
4241 ref.Py_XDECREF(ret_s)
4242
4243 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
4244 include_parent = True, whole_object = False):
4245 """
4246 Iterate over the changed extents of an image.
4247
4248 This will call iterate_cb with three arguments:
4249
4250 (offset, length, exists)
4251
4252 where the changed extent starts at offset bytes, continues for
4253 length bytes, and is full of data (if exists is True) or zeroes
4254 (if exists is False).
4255
4256 If from_snapshot is None, it is interpreted as the beginning
4257 of time and this generates all allocated extents.
4258
4259 The end version is whatever is currently selected (via set_snap)
4260 for the image.
4261
4262 iterate_cb may raise an exception, which will abort the diff and will be
4263 propagated to the caller.
4264
4265 Raises :class:`InvalidArgument` if from_snapshot is after
4266 the currently set snapshot.
4267
4268 Raises :class:`ImageNotFound` if from_snapshot is not the name
4269 of a snapshot of the image.
4270
4271 :param offset: start offset in bytes
4272 :type offset: int
4273 :param length: size of region to report on, in bytes
4274 :type length: int
4275 :param from_snapshot: starting snapshot name, or None
4276 :type from_snapshot: str or None
4277 :param iterate_cb: function to call for each extent
4278 :type iterate_cb: function acception arguments for offset,
4279 length, and exists
4280 :param include_parent: True if full history diff should include parent
4281 :type include_parent: bool
4282 :param whole_object: True if diff extents should cover whole object
4283 :type whole_object: bool
4284 :raises: :class:`InvalidArgument`, :class:`IOError`,
4285 :class:`ImageNotFound`
4286 """
4287 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
4288 cdef:
4289 char *_from_snapshot = opt_str(from_snapshot)
4290 uint64_t _offset = offset, _length = length
4291 uint8_t _include_parent = include_parent
4292 uint8_t _whole_object = whole_object
4293 with nogil:
4294 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
4295 _length, _include_parent, _whole_object,
4296 &diff_iterate_cb, <void *>iterate_cb)
4297 if ret < 0:
4298 msg = 'error generating diff from snapshot %s' % from_snapshot
4299 raise make_ex(ret, msg)
4300
4301 def write(self, data, offset, fadvise_flags=0):
4302 """
4303 Write data to the image. Raises :class:`InvalidArgument` if
4304 part of the write would fall outside the image.
4305
4306 :param data: the data to be written
4307 :type data: bytes
4308 :param offset: where to start writing data
4309 :type offset: int
4310 :param fadvise_flags: fadvise flags for this write
4311 :type fadvise_flags: int
4312 :returns: int - the number of bytes written
4313 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
4314 :class:`InvalidArgument`, :class:`IOError`
4315 """
4316 if not isinstance(data, bytes):
4317 raise TypeError('data must be a byte string')
4318 cdef:
4319 uint64_t _offset = offset, length = len(data)
4320 char *_data = data
4321 int _fadvise_flags = fadvise_flags
4322 with nogil:
4323 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
4324
4325 if ret == <ssize_t>length:
4326 return ret
4327 elif ret < 0:
4328 raise make_ex(ret, "error writing to %s" % self.name)
4329 elif ret < <ssize_t>length:
4330 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
4331 else:
4332 raise LogicError("logic error: rbd_write(%s) \
4333 returned %d, but %d was the maximum number of bytes it could have \
4334 written." % (self.name, ret, length))
4335
4336 def discard(self, offset, length):
4337 """
4338 Trim the range from the image. It will be logically filled
4339 with zeroes.
4340 """
4341 cdef uint64_t _offset = offset, _length = length
4342 with nogil:
4343 ret = rbd_discard(self.image, _offset, _length)
4344 if ret < 0:
4345 msg = 'error discarding region %d~%d' % (offset, length)
4346 raise make_ex(ret, msg)
4347
4348 def flush(self):
4349 """
4350 Block until all writes are fully flushed if caching is enabled.
4351 """
4352 with nogil:
4353 ret = rbd_flush(self.image)
4354 if ret < 0:
4355 raise make_ex(ret, 'error flushing image')
4356
4357 def invalidate_cache(self):
4358 """
4359 Drop any cached data for the image.
4360 """
4361 with nogil:
4362 ret = rbd_invalidate_cache(self.image)
4363 if ret < 0:
4364 raise make_ex(ret, 'error invalidating cache')
4365
4366 def stripe_unit(self):
4367 """
4368 Return the stripe unit used for the image.
4369 """
4370 cdef uint64_t stripe_unit
4371 with nogil:
4372 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
4373 if ret != 0:
4374 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
4375 return stripe_unit
4376
4377 def stripe_count(self):
4378 """
4379 Return the stripe count used for the image.
4380 """
4381 cdef uint64_t stripe_count
4382 with nogil:
4383 ret = rbd_get_stripe_count(self.image, &stripe_count)
4384 if ret != 0:
4385 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
4386 return stripe_count
4387
4388 def create_timestamp(self):
4389 """
4390 Return the create timestamp for the image.
4391 """
4392 cdef:
4393 timespec timestamp
4394 with nogil:
4395 ret = rbd_get_create_timestamp(self.image, &timestamp)
4396 if ret != 0:
4397 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
4398 return datetime.utcfromtimestamp(timestamp.tv_sec)
4399
4400 def access_timestamp(self):
4401 """
4402 Return the access timestamp for the image.
4403 """
4404 cdef:
4405 timespec timestamp
4406 with nogil:
4407 ret = rbd_get_access_timestamp(self.image, &timestamp)
4408 if ret != 0:
4409 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
4410 return datetime.fromtimestamp(timestamp.tv_sec)
4411
4412 def modify_timestamp(self):
4413 """
4414 Return the modify timestamp for the image.
4415 """
4416 cdef:
4417 timespec timestamp
4418 with nogil:
4419 ret = rbd_get_modify_timestamp(self.image, &timestamp)
4420 if ret != 0:
4421 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
4422 return datetime.fromtimestamp(timestamp.tv_sec)
4423
4424 def flatten(self, on_progress=None):
4425 """
4426 Flatten clone image (copy all blocks from parent to child)
4427 :param on_progress: optional progress callback function
4428 :type on_progress: callback function
4429 """
4430 cdef:
4431 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
4432 void *_prog_arg = NULL
4433 if on_progress:
4434 _prog_cb = &progress_callback
4435 _prog_arg = <void *>on_progress
4436 with nogil:
4437 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
4438 if ret < 0:
4439 raise make_ex(ret, "error flattening %s" % self.name)
4440
4441 def sparsify(self, sparse_size):
4442 """
4443 Reclaim space for zeroed image extents
4444 """
4445 cdef:
4446 size_t _sparse_size = sparse_size
4447 with nogil:
4448 ret = rbd_sparsify(self.image, _sparse_size)
4449 if ret < 0:
4450 raise make_ex(ret, "error sparsifying %s" % self.name)
4451
4452 def rebuild_object_map(self):
4453 """
4454 Rebuild the object map for the image HEAD or currently set snapshot
4455 """
4456 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
4457 with nogil:
4458 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
4459 if ret < 0:
4460 raise make_ex(ret, "error rebuilding object map %s" % self.name)
4461
4462 def list_children(self):
4463 """
4464 List children of the currently set snapshot (set via set_snap()).
4465
4466 :returns: list - a list of (pool name, image name) tuples
4467 """
4468 cdef:
4469 rbd_linked_image_spec_t *children = NULL
4470 size_t num_children = 10
4471
4472 try:
4473 while True:
4474 children = <rbd_linked_image_spec_t*>realloc_chk(
4475 children, num_children * sizeof(rbd_linked_image_spec_t))
4476 with nogil:
4477 ret = rbd_list_children3(self.image, children,
4478 &num_children)
4479 if ret >= 0:
4480 break
4481 elif ret != -errno.ERANGE:
4482 raise make_ex(ret, 'error listing children.')
4483
4484 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
4485 in children[:num_children] if not x.trash]
4486 finally:
4487 if children:
4488 rbd_linked_image_spec_list_cleanup(children, num_children)
4489 free(children)
4490
4491 def list_children2(self):
4492 """
4493 Iterate over the children of the image or its snapshot.
4494
4495 :returns: :class:`ChildIterator`
4496 """
4497 return ChildIterator(self)
4498
4499 def list_descendants(self):
4500 """
4501 Iterate over the descendants of the image.
4502
4503 :returns: :class:`ChildIterator`
4504 """
4505 return ChildIterator(self, True)
4506
4507 def list_lockers(self):
4508 """
4509 List clients that have locked the image and information
4510 about the lock.
4511
4512 :returns: dict - contains the following keys:
4513
4514 * ``tag`` - the tag associated with the lock (every
4515 additional locker must use the same tag)
4516 * ``exclusive`` - boolean indicating whether the
4517 lock is exclusive or shared
4518 * ``lockers`` - a list of (client, cookie, address)
4519 tuples
4520 """
4521 cdef:
4522 size_t clients_size = 512, cookies_size = 512
4523 size_t addrs_size = 512, tag_size = 512
4524 int exclusive = 0
4525 char *c_clients = NULL
4526 char *c_cookies = NULL
4527 char *c_addrs = NULL
4528 char *c_tag = NULL
4529
4530 try:
4531 while True:
4532 c_clients = <char *>realloc_chk(c_clients, clients_size)
4533 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
4534 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
4535 c_tag = <char *>realloc_chk(c_tag, tag_size)
4536 with nogil:
4537 ret = rbd_list_lockers(self.image, &exclusive,
4538 c_tag, &tag_size,
4539 c_clients, &clients_size,
4540 c_cookies, &cookies_size,
4541 c_addrs, &addrs_size)
4542 if ret >= 0:
4543 break
4544 elif ret != -errno.ERANGE:
4545 raise make_ex(ret, 'error listing images')
4546 if ret == 0:
4547 return []
4548 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
4549 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
4550 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
4551 return {
4552 'tag' : decode_cstr(c_tag),
4553 'exclusive' : exclusive == 1,
4554 'lockers' : list(zip(clients, cookies, addrs)),
4555 }
4556 finally:
4557 free(c_clients)
4558 free(c_cookies)
4559 free(c_addrs)
4560 free(c_tag)
4561
4562 def lock_acquire(self, lock_mode):
4563 """
4564 Acquire a managed lock on the image.
4565
4566 :param lock_mode: lock mode to set
4567 :type lock_mode: int
4568 :raises: :class:`ImageBusy` if the lock could not be acquired
4569 """
4570 cdef:
4571 rbd_lock_mode_t _lock_mode = lock_mode
4572 with nogil:
4573 ret = rbd_lock_acquire(self.image, _lock_mode)
4574 if ret < 0:
4575 raise make_ex(ret, 'error acquiring lock on image')
4576
4577 def lock_release(self):
4578 """
4579 Release a managed lock on the image that was previously acquired.
4580 """
4581 with nogil:
4582 ret = rbd_lock_release(self.image)
4583 if ret < 0:
4584 raise make_ex(ret, 'error releasing lock on image')
4585
4586 def lock_get_owners(self):
4587 """
4588 Iterate over the lock owners of an image.
4589
4590 :returns: :class:`LockOwnerIterator`
4591 """
4592 return LockOwnerIterator(self)
4593
4594 def lock_break(self, lock_mode, lock_owner):
4595 """
4596 Break the image lock held by a another client.
4597
4598 :param lock_owner: the owner of the lock to break
4599 :type lock_owner: str
4600 """
4601 lock_owner = cstr(lock_owner, 'lock_owner')
4602 cdef:
4603 rbd_lock_mode_t _lock_mode = lock_mode
4604 char *_lock_owner = lock_owner
4605 with nogil:
4606 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
4607 if ret < 0:
4608 raise make_ex(ret, 'error breaking lock on image')
4609
4610 def lock_exclusive(self, cookie):
4611 """
4612 Take an exclusive lock on the image.
4613
4614 :raises: :class:`ImageBusy` if a different client or cookie locked it
4615 :class:`ImageExists` if the same client and cookie locked it
4616 """
4617 cookie = cstr(cookie, 'cookie')
4618 cdef char *_cookie = cookie
4619 with nogil:
4620 ret = rbd_lock_exclusive(self.image, _cookie)
4621 if ret < 0:
4622 raise make_ex(ret, 'error acquiring exclusive lock on image')
4623
4624 def lock_shared(self, cookie, tag):
4625 """
4626 Take a shared lock on the image. The tag must match
4627 that of the existing lockers, if any.
4628
4629 :raises: :class:`ImageBusy` if a different client or cookie locked it
4630 :class:`ImageExists` if the same client and cookie locked it
4631 """
4632 cookie = cstr(cookie, 'cookie')
4633 tag = cstr(tag, 'tag')
4634 cdef:
4635 char *_cookie = cookie
4636 char *_tag = tag
4637 with nogil:
4638 ret = rbd_lock_shared(self.image, _cookie, _tag)
4639 if ret < 0:
4640 raise make_ex(ret, 'error acquiring shared lock on image')
4641
4642 def unlock(self, cookie):
4643 """
4644 Release a lock on the image that was locked by this rados client.
4645 """
4646 cookie = cstr(cookie, 'cookie')
4647 cdef char *_cookie = cookie
4648 with nogil:
4649 ret = rbd_unlock(self.image, _cookie)
4650 if ret < 0:
4651 raise make_ex(ret, 'error unlocking image')
4652
4653 def break_lock(self, client, cookie):
4654 """
4655 Release a lock held by another rados client.
4656 """
4657 client = cstr(client, 'client')
4658 cookie = cstr(cookie, 'cookie')
4659 cdef:
4660 char *_client = client
4661 char *_cookie = cookie
4662 with nogil:
4663 ret = rbd_break_lock(self.image, _client, _cookie)
4664 if ret < 0:
4665 raise make_ex(ret, 'error unlocking image')
4666
4667 def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
4668 """
4669 Enable mirroring for the image.
4670 """
4671 cdef rbd_mirror_image_mode_t c_mode = mode
4672 with nogil:
4673 ret = rbd_mirror_image_enable2(self.image, c_mode)
4674 if ret < 0:
4675 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4676
4677 def mirror_image_disable(self, force):
4678 """
4679 Disable mirroring for the image.
4680
4681 :param force: force disabling
4682 :type force: bool
4683 """
4684 cdef bint c_force = force
4685 with nogil:
4686 ret = rbd_mirror_image_disable(self.image, c_force)
4687 if ret < 0:
4688 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4689
4690 def mirror_image_promote(self, force):
4691 """
4692 Promote the image to primary for mirroring.
4693
4694 :param force: force promoting
4695 :type force: bool
4696 """
4697 cdef bint c_force = force
4698 with nogil:
4699 ret = rbd_mirror_image_promote(self.image, c_force)
4700 if ret < 0:
4701 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4702
4703 def mirror_image_demote(self):
4704 """
4705 Demote the image to secondary for mirroring.
4706 """
4707 with nogil:
4708 ret = rbd_mirror_image_demote(self.image)
4709 if ret < 0:
4710 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4711
4712 def mirror_image_resync(self):
4713 """
4714 Flag the image to resync.
4715 """
4716 with nogil:
4717 ret = rbd_mirror_image_resync(self.image)
4718 if ret < 0:
4719 raise make_ex(ret, 'error to resync image %s' % self.name)
4720
4721 def mirror_image_create_snapshot(self):
4722 """
4723 Create mirror snapshot.
4724
4725 :param force: ignore mirror snapshot limit
4726 :type force: bool
4727 :returns: int - the snapshot Id
4728 """
4729 cdef:
4730 uint64_t snap_id
4731 with nogil:
4732 ret = rbd_mirror_image_create_snapshot(self.image, &snap_id)
4733 if ret < 0:
4734 raise make_ex(ret, 'error creating mirror snapshot for image %s' %
4735 self.name)
4736 return snap_id
4737
4738 def mirror_image_get_info(self):
4739 """
4740 Get mirror info for the image.
4741
4742 :returns: dict - contains the following keys:
4743
4744 * ``global_id`` (str) - image global id
4745
4746 * ``state`` (int) - mirror state
4747
4748 * ``primary`` (bool) - is image primary
4749 """
4750 cdef rbd_mirror_image_info_t c_info
4751 with nogil:
4752 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4753 if ret != 0:
4754 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4755 info = {
4756 'global_id' : decode_cstr(c_info.global_id),
4757 'state' : int(c_info.state),
4758 'primary' : c_info.primary,
4759 }
4760 rbd_mirror_image_get_info_cleanup(&c_info)
4761 return info
4762
4763 def mirror_image_get_mode(self):
4764 """
4765 Get mirror mode for the image.
4766
4767 :returns: int - mirror mode
4768 """
4769 cdef rbd_mirror_image_mode_t c_mode
4770 with nogil:
4771 ret = rbd_mirror_image_get_mode(self.image, &c_mode)
4772 if ret != 0:
4773 raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
4774 return int(c_mode)
4775
4776 def mirror_image_get_status(self):
4777 """
4778 Get mirror status for the image.
4779
4780 :returns: dict - contains the following keys:
4781
4782 * ``name`` (str) - mirror image name
4783
4784 * ``id`` (str) - mirror image id
4785
4786 * ``info`` (dict) - mirror image info
4787
4788 * ``state`` (int) - status mirror state
4789
4790 * ``description`` (str) - status description
4791
4792 * ``last_update`` (datetime) - last status update time
4793
4794 * ``up`` (bool) - is mirroring agent up
4795
4796 * ``remote_statuses`` (array) -
4797
4798 * ``mirror_uuid`` (str) - remote mirror uuid
4799
4800 * ``state`` (int) - status mirror state
4801
4802 * ``description`` (str) - status description
4803
4804 * ``last_update`` (datetime) - last status update time
4805
4806 * ``up`` (bool) - is mirroring agent up
4807 """
4808 cdef:
4809 rbd_mirror_image_site_status_t *s_status
4810 rbd_mirror_image_global_status_t c_status
4811 try:
4812 with nogil:
4813 ret = rbd_mirror_image_get_global_status(self.image, &c_status,
4814 sizeof(c_status))
4815 if ret != 0:
4816 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4817
4818 local_status = None
4819 site_statuses = []
4820 for i in range(c_status.site_statuses_count):
4821 s_status = &c_status.site_statuses[i]
4822 site_status = {
4823 'state' : s_status.state,
4824 'description' : decode_cstr(s_status.description),
4825 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
4826 'up' : s_status.up,
4827 }
4828 mirror_uuid = decode_cstr(s_status.mirror_uuid)
4829 if mirror_uuid == '':
4830 local_status = site_status
4831 else:
4832 site_statuses['mirror_uuid'] = mirror_uuid
4833 site_statuses += site_status
4834 status = {
4835 'name': decode_cstr(c_status.name),
4836 'id' : self.id(),
4837 'info': {
4838 'global_id' : decode_cstr(c_status.info.global_id),
4839 'state' : int(c_status.info.state),
4840 'primary' : c_status.info.primary,
4841 },
4842 'remote_statuses': site_statuses,
4843 }
4844 if local_status:
4845 status.update(local_status)
4846 finally:
4847 rbd_mirror_image_global_status_cleanup(&c_status)
4848 return status
4849
4850 def mirror_image_get_instance_id(self):
4851 """
4852 Get mirror instance id for the image.
4853
4854 :returns: str - instance id
4855 """
4856 cdef:
4857 int ret = -errno.ERANGE
4858 size_t size = 32
4859 char *instance_id = NULL
4860 try:
4861 while ret == -errno.ERANGE and size <= 4096:
4862 instance_id = <char *>realloc_chk(instance_id, size)
4863 with nogil:
4864 ret = rbd_mirror_image_get_instance_id(self.image,
4865 instance_id, &size)
4866 if ret != 0:
4867 raise make_ex(ret,
4868 'error getting mirror instance id for image %s' %
4869 self.name)
4870 return decode_cstr(instance_id)
4871 finally:
4872 free(instance_id)
4873
4874 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4875 """
4876 Asynchronously read data from the image
4877
4878 Raises :class:`InvalidArgument` if part of the range specified is
4879 outside the image.
4880
4881 oncomplete will be called with the returned read value as
4882 well as the completion:
4883
4884 oncomplete(completion, data_read)
4885
4886 :param offset: the offset to start reading at
4887 :type offset: int
4888 :param length: how many bytes to read
4889 :type length: int
4890 :param oncomplete: what to do when the read is complete
4891 :type oncomplete: completion
4892 :param fadvise_flags: fadvise flags for this read
4893 :type fadvise_flags: int
4894 :returns: :class:`Completion` - the completion object
4895 :raises: :class:`InvalidArgument`, :class:`IOError`
4896 """
4897
4898 cdef:
4899 char *ret_buf
4900 uint64_t _offset = offset
4901 size_t _length = length
4902 int _fadvise_flags = fadvise_flags
4903 Completion completion
4904
4905 def oncomplete_(completion_v):
4906 cdef Completion _completion_v = completion_v
4907 return_value = _completion_v.get_return_value()
4908 if return_value > 0 and return_value != length:
4909 _PyBytes_Resize(&_completion_v.buf, return_value)
4910 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
4911
4912 completion = self.__get_completion(oncomplete_)
4913 completion.buf = PyBytes_FromStringAndSize(NULL, length)
4914 ret_buf = PyBytes_AsString(completion.buf)
4915 try:
4916 completion.__persist()
4917 with nogil:
4918 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
4919 completion.rbd_comp, _fadvise_flags)
4920 if ret < 0:
4921 raise make_ex(ret, 'error reading %s %ld~%ld' %
4922 (self.name, offset, length))
4923 except:
4924 completion.__unpersist()
4925 raise
4926
4927 return completion
4928
4929 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
4930 """
4931 Asynchronously write data to the image
4932
4933 Raises :class:`InvalidArgument` if part of the write would fall outside
4934 the image.
4935
4936 oncomplete will be called with the completion:
4937
4938 oncomplete(completion)
4939
4940 :param data: the data to be written
4941 :type data: bytes
4942 :param offset: the offset to start writing at
4943 :type offset: int
4944 :param oncomplete: what to do when the write is complete
4945 :type oncomplete: completion
4946 :param fadvise_flags: fadvise flags for this write
4947 :type fadvise_flags: int
4948 :returns: :class:`Completion` - the completion object
4949 :raises: :class:`InvalidArgument`, :class:`IOError`
4950 """
4951
4952 cdef:
4953 uint64_t _offset = offset
4954 char *_data = data
4955 size_t _length = len(data)
4956 int _fadvise_flags = fadvise_flags
4957 Completion completion
4958
4959 completion = self.__get_completion(oncomplete)
4960 try:
4961 completion.__persist()
4962 with nogil:
4963 ret = rbd_aio_write2(self.image, _offset, _length, _data,
4964 completion.rbd_comp, _fadvise_flags)
4965 if ret < 0:
4966 raise make_ex(ret, 'error writing %s %ld~%ld' %
4967 (self.name, offset, _length))
4968 except:
4969 completion.__unpersist()
4970 raise
4971
4972 return completion
4973
4974 def aio_discard(self, offset, length, oncomplete):
4975 """
4976 Asynchronously trim the range from the image. It will be logically
4977 filled with zeroes.
4978 """
4979
4980 cdef:
4981 uint64_t _offset = offset
4982 size_t _length = length
4983 Completion completion
4984
4985 completion = self.__get_completion(oncomplete)
4986 try:
4987 completion.__persist()
4988 with nogil:
4989 ret = rbd_aio_discard(self.image, _offset, _length,
4990 completion.rbd_comp)
4991 if ret < 0:
4992 raise make_ex(ret, 'error discarding %s %ld~%ld' %
4993 (self.name, offset, _length))
4994 except:
4995 completion.__unpersist()
4996 raise
4997
4998 return completion
4999
5000 def aio_flush(self, oncomplete):
5001 """
5002 Asynchronously wait until all writes are fully flushed if caching is
5003 enabled.
5004 """
5005
5006 cdef Completion completion = self.__get_completion(oncomplete)
5007 try:
5008 completion.__persist()
5009 with nogil:
5010 ret = rbd_aio_flush(self.image, completion.rbd_comp)
5011 if ret < 0:
5012 raise make_ex(ret, 'error flushing')
5013 except:
5014 completion.__unpersist()
5015 raise
5016
5017 return completion
5018
5019 def metadata_get(self, key):
5020 """
5021 Get image metadata for the given key.
5022
5023 :param key: metadata key
5024 :type key: str
5025 :returns: str - metadata value
5026 """
5027 key = cstr(key, 'key')
5028 cdef:
5029 char *_key = key
5030 size_t size = 4096
5031 char *value = NULL
5032 int ret
5033 try:
5034 while True:
5035 value = <char *>realloc_chk(value, size)
5036 with nogil:
5037 ret = rbd_metadata_get(self.image, _key, value, &size)
5038 if ret != -errno.ERANGE:
5039 break
5040 if ret == -errno.ENOENT:
5041 raise KeyError('no metadata %s for image %s' % (key, self.name))
5042 if ret != 0:
5043 raise make_ex(ret, 'error getting metadata %s for image %s' %
5044 (key, self.name))
5045 return decode_cstr(value)
5046 finally:
5047 free(value)
5048
5049 def metadata_set(self, key, value):
5050 """
5051 Set image metadata for the given key.
5052
5053 :param key: metadata key
5054 :type key: str
5055 :param value: metadata value
5056 :type value: str
5057 """
5058 key = cstr(key, 'key')
5059 value = cstr(value, 'value')
5060 cdef:
5061 char *_key = key
5062 char *_value = value
5063 with nogil:
5064 ret = rbd_metadata_set(self.image, _key, _value)
5065
5066 if ret != 0:
5067 raise make_ex(ret, 'error setting metadata %s for image %s' %
5068 (key, self.name))
5069
5070
5071 def metadata_remove(self, key):
5072 """
5073 Remove image metadata for the given key.
5074
5075 :param key: metadata key
5076 :type key: str
5077 """
5078 key = cstr(key, 'key')
5079 cdef:
5080 char *_key = key
5081 with nogil:
5082 ret = rbd_metadata_remove(self.image, _key)
5083
5084 if ret == -errno.ENOENT:
5085 raise KeyError('no metadata %s for image %s' % (key, self.name))
5086 if ret != 0:
5087 raise make_ex(ret, 'error removing metadata %s for image %s' %
5088 (key, self.name))
5089
5090 def metadata_list(self):
5091 """
5092 List image metadata.
5093
5094 :returns: :class:`MetadataIterator`
5095 """
5096 return MetadataIterator(self)
5097
5098 def watchers_list(self):
5099 """
5100 List image watchers.
5101
5102 :returns: :class:`WatcherIterator`
5103 """
5104 return WatcherIterator(self)
5105
5106 def config_list(self):
5107 """
5108 List image-level config overrides.
5109
5110 :returns: :class:`ConfigImageIterator`
5111 """
5112 return ConfigImageIterator(self)
5113
5114
5115 def config_set(self, key, value):
5116 """
5117 Set an image-level configuration override.
5118
5119 :param key: key
5120 :type key: str
5121 :param value: value
5122 :type value: str
5123 """
5124 conf_key = 'conf_' + key
5125 conf_key = cstr(conf_key, 'key')
5126 value = cstr(value, 'value')
5127 cdef:
5128 char *_key = conf_key
5129 char *_value = value
5130 with nogil:
5131 ret = rbd_metadata_set(self.image, _key, _value)
5132
5133 if ret != 0:
5134 raise make_ex(ret, 'error setting config %s for image %s' %
5135 (key, self.name))
5136
5137
5138 def config_get(self, key):
5139 """
5140 Get an image-level configuration override.
5141
5142 :param key: key
5143 :type key: str
5144 :returns: str - value
5145 """
5146 conf_key = 'conf_' + key
5147 conf_key = cstr(conf_key, 'key')
5148 cdef:
5149 char *_key = conf_key
5150 size_t size = 4096
5151 char *value = NULL
5152 int ret
5153 try:
5154 while True:
5155 value = <char *>realloc_chk(value, size)
5156 with nogil:
5157 ret = rbd_metadata_get(self.image, _key, value, &size)
5158 if ret != -errno.ERANGE:
5159 break
5160 if ret == -errno.ENOENT:
5161 raise KeyError('no config %s for image %s' % (key, self.name))
5162 if ret != 0:
5163 raise make_ex(ret, 'error getting config %s for image %s' %
5164 (key, self.name))
5165 return decode_cstr(value)
5166 finally:
5167 free(value)
5168
5169
5170 def config_remove(self, key):
5171 """
5172 Remove an image-level configuration override.
5173
5174 :param key: key
5175 :type key: str
5176 """
5177 conf_key = 'conf_' + key
5178 conf_key = cstr(conf_key, 'key')
5179 cdef:
5180 char *_key = conf_key
5181 with nogil:
5182 ret = rbd_metadata_remove(self.image, _key)
5183
5184 if ret == -errno.ENOENT:
5185 raise KeyError('no config %s for image %s' % (key, self.name))
5186 if ret != 0:
5187 raise make_ex(ret, 'error removing config %s for image %s' %
5188 (key, self.name))
5189
5190
5191 def snap_get_namespace_type(self, snap_id):
5192 """
5193 Get the snapshot namespace type.
5194 :param snap_id: the snapshot id of a snap shot
5195 :type key: int
5196 """
5197 cdef:
5198 rbd_snap_namespace_type_t namespace_type
5199 uint64_t _snap_id = snap_id
5200 with nogil:
5201 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
5202 if ret != 0:
5203 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
5204
5205 return namespace_type
5206
5207 def snap_get_group_namespace(self, snap_id):
5208 """
5209 get the group namespace details.
5210 :param snap_id: the snapshot id of the group snapshot
5211 :type key: int
5212 :returns: dict - contains the following keys:
5213
5214 * ``pool`` (int) - pool id
5215
5216 * ``name`` (str) - group name
5217
5218 * ``snap_name`` (str) - group snap name
5219 """
5220 cdef:
5221 rbd_snap_group_namespace_t group_namespace
5222 uint64_t _snap_id = snap_id
5223 with nogil:
5224 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
5225 &group_namespace,
5226 sizeof(rbd_snap_group_namespace_t))
5227 if ret != 0:
5228 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
5229
5230 info = {
5231 'pool' : group_namespace.group_pool,
5232 'name' : decode_cstr(group_namespace.group_name),
5233 'snap_name' : decode_cstr(group_namespace.group_snap_name)
5234 }
5235 rbd_snap_group_namespace_cleanup(&group_namespace,
5236 sizeof(rbd_snap_group_namespace_t))
5237 return info
5238
5239 def snap_get_trash_namespace(self, snap_id):
5240 """
5241 get the trash namespace details.
5242 :param snap_id: the snapshot id of the trash snapshot
5243 :type key: int
5244 :returns: dict - contains the following keys:
5245
5246 * ``original_name`` (str) - original snap name
5247 """
5248 cdef:
5249 uint64_t _snap_id = snap_id
5250 size_t _size = 512
5251 char *_name = NULL
5252 try:
5253 while True:
5254 _name = <char*>realloc_chk(_name, _size);
5255 with nogil:
5256 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
5257 _name, _size)
5258 if ret >= 0:
5259 break
5260 elif ret != -errno.ERANGE:
5261 raise make_ex(ret, 'error getting snapshot trash '
5262 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
5263 return {
5264 'original_name' : decode_cstr(_name)
5265 }
5266 finally:
5267 free(_name)
5268
5269 def snap_get_mirror_namespace(self, snap_id):
5270 """
5271 get the mirror namespace details.
5272 :param snap_id: the snapshot id of the mirror snapshot
5273 :type key: int
5274 :returns: dict - contains the following keys:
5275
5276 * ``state`` (int) - the snapshot state
5277
5278 * ``mirror_peer_uuids`` (list) - mirror peer uuids
5279
5280 * ``complete`` (bool) - True if snapshot is complete
5281
5282 * ``primary_mirror_uuid`` (str) - primary mirror uuid
5283
5284 * ``primary_snap_id`` (int) - primary snapshot Id
5285
5286 * ``last_copied_object_number`` (int) - last copied object number
5287 """
5288 cdef:
5289 rbd_snap_mirror_namespace_t sn
5290 uint64_t _snap_id = snap_id
5291 with nogil:
5292 ret = rbd_snap_get_mirror_namespace(
5293 self.image, _snap_id, &sn,
5294 sizeof(rbd_snap_mirror_namespace_t))
5295 if ret != 0:
5296 raise make_ex(ret, 'error getting snapshot mirror '
5297 'namespace for image: %s, snap_id: %d' %
5298 (self.name, snap_id))
5299 uuids = []
5300 cdef char *p = sn.mirror_peer_uuids
5301 for i in range(sn.mirror_peer_uuids_count):
5302 uuid = decode_cstr(p)
5303 uuids.append(uuid)
5304 p += len(uuid) + 1
5305 info = {
5306 'state' : sn.state,
5307 'mirror_peer_uuids' : uuids,
5308 'complete' : sn.complete,
5309 'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
5310 'primary_snap_id' : sn.primary_snap_id,
5311 'last_copied_object_number' : sn.last_copied_object_number,
5312 }
5313 rbd_snap_mirror_namespace_cleanup(
5314 &sn, sizeof(rbd_snap_mirror_namespace_t))
5315 return info
5316
5317
5318 cdef class ImageIterator(object):
5319 """
5320 Iterator over RBD images in a pool
5321
5322 Yields a dictionary containing information about the images
5323
5324 Keys are:
5325
5326 * ``id`` (str) - image id
5327
5328 * ``name`` (str) - image name
5329 """
5330 cdef rados_ioctx_t ioctx
5331 cdef rbd_image_spec_t *images
5332 cdef size_t num_images
5333
5334 def __init__(self, ioctx):
5335 self.ioctx = convert_ioctx(ioctx)
5336 self.images = NULL
5337 self.num_images = 1024
5338 while True:
5339 self.images = <rbd_image_spec_t*>realloc_chk(
5340 self.images, self.num_images * sizeof(rbd_image_spec_t))
5341 with nogil:
5342 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
5343 if ret >= 0:
5344 break
5345 elif ret == -errno.ERANGE:
5346 self.num_images *= 2
5347 else:
5348 raise make_ex(ret, 'error listing images.')
5349
5350 def __iter__(self):
5351 for i in range(self.num_images):
5352 yield {
5353 'id' : decode_cstr(self.images[i].id),
5354 'name' : decode_cstr(self.images[i].name)
5355 }
5356
5357 def __dealloc__(self):
5358 if self.images:
5359 rbd_image_spec_list_cleanup(self.images, self.num_images)
5360 free(self.images)
5361
5362
5363 cdef class LockOwnerIterator(object):
5364 """
5365 Iterator over managed lock owners for an image
5366
5367 Yields a dictionary containing information about the image's lock
5368
5369 Keys are:
5370
5371 * ``mode`` (int) - active lock mode
5372
5373 * ``owner`` (str) - lock owner name
5374 """
5375
5376 cdef:
5377 rbd_lock_mode_t lock_mode
5378 char **lock_owners
5379 size_t num_lock_owners
5380 object image
5381
5382 def __init__(self, Image image):
5383 self.image = image
5384 self.lock_owners = NULL
5385 self.num_lock_owners = 8
5386 while True:
5387 self.lock_owners = <char**>realloc_chk(self.lock_owners,
5388 self.num_lock_owners *
5389 sizeof(char*))
5390 with nogil:
5391 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
5392 self.lock_owners,
5393 &self.num_lock_owners)
5394 if ret >= 0:
5395 break
5396 elif ret != -errno.ERANGE:
5397 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
5398
5399 def __iter__(self):
5400 for i in range(self.num_lock_owners):
5401 yield {
5402 'mode' : int(self.lock_mode),
5403 'owner' : decode_cstr(self.lock_owners[i]),
5404 }
5405
5406 def __dealloc__(self):
5407 if self.lock_owners:
5408 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
5409 free(self.lock_owners)
5410
5411 cdef class MetadataIterator(object):
5412 """
5413 Iterator over metadata list for an image.
5414
5415 Yields ``(key, value)`` tuple.
5416
5417 * ``key`` (str) - metadata key
5418 * ``value`` (str) - metadata value
5419 """
5420
5421 cdef:
5422 object image_name
5423 rbd_image_t image
5424 char *last_read
5425 uint64_t max_read
5426 object next_chunk
5427
5428 def __init__(self, Image image):
5429 self.image_name = image.name
5430 self.image = image.image
5431 self.last_read = strdup("")
5432 self.max_read = 32
5433 self.get_next_chunk()
5434
5435 def __iter__(self):
5436 while len(self.next_chunk) > 0:
5437 for pair in self.next_chunk:
5438 yield pair
5439 if len(self.next_chunk) < self.max_read:
5440 break
5441 self.get_next_chunk()
5442
5443 def __dealloc__(self):
5444 if self.last_read:
5445 free(self.last_read)
5446
5447 def get_next_chunk(self):
5448 cdef:
5449 char *c_keys = NULL
5450 size_t keys_size = 4096
5451 char *c_vals = NULL
5452 size_t vals_size = 4096
5453 try:
5454 while True:
5455 c_keys = <char *>realloc_chk(c_keys, keys_size)
5456 c_vals = <char *>realloc_chk(c_vals, vals_size)
5457 with nogil:
5458 ret = rbd_metadata_list(self.image, self.last_read,
5459 self.max_read, c_keys, &keys_size,
5460 c_vals, &vals_size)
5461 if ret >= 0:
5462 break
5463 elif ret != -errno.ERANGE:
5464 raise make_ex(ret, 'error listing metadata for image %s' %
5465 self.image_name)
5466 keys = [decode_cstr(key) for key in
5467 c_keys[:keys_size].split(b'\0') if key]
5468 vals = [decode_cstr(val) for val in
5469 c_vals[:vals_size].split(b'\0') if val]
5470 if len(keys) > 0:
5471 last_read = cstr(keys[-1], 'last_read')
5472 free(self.last_read)
5473 self.last_read = strdup(last_read)
5474 self.next_chunk = list(zip(keys, vals))
5475 finally:
5476 free(c_keys)
5477 free(c_vals)
5478
5479 cdef class SnapIterator(object):
5480 """
5481 Iterator over snapshot info for an image.
5482
5483 Yields a dictionary containing information about a snapshot.
5484
5485 Keys are:
5486
5487 * ``id`` (int) - numeric identifier of the snapshot
5488
5489 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
5490
5491 * ``name`` (str) - name of the snapshot
5492
5493 * ``namespace`` (int) - enum for snap namespace
5494
5495 * ``group`` (dict) - optional for group namespace snapshots
5496
5497 * ``trash`` (dict) - optional for trash namespace snapshots
5498
5499 * ``mirror`` (dict) - optional for mirror namespace snapshots
5500 """
5501
5502 cdef rbd_snap_info_t *snaps
5503 cdef int num_snaps
5504 cdef object image
5505
5506 def __init__(self, Image image):
5507 self.image = image
5508 self.snaps = NULL
5509 self.num_snaps = 10
5510 while True:
5511 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
5512 self.num_snaps *
5513 sizeof(rbd_snap_info_t))
5514 with nogil:
5515 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
5516 if ret >= 0:
5517 self.num_snaps = ret
5518 break
5519 elif ret != -errno.ERANGE:
5520 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
5521
5522 def __iter__(self):
5523 for i in range(self.num_snaps):
5524 s = {
5525 'id' : self.snaps[i].id,
5526 'size' : self.snaps[i].size,
5527 'name' : decode_cstr(self.snaps[i].name),
5528 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
5529 }
5530 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
5531 try:
5532 group = self.image.snap_get_group_namespace(self.snaps[i].id)
5533 except:
5534 group = None
5535 s['group'] = group
5536 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
5537 try:
5538 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
5539 except:
5540 trash = None
5541 s['trash'] = trash
5542 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR:
5543 try:
5544 mirror = self.image.snap_get_mirror_namespace(
5545 self.snaps[i].id)
5546 except:
5547 mirror = None
5548 s['mirror'] = mirror
5549 yield s
5550
5551 def __dealloc__(self):
5552 if self.snaps:
5553 rbd_snap_list_end(self.snaps)
5554 free(self.snaps)
5555
5556 cdef class TrashIterator(object):
5557 """
5558 Iterator over trash entries.
5559
5560 Yields a dictionary containing trash info of an image.
5561
5562 Keys are:
5563
5564 * `id` (str) - image id
5565
5566 * `name` (str) - image name
5567
5568 * `source` (str) - source of deletion
5569
5570 * `deletion_time` (datetime) - time of deletion
5571
5572 * `deferment_end_time` (datetime) - time that an image is allowed to be
5573 removed from trash
5574 """
5575
5576 cdef:
5577 rados_ioctx_t ioctx
5578 size_t num_entries
5579 rbd_trash_image_info_t *entries
5580
5581 def __init__(self, ioctx):
5582 self.ioctx = convert_ioctx(ioctx)
5583 self.num_entries = 1024
5584 self.entries = NULL
5585 while True:
5586 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
5587 self.num_entries *
5588 sizeof(rbd_trash_image_info_t))
5589 with nogil:
5590 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
5591 if ret >= 0:
5592 self.num_entries = ret
5593 break
5594 elif ret != -errno.ERANGE:
5595 raise make_ex(ret, 'error listing trash entries')
5596
5597 __source_string = ['USER', 'MIRRORING']
5598
5599 def __iter__(self):
5600 for i in range(self.num_entries):
5601 yield {
5602 'id' : decode_cstr(self.entries[i].id),
5603 'name' : decode_cstr(self.entries[i].name),
5604 'source' : TrashIterator.__source_string[self.entries[i].source],
5605 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
5606 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
5607 }
5608
5609 def __dealloc__(self):
5610 rbd_trash_list_cleanup(self.entries, self.num_entries)
5611 if self.entries:
5612 free(self.entries)
5613
5614 cdef class ChildIterator(object):
5615 """
5616 Iterator over child info for the image or its snapshot.
5617
5618 Yields a dictionary containing information about a child.
5619
5620 Keys are:
5621
5622 * ``pool`` (str) - name of the pool
5623
5624 * ``pool_namespace`` (str) - namespace of the pool
5625
5626 * ``image`` (str) - name of the child
5627
5628 * ``id`` (str) - id of the child
5629
5630 * ``trash`` (bool) - True if child is in trash bin
5631 """
5632
5633 cdef rbd_linked_image_spec_t *children
5634 cdef size_t num_children
5635 cdef object image
5636
5637 def __init__(self, Image image, descendants=False):
5638 self.image = image
5639 self.children = NULL
5640 self.num_children = 10
5641 while True:
5642 self.children = <rbd_linked_image_spec_t*>realloc_chk(
5643 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
5644 if descendants:
5645 with nogil:
5646 ret = rbd_list_descendants(image.image, self.children,
5647 &self.num_children)
5648 else:
5649 with nogil:
5650 ret = rbd_list_children3(image.image, self.children,
5651 &self.num_children)
5652 if ret >= 0:
5653 break
5654 elif ret != -errno.ERANGE:
5655 raise make_ex(ret, 'error listing children.')
5656
5657 def __iter__(self):
5658 for i in range(self.num_children):
5659 yield {
5660 'pool' : decode_cstr(self.children[i].pool_name),
5661 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
5662 'image' : decode_cstr(self.children[i].image_name),
5663 'id' : decode_cstr(self.children[i].image_id),
5664 'trash' : self.children[i].trash
5665 }
5666
5667 def __dealloc__(self):
5668 if self.children:
5669 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
5670 free(self.children)
5671
5672 cdef class WatcherIterator(object):
5673 """
5674 Iterator over watchers of an image.
5675
5676 Yields a dictionary containing information about a watcher.
5677
5678 Keys are:
5679
5680 * ``addr`` (str) - address of the watcher
5681
5682 * ``id`` (int) - id of the watcher
5683
5684 * ``cookie`` (int) - the watcher's cookie
5685 """
5686
5687 cdef rbd_image_watcher_t *watchers
5688 cdef size_t num_watchers
5689 cdef object image
5690
5691 def __init__(self, Image image):
5692 self.image = image
5693 self.watchers = NULL
5694 self.num_watchers = 10
5695 while True:
5696 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
5697 self.num_watchers *
5698 sizeof(rbd_image_watcher_t))
5699 with nogil:
5700 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
5701 if ret >= 0:
5702 break
5703 elif ret != -errno.ERANGE:
5704 raise make_ex(ret, 'error listing watchers.')
5705
5706 def __iter__(self):
5707 for i in range(self.num_watchers):
5708 yield {
5709 'addr' : decode_cstr(self.watchers[i].addr),
5710 'id' : self.watchers[i].id,
5711 'cookie' : self.watchers[i].cookie
5712 }
5713
5714 def __dealloc__(self):
5715 if self.watchers:
5716 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
5717 free(self.watchers)
5718
5719 cdef class ConfigImageIterator(object):
5720 """
5721 Iterator over image-level overrides for an image.
5722
5723 Yields a dictionary containing information about an override.
5724
5725 Keys are:
5726
5727 * ``name`` (str) - override name
5728
5729 * ``value`` (str) - override value
5730
5731 * ``source`` (str) - override source
5732 """
5733
5734 cdef:
5735 rbd_config_option_t *options
5736 int num_options
5737
5738 def __init__(self, Image image):
5739 self.options = NULL
5740 self.num_options = 32
5741 while True:
5742 self.options = <rbd_config_option_t *>realloc_chk(
5743 self.options, self.num_options * sizeof(rbd_config_option_t))
5744 with nogil:
5745 ret = rbd_config_image_list(image.image, self.options,
5746 &self.num_options)
5747 if ret < 0:
5748 if ret == -errno.ERANGE:
5749 continue
5750 self.num_options = 0
5751 raise make_ex(ret, 'error listing config options')
5752 break
5753
5754 def __iter__(self):
5755 for i in range(self.num_options):
5756 yield {
5757 'name' : decode_cstr(self.options[i].name),
5758 'value' : decode_cstr(self.options[i].value),
5759 'source' : self.options[i].source,
5760 }
5761
5762 def __dealloc__(self):
5763 if self.options:
5764 rbd_config_image_list_cleanup(self.options, self.num_options)
5765 free(self.options)
5766
5767 cdef class GroupImageIterator(object):
5768 """
5769 Iterator over image info for a group.
5770
5771 Yields a dictionary containing information about an image.
5772
5773 Keys are:
5774
5775 * ``name`` (str) - name of the image
5776
5777 * ``pool`` (int) - id of the pool this image belongs to
5778
5779 * ``state`` (int) - state of the image
5780 """
5781
5782 cdef rbd_group_image_info_t *images
5783 cdef size_t num_images
5784 cdef object group
5785
5786 def __init__(self, Group group):
5787 self.group = group
5788 self.images = NULL
5789 self.num_images = 10
5790 while True:
5791 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
5792 self.num_images *
5793 sizeof(rbd_group_image_info_t))
5794 with nogil:
5795 ret = rbd_group_image_list(group._ioctx, group._name,
5796 self.images,
5797 sizeof(rbd_group_image_info_t),
5798 &self.num_images)
5799
5800 if ret >= 0:
5801 break
5802 elif ret != -errno.ERANGE:
5803 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
5804
5805 def __iter__(self):
5806 for i in range(self.num_images):
5807 yield {
5808 'name' : decode_cstr(self.images[i].name),
5809 'pool' : self.images[i].pool,
5810 'state' : self.images[i].state,
5811 }
5812
5813 def __dealloc__(self):
5814 if self.images:
5815 rbd_group_image_list_cleanup(self.images,
5816 sizeof(rbd_group_image_info_t),
5817 self.num_images)
5818 free(self.images)
5819
5820 cdef class GroupSnapIterator(object):
5821 """
5822 Iterator over snaps specs for a group.
5823
5824 Yields a dictionary containing information about a snapshot.
5825
5826 Keys are:
5827
5828 * ``name`` (str) - name of the snapshot
5829
5830 * ``state`` (int) - state of the snapshot
5831 """
5832
5833 cdef rbd_group_snap_info_t *snaps
5834 cdef size_t num_snaps
5835 cdef object group
5836
5837 def __init__(self, Group group):
5838 self.group = group
5839 self.snaps = NULL
5840 self.num_snaps = 10
5841 while True:
5842 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
5843 self.num_snaps *
5844 sizeof(rbd_group_snap_info_t))
5845 with nogil:
5846 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
5847 sizeof(rbd_group_snap_info_t),
5848 &self.num_snaps)
5849
5850 if ret >= 0:
5851 break
5852 elif ret != -errno.ERANGE:
5853 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
5854
5855 def __iter__(self):
5856 for i in range(self.num_snaps):
5857 yield {
5858 'name' : decode_cstr(self.snaps[i].name),
5859 'state' : self.snaps[i].state,
5860 }
5861
5862 def __dealloc__(self):
5863 if self.snaps:
5864 rbd_group_snap_list_cleanup(self.snaps,
5865 sizeof(rbd_group_snap_info_t),
5866 self.num_snaps)
5867 free(self.snaps)