]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/rbd/rbd.pyx
import 15.2.4
[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=False,
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 def requires_not_closed(f):
3296 def wrapper(self, *args, **kwargs):
3297 self.require_not_closed()
3298 return f(self, *args, **kwargs)
3299
3300 return wrapper
3301
3302 cdef class Image(object):
3303 """
3304 This class represents an RBD image. It is used to perform I/O on
3305 the image and interact with snapshots.
3306
3307 **Note**: Any method of this class may raise :class:`ImageNotFound`
3308 if the image has been deleted.
3309 """
3310 cdef rbd_image_t image
3311 cdef bint closed
3312 cdef object name
3313 cdef object ioctx
3314 cdef rados_ioctx_t _ioctx
3315
3316 def __init__(self, ioctx, name=None, snapshot=None,
3317 read_only=False, image_id=None):
3318 """
3319 Open the image at the given snapshot.
3320 Specify either name or id, otherwise :class:`InvalidArgument` is raised.
3321
3322 If a snapshot is specified, the image will be read-only, unless
3323 :func:`Image.set_snap` is called later.
3324
3325 If read-only mode is used, metadata for the :class:`Image`
3326 object (such as which snapshots exist) may become obsolete. See
3327 the C api for more details.
3328
3329 To clean up from opening the image, :func:`Image.close` should
3330 be called. For ease of use, this is done automatically when
3331 an :class:`Image` is used as a context manager (see :pep:`343`).
3332
3333 :param ioctx: determines which RADOS pool the image is in
3334 :type ioctx: :class:`rados.Ioctx`
3335 :param name: the name of the image
3336 :type name: str
3337 :param snapshot: which snapshot to read from
3338 :type snaphshot: str
3339 :param read_only: whether to open the image in read-only mode
3340 :type read_only: bool
3341 :param image_id: the id of the image
3342 :type image_id: str
3343 """
3344 name = cstr(name, 'name', opt=True)
3345 image_id = cstr(image_id, 'image_id', opt=True)
3346 snapshot = cstr(snapshot, 'snapshot', opt=True)
3347 self.closed = True
3348 if name is not None and image_id is not None:
3349 raise InvalidArgument("only need to specify image name or image id")
3350 elif name is None and image_id is None:
3351 raise InvalidArgument("image name or image id was not specified")
3352 elif name is not None:
3353 self.name = name
3354 else:
3355 self.name = image_id
3356 # Keep around a reference to the ioctx, so it won't get deleted
3357 self.ioctx = ioctx
3358 cdef:
3359 rados_ioctx_t _ioctx = convert_ioctx(ioctx)
3360 char *_name = opt_str(name)
3361 char *_image_id = opt_str(image_id)
3362 char *_snapshot = opt_str(snapshot)
3363 if read_only:
3364 with nogil:
3365 if name is not None:
3366 ret = rbd_open_read_only(_ioctx, _name, &self.image, _snapshot)
3367 else:
3368 ret = rbd_open_by_id_read_only(_ioctx, _image_id, &self.image, _snapshot)
3369 else:
3370 with nogil:
3371 if name is not None:
3372 ret = rbd_open(_ioctx, _name, &self.image, _snapshot)
3373 else:
3374 ret = rbd_open_by_id(_ioctx, _image_id, &self.image, _snapshot)
3375 if ret != 0:
3376 raise make_ex(ret, 'error opening image %s at snapshot %s' % (self.name, snapshot))
3377 self.closed = False
3378 if name is None:
3379 self.name = self.get_name()
3380
3381 def __enter__(self):
3382 return self
3383
3384 def __exit__(self, type_, value, traceback):
3385 """
3386 Closes the image. See :func:`close`
3387 """
3388 self.close()
3389 return False
3390
3391 def __get_completion(self, oncomplete):
3392 """
3393 Constructs a completion to use with asynchronous operations
3394
3395 :param oncomplete: callback for the completion
3396
3397 :raises: :class:`Error`
3398 :returns: completion object
3399 """
3400
3401 completion_obj = Completion(self, oncomplete)
3402
3403 cdef:
3404 rbd_completion_t completion
3405 PyObject* p_completion_obj= <PyObject*>completion_obj
3406
3407 with nogil:
3408 ret = rbd_aio_create_completion(p_completion_obj, __aio_complete_cb,
3409 &completion)
3410 if ret < 0:
3411 raise make_ex(ret, "error getting a completion")
3412
3413 completion_obj.rbd_comp = completion
3414 return completion_obj
3415
3416 def require_not_closed(self):
3417 """
3418 Checks if the Image is not closed
3419
3420 :raises: :class:`InvalidArgument`
3421 """
3422 if self.closed:
3423 raise InvalidArgument("image is closed")
3424
3425 def close(self):
3426 """
3427 Release the resources used by this image object.
3428
3429 After this is called, this object should not be used.
3430 """
3431 if not self.closed:
3432 self.closed = True
3433 with nogil:
3434 ret = rbd_close(self.image)
3435 if ret < 0:
3436 raise make_ex(ret, 'error while closing image %s' % (
3437 self.name,))
3438
3439 def __dealloc__(self):
3440 self.close()
3441
3442 def __repr__(self):
3443 return "rbd.Image(ioctx, %r)" % self.name
3444
3445 @requires_not_closed
3446 def resize(self, size, allow_shrink=True):
3447 """
3448 Change the size of the image, allow shrink.
3449
3450 :param size: the new size of the image
3451 :type size: int
3452 :param allow_shrink: permit shrinking
3453 :type allow_shrink: bool
3454 """
3455 old_size = self.size()
3456 if old_size == size:
3457 return
3458 if not allow_shrink and old_size > size:
3459 raise InvalidArgument("error allow_shrink is False but old_size > new_size")
3460 cdef:
3461 uint64_t _size = size
3462 bint _allow_shrink = allow_shrink
3463 librbd_progress_fn_t prog_cb = &no_op_progress_callback
3464 with nogil:
3465 ret = rbd_resize2(self.image, _size, _allow_shrink, prog_cb, NULL)
3466 if ret < 0:
3467 raise make_ex(ret, 'error resizing image %s' % self.name)
3468
3469 @requires_not_closed
3470 def stat(self):
3471 """
3472 Get information about the image. Currently parent pool and
3473 parent name are always -1 and ''.
3474
3475 :returns: dict - contains the following keys:
3476
3477 * ``size`` (int) - the size of the image in bytes
3478
3479 * ``obj_size`` (int) - the size of each object that comprises the
3480 image
3481
3482 * ``num_objs`` (int) - the number of objects in the image
3483
3484 * ``order`` (int) - log_2(object_size)
3485
3486 * ``block_name_prefix`` (str) - the prefix of the RADOS objects used
3487 to store the image
3488
3489 * ``parent_pool`` (int) - deprecated
3490
3491 * ``parent_name`` (str) - deprecated
3492
3493 See also :meth:`format` and :meth:`features`.
3494
3495 """
3496 cdef rbd_image_info_t info
3497 with nogil:
3498 ret = rbd_stat(self.image, &info, sizeof(info))
3499 if ret != 0:
3500 raise make_ex(ret, 'error getting info for image %s' % self.name)
3501 return {
3502 'size' : info.size,
3503 'obj_size' : info.obj_size,
3504 'num_objs' : info.num_objs,
3505 'order' : info.order,
3506 'block_name_prefix' : decode_cstr(info.block_name_prefix),
3507 'parent_pool' : info.parent_pool,
3508 'parent_name' : info.parent_name
3509 }
3510
3511 @requires_not_closed
3512 def get_name(self):
3513 """
3514 Get the RBD image name
3515
3516 :returns: str - image name
3517 """
3518 cdef:
3519 int ret = -errno.ERANGE
3520 size_t size = 64
3521 char *image_name = NULL
3522 try:
3523 while ret == -errno.ERANGE:
3524 image_name = <char *>realloc_chk(image_name, size)
3525 with nogil:
3526 ret = rbd_get_name(self.image, image_name, &size)
3527
3528 if ret != 0:
3529 raise make_ex(ret, 'error getting name for image %s' % self.name)
3530 return decode_cstr(image_name)
3531 finally:
3532 free(image_name)
3533
3534 @requires_not_closed
3535 def id(self):
3536 """
3537 Get the RBD v2 internal image id
3538
3539 :returns: str - image id
3540 """
3541 cdef:
3542 int ret = -errno.ERANGE
3543 size_t size = 32
3544 char *image_id = NULL
3545 try:
3546 while ret == -errno.ERANGE and size <= 4096:
3547 image_id = <char *>realloc_chk(image_id, size)
3548 with nogil:
3549 ret = rbd_get_id(self.image, image_id, size)
3550 if ret == -errno.ERANGE:
3551 size *= 2
3552
3553 if ret != 0:
3554 raise make_ex(ret, 'error getting id for image %s' % self.name)
3555 return decode_cstr(image_id)
3556 finally:
3557 free(image_id)
3558
3559 @requires_not_closed
3560 def block_name_prefix(self):
3561 """
3562 Get the RBD block name prefix
3563
3564 :returns: str - block name prefix
3565 """
3566 cdef:
3567 int ret = -errno.ERANGE
3568 size_t size = 32
3569 char *prefix = NULL
3570 try:
3571 while ret == -errno.ERANGE and size <= 4096:
3572 prefix = <char *>realloc_chk(prefix, size)
3573 with nogil:
3574 ret = rbd_get_block_name_prefix(self.image, prefix, size)
3575 if ret == -errno.ERANGE:
3576 size *= 2
3577
3578 if ret != 0:
3579 raise make_ex(ret, 'error getting block name prefix for image %s' % self.name)
3580 return decode_cstr(prefix)
3581 finally:
3582 free(prefix)
3583
3584 @requires_not_closed
3585 def data_pool_id(self):
3586 """
3587 Get the pool id of the pool where the data of this RBD image is stored.
3588
3589 :returns: int - the pool id
3590 """
3591 return rbd_get_data_pool_id(self.image)
3592
3593 @requires_not_closed
3594 def get_parent_image_spec(self):
3595 """
3596 Get spec of the cloned image's parent
3597
3598 :returns: dict - contains the following keys:
3599 * ``pool_name`` (str) - parent pool name
3600 * ``pool_namespace`` (str) - parent pool namespace
3601 * ``image_name`` (str) - parent image name
3602 * ``snap_name`` (str) - parent snapshot name
3603
3604 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3605 """
3606 cdef:
3607 rbd_linked_image_spec_t parent_spec
3608 rbd_snap_spec_t snap_spec
3609 with nogil:
3610 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3611 if ret != 0:
3612 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3613
3614 result = {'pool_name': decode_cstr(parent_spec.pool_name),
3615 'pool_namespace': decode_cstr(parent_spec.pool_namespace),
3616 'image_name': decode_cstr(parent_spec.image_name),
3617 'snap_name': decode_cstr(snap_spec.name)}
3618
3619 rbd_linked_image_spec_cleanup(&parent_spec)
3620 rbd_snap_spec_cleanup(&snap_spec)
3621 return result
3622
3623 @requires_not_closed
3624 def parent_info(self):
3625 """
3626 Deprecated. Use `get_parent_image_spec` instead.
3627
3628 Get information about a cloned image's parent (if any)
3629
3630 :returns: tuple - ``(pool name, image name, snapshot name)`` components
3631 of the parent image
3632 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3633 """
3634 parent = self.get_parent_image_spec()
3635 return (parent['pool_name'], parent['image_name'], parent['snap_name'])
3636
3637 @requires_not_closed
3638 def parent_id(self):
3639 """
3640 Get image id of a cloned image's parent (if any)
3641
3642 :returns: str - the parent id
3643 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3644 """
3645 cdef:
3646 rbd_linked_image_spec_t parent_spec
3647 rbd_snap_spec_t snap_spec
3648 with nogil:
3649 ret = rbd_get_parent(self.image, &parent_spec, &snap_spec)
3650 if ret != 0:
3651 raise make_ex(ret, 'error getting parent info for image %s' % self.name)
3652
3653 result = decode_cstr(parent_spec.image_id)
3654
3655 rbd_linked_image_spec_cleanup(&parent_spec)
3656 rbd_snap_spec_cleanup(&snap_spec)
3657 return result
3658
3659 @requires_not_closed
3660 def old_format(self):
3661 """
3662 Find out whether the image uses the old RBD format.
3663
3664 :returns: bool - whether the image uses the old RBD format
3665 """
3666 cdef uint8_t old
3667 with nogil:
3668 ret = rbd_get_old_format(self.image, &old)
3669 if ret != 0:
3670 raise make_ex(ret, 'error getting old_format for image %s' % (self.name))
3671 return old != 0
3672
3673 @requires_not_closed
3674 def size(self):
3675 """
3676 Get the size of the image. If open to a snapshot, returns the
3677 size of that snapshot.
3678
3679 :returns: int - the size of the image in bytes
3680 """
3681 cdef uint64_t image_size
3682 with nogil:
3683 ret = rbd_get_size(self.image, &image_size)
3684 if ret != 0:
3685 raise make_ex(ret, 'error getting size for image %s' % (self.name))
3686 return image_size
3687
3688 @requires_not_closed
3689 def features(self):
3690 """
3691 Get the features bitmask of the image.
3692
3693 :returns: int - the features bitmask of the image
3694 """
3695 cdef uint64_t features
3696 with nogil:
3697 ret = rbd_get_features(self.image, &features)
3698 if ret != 0:
3699 raise make_ex(ret, 'error getting features for image %s' % (self.name))
3700 return features
3701
3702 @requires_not_closed
3703 def update_features(self, features, enabled):
3704 """
3705 Update the features bitmask of the image by enabling/disabling
3706 a single feature. The feature must support the ability to be
3707 dynamically enabled/disabled.
3708
3709 :param features: feature bitmask to enable/disable
3710 :type features: int
3711 :param enabled: whether to enable/disable the feature
3712 :type enabled: bool
3713 :raises: :class:`InvalidArgument`
3714 """
3715 cdef:
3716 uint64_t _features = features
3717 uint8_t _enabled = bool(enabled)
3718 with nogil:
3719 ret = rbd_update_features(self.image, _features, _enabled)
3720 if ret != 0:
3721 raise make_ex(ret, 'error updating features for image %s' %
3722 (self.name))
3723
3724 @requires_not_closed
3725 def op_features(self):
3726 """
3727 Get the op features bitmask of the image.
3728
3729 :returns: int - the op features bitmask of the image
3730 """
3731 cdef uint64_t op_features
3732 with nogil:
3733 ret = rbd_get_op_features(self.image, &op_features)
3734 if ret != 0:
3735 raise make_ex(ret, 'error getting op features for image %s' % (self.name))
3736 return op_features
3737
3738 @requires_not_closed
3739 def overlap(self):
3740 """
3741 Get the number of overlapping bytes between the image and its parent
3742 image. If open to a snapshot, returns the overlap between the snapshot
3743 and the parent image.
3744
3745 :returns: int - the overlap in bytes
3746 :raises: :class:`ImageNotFound` if the image doesn't have a parent
3747 """
3748 cdef uint64_t overlap
3749 with nogil:
3750 ret = rbd_get_overlap(self.image, &overlap)
3751 if ret != 0:
3752 raise make_ex(ret, 'error getting overlap for image %s' % (self.name))
3753 return overlap
3754
3755 @requires_not_closed
3756 def flags(self):
3757 """
3758 Get the flags bitmask of the image.
3759
3760 :returns: int - the flags bitmask of the image
3761 """
3762 cdef uint64_t flags
3763 with nogil:
3764 ret = rbd_get_flags(self.image, &flags)
3765 if ret != 0:
3766 raise make_ex(ret, 'error getting flags for image %s' % (self.name))
3767 return flags
3768
3769 @requires_not_closed
3770 def group(self):
3771 """
3772 Get information about the image's group.
3773
3774 :returns: dict - contains the following keys:
3775
3776 * ``pool`` (int) - id of the group pool
3777
3778 * ``name`` (str) - name of the group
3779
3780 """
3781 cdef rbd_group_info_t info
3782 with nogil:
3783 ret = rbd_get_group(self.image, &info, sizeof(info))
3784 if ret != 0:
3785 raise make_ex(ret, 'error getting group for image %s' % self.name)
3786 result = {
3787 'pool' : info.pool,
3788 'name' : decode_cstr(info.name)
3789 }
3790 rbd_group_info_cleanup(&info, sizeof(info))
3791 return result
3792
3793 @requires_not_closed
3794 def is_exclusive_lock_owner(self):
3795 """
3796 Get the status of the image exclusive lock.
3797
3798 :returns: bool - true if the image is exclusively locked
3799 """
3800 cdef int owner
3801 with nogil:
3802 ret = rbd_is_exclusive_lock_owner(self.image, &owner)
3803 if ret != 0:
3804 raise make_ex(ret, 'error getting lock status for image %s' % (self.name))
3805 return owner == 1
3806
3807 @requires_not_closed
3808 def copy(self, dest_ioctx, dest_name, features=None, order=None,
3809 stripe_unit=None, stripe_count=None, data_pool=None):
3810 """
3811 Copy the image to another location.
3812
3813 :param dest_ioctx: determines which pool to copy into
3814 :type dest_ioctx: :class:`rados.Ioctx`
3815 :param dest_name: the name of the copy
3816 :type dest_name: str
3817 :param features: bitmask of features to enable; if set, must include layering
3818 :type features: int
3819 :param order: the image is split into (2**order) byte objects
3820 :type order: int
3821 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3822 :type stripe_unit: int
3823 :param stripe_count: objects to stripe over before looping
3824 :type stripe_count: int
3825 :param data_pool: optional separate pool for data blocks
3826 :type data_pool: str
3827 :raises: :class:`TypeError`
3828 :raises: :class:`InvalidArgument`
3829 :raises: :class:`ImageExists`
3830 :raises: :class:`FunctionNotSupported`
3831 :raises: :class:`ArgumentOutOfRange`
3832 """
3833 dest_name = cstr(dest_name, 'dest_name')
3834 data_pool = cstr(data_pool, 'data_pool', opt=True)
3835 cdef:
3836 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3837 char *_dest_name = dest_name
3838 rbd_image_options_t opts
3839
3840 rbd_image_options_create(&opts)
3841 try:
3842 if features is not None:
3843 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3844 features)
3845 if order is not None:
3846 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3847 order)
3848 if stripe_unit is not None:
3849 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3850 stripe_unit)
3851 if stripe_count is not None:
3852 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3853 stripe_count)
3854 if data_pool is not None:
3855 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3856 data_pool)
3857 with nogil:
3858 ret = rbd_copy3(self.image, _dest_ioctx, _dest_name, opts)
3859 finally:
3860 rbd_image_options_destroy(opts)
3861 if ret < 0:
3862 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3863
3864 @requires_not_closed
3865 def deep_copy(self, dest_ioctx, dest_name, features=None, order=None,
3866 stripe_unit=None, stripe_count=None, data_pool=None):
3867 """
3868 Deep copy the image to another location.
3869
3870 :param dest_ioctx: determines which pool to copy into
3871 :type dest_ioctx: :class:`rados.Ioctx`
3872 :param dest_name: the name of the copy
3873 :type dest_name: str
3874 :param features: bitmask of features to enable; if set, must include layering
3875 :type features: int
3876 :param order: the image is split into (2**order) byte objects
3877 :type order: int
3878 :param stripe_unit: stripe unit in bytes (default None to let librbd decide)
3879 :type stripe_unit: int
3880 :param stripe_count: objects to stripe over before looping
3881 :type stripe_count: int
3882 :param data_pool: optional separate pool for data blocks
3883 :type data_pool: str
3884 :raises: :class:`TypeError`
3885 :raises: :class:`InvalidArgument`
3886 :raises: :class:`ImageExists`
3887 :raises: :class:`FunctionNotSupported`
3888 :raises: :class:`ArgumentOutOfRange`
3889 """
3890 dest_name = cstr(dest_name, 'dest_name')
3891 data_pool = cstr(data_pool, 'data_pool', opt=True)
3892 cdef:
3893 rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
3894 char *_dest_name = dest_name
3895 rbd_image_options_t opts
3896
3897 rbd_image_options_create(&opts)
3898 try:
3899 if features is not None:
3900 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
3901 features)
3902 if order is not None:
3903 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
3904 order)
3905 if stripe_unit is not None:
3906 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
3907 stripe_unit)
3908 if stripe_count is not None:
3909 rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
3910 stripe_count)
3911 if data_pool is not None:
3912 rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
3913 data_pool)
3914 with nogil:
3915 ret = rbd_deep_copy(self.image, _dest_ioctx, _dest_name, opts)
3916 finally:
3917 rbd_image_options_destroy(opts)
3918 if ret < 0:
3919 raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
3920
3921 @requires_not_closed
3922 def list_snaps(self):
3923 """
3924 Iterate over the snapshots of an image.
3925
3926 :returns: :class:`SnapIterator`
3927 """
3928 return SnapIterator(self)
3929
3930 @requires_not_closed
3931 def create_snap(self, name):
3932 """
3933 Create a snapshot of the image.
3934
3935 :param name: the name of the snapshot
3936 :type name: str
3937 :raises: :class:`ImageExists`
3938 """
3939 name = cstr(name, 'name')
3940 cdef char *_name = name
3941 with nogil:
3942 ret = rbd_snap_create(self.image, _name)
3943 if ret != 0:
3944 raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name))
3945
3946 @requires_not_closed
3947 def rename_snap(self, srcname, dstname):
3948 """
3949 rename a snapshot of the image.
3950
3951 :param srcname: the src name of the snapshot
3952 :type srcname: str
3953 :param dstname: the dst name of the snapshot
3954 :type dstname: str
3955 :raises: :class:`ImageExists`
3956 """
3957 srcname = cstr(srcname, 'srcname')
3958 dstname = cstr(dstname, 'dstname')
3959 cdef:
3960 char *_srcname = srcname
3961 char *_dstname = dstname
3962 with nogil:
3963 ret = rbd_snap_rename(self.image, _srcname, _dstname)
3964 if ret != 0:
3965 raise make_ex(ret, 'error renaming snapshot of %s from %s to %s' % (self.name, srcname, dstname))
3966
3967 @requires_not_closed
3968 def remove_snap(self, name):
3969 """
3970 Delete a snapshot of the image.
3971
3972 :param name: the name of the snapshot
3973 :type name: str
3974 :raises: :class:`IOError`, :class:`ImageBusy`, :class:`ImageNotFound`
3975 """
3976 name = cstr(name, 'name')
3977 cdef char *_name = name
3978 with nogil:
3979 ret = rbd_snap_remove(self.image, _name)
3980 if ret != 0:
3981 raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name))
3982
3983 @requires_not_closed
3984 def remove_snap2(self, name, flags):
3985 """
3986 Delete a snapshot of the image.
3987
3988 :param name: the name of the snapshot
3989 :param flags: the flags for removal
3990 :type name: str
3991 :raises: :class:`IOError`, :class:`ImageBusy`
3992 """
3993 self.require_not_closed()
3994
3995 name = cstr(name, 'name')
3996 cdef:
3997 char *_name = name
3998 uint32_t _flags = flags
3999 librbd_progress_fn_t prog_cb = &no_op_progress_callback
4000 with nogil:
4001 ret = rbd_snap_remove2(self.image, _name, _flags, prog_cb, NULL)
4002 if ret != 0:
4003 raise make_ex(ret, 'error removing snapshot %s from %s with flags %lx' % (name, self.name, flags))
4004
4005 @requires_not_closed
4006 def remove_snap_by_id(self, snap_id):
4007 """
4008 Delete a snapshot of the image by its id.
4009
4010 :param id: the id of the snapshot
4011 :type name: int
4012 :raises: :class:`IOError`, :class:`ImageBusy`
4013 """
4014 cdef:
4015 uint64_t _snap_id = snap_id
4016 with nogil:
4017 ret = rbd_snap_remove_by_id(self.image, _snap_id)
4018 if ret != 0:
4019 raise make_ex(ret, 'error removing snapshot %s from %s' % (snap_id, self.name))
4020
4021 @requires_not_closed
4022 def rollback_to_snap(self, name):
4023 """
4024 Revert the image to its contents at a snapshot. This is a
4025 potentially expensive operation, since it rolls back each
4026 object individually.
4027
4028 :param name: the snapshot to rollback to
4029 :type name: str
4030 :raises: :class:`IOError`
4031 """
4032 name = cstr(name, 'name')
4033 cdef char *_name = name
4034 with nogil:
4035 ret = rbd_snap_rollback(self.image, _name)
4036 if ret != 0:
4037 raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name))
4038
4039 @requires_not_closed
4040 def protect_snap(self, name):
4041 """
4042 Mark a snapshot as protected. This means it can't be deleted
4043 until it is unprotected.
4044
4045 :param name: the snapshot to protect
4046 :type name: str
4047 :raises: :class:`IOError`, :class:`ImageNotFound`
4048 """
4049 name = cstr(name, 'name')
4050 cdef char *_name = name
4051 with nogil:
4052 ret = rbd_snap_protect(self.image, _name)
4053 if ret != 0:
4054 raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name))
4055
4056 @requires_not_closed
4057 def unprotect_snap(self, name):
4058 """
4059 Mark a snapshot unprotected. This allows it to be deleted if
4060 it was protected.
4061
4062 :param name: the snapshot to unprotect
4063 :type name: str
4064 :raises: :class:`IOError`, :class:`ImageNotFound`
4065 """
4066 name = cstr(name, 'name')
4067 cdef char *_name = name
4068 with nogil:
4069 ret = rbd_snap_unprotect(self.image, _name)
4070 if ret != 0:
4071 raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name))
4072
4073 @requires_not_closed
4074 def is_protected_snap(self, name):
4075 """
4076 Find out whether a snapshot is protected from deletion.
4077
4078 :param name: the snapshot to check
4079 :type name: str
4080 :returns: bool - whether the snapshot is protected
4081 :raises: :class:`IOError`, :class:`ImageNotFound`
4082 """
4083 name = cstr(name, 'name')
4084 cdef:
4085 char *_name = name
4086 int is_protected
4087 with nogil:
4088 ret = rbd_snap_is_protected(self.image, _name, &is_protected)
4089 if ret != 0:
4090 raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name))
4091 return is_protected == 1
4092
4093 @requires_not_closed
4094 def snap_exists(self, name):
4095 """
4096 Find out whether a snapshot is exists.
4097
4098 :param name: the snapshot to check
4099 :type name: str
4100 :returns: bool - whether the snapshot is exists
4101 """
4102 name = cstr(name, 'name')
4103 cdef:
4104 char *_name = name
4105 bint _exists = False
4106 with nogil:
4107 ret = rbd_snap_exists(self.image, _name, &_exists)
4108 if ret != 0:
4109 raise make_ex(ret, 'error getting snapshot exists for %s' % self.name)
4110 return bool(_exists != 0)
4111
4112 @requires_not_closed
4113 def get_snap_limit(self):
4114 """
4115 Get the snapshot limit for an image.
4116
4117 :returns: int - the snapshot limit for an image
4118 """
4119 cdef:
4120 uint64_t limit
4121 with nogil:
4122 ret = rbd_snap_get_limit(self.image, &limit)
4123 if ret != 0:
4124 raise make_ex(ret, 'error getting snapshot limit for %s' % self.name)
4125 return limit
4126
4127 @requires_not_closed
4128 def set_snap_limit(self, limit):
4129 """
4130 Set the snapshot limit for an image.
4131
4132 :param limit: the new limit to set
4133 """
4134 cdef:
4135 uint64_t _limit = limit
4136 with nogil:
4137 ret = rbd_snap_set_limit(self.image, _limit)
4138 if ret != 0:
4139 raise make_ex(ret, 'error setting snapshot limit for %s' % self.name)
4140 return ret
4141
4142 @requires_not_closed
4143 def get_snap_timestamp(self, snap_id):
4144 """
4145 Get the snapshot timestamp for an image.
4146 :param snap_id: the snapshot id of a snap shot
4147 :returns: datetime - the snapshot timestamp for an image
4148 """
4149 cdef:
4150 timespec timestamp
4151 uint64_t _snap_id = snap_id
4152 with nogil:
4153 ret = rbd_snap_get_timestamp(self.image, _snap_id, &timestamp)
4154 if ret != 0:
4155 raise make_ex(ret, 'error getting snapshot timestamp for image: %s, snap_id: %d' % (self.name, snap_id))
4156 return datetime.utcfromtimestamp(timestamp.tv_sec)
4157
4158 @requires_not_closed
4159 def remove_snap_limit(self):
4160 """
4161 Remove the snapshot limit for an image, essentially setting
4162 the limit to the maximum size allowed by the implementation.
4163 """
4164 with nogil:
4165 ret = rbd_snap_set_limit(self.image, UINT64_MAX)
4166 if ret != 0:
4167 raise make_ex(ret, 'error removing snapshot limit for %s' % self.name)
4168 return ret
4169
4170 @requires_not_closed
4171 def set_snap(self, name):
4172 """
4173 Set the snapshot to read from. Writes will raise ReadOnlyImage
4174 while a snapshot is set. Pass None to unset the snapshot
4175 (reads come from the current image) , and allow writing again.
4176
4177 :param name: the snapshot to read from, or None to unset the snapshot
4178 :type name: str or None
4179 """
4180 name = cstr(name, 'name', opt=True)
4181 cdef char *_name = opt_str(name)
4182 with nogil:
4183 ret = rbd_snap_set(self.image, _name)
4184 if ret != 0:
4185 raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name))
4186
4187 @requires_not_closed
4188 def set_snap_by_id(self, snap_id):
4189 """
4190 Set the snapshot to read from. Writes will raise ReadOnlyImage
4191 while a snapshot is set. Pass None to unset the snapshot
4192 (reads come from the current image) , and allow writing again.
4193
4194 :param snap_id: the snapshot to read from, or None to unset the snapshot
4195 :type snap_id: int
4196 """
4197 if not snap_id:
4198 snap_id = _LIBRADOS_SNAP_HEAD
4199 cdef int64_t _snap_id = snap_id
4200 with nogil:
4201 ret = rbd_snap_set_by_id(self.image, _snap_id)
4202 if ret != 0:
4203 raise make_ex(ret, 'error setting image %s to snapshot %d' % (self.name, snap_id))
4204
4205 @requires_not_closed
4206 def snap_get_name(self, snap_id):
4207 """
4208 Get snapshot name by id.
4209
4210 :param snap_id: the snapshot id
4211 :type snap_id: int
4212 :returns: str - snapshot name
4213 :raises: :class:`ImageNotFound`
4214 """
4215 cdef:
4216 int ret = -errno.ERANGE
4217 int64_t _snap_id = snap_id
4218 size_t size = 512
4219 char *image_name = NULL
4220 try:
4221 while ret == -errno.ERANGE:
4222 image_name = <char *>realloc_chk(image_name, size)
4223 with nogil:
4224 ret = rbd_snap_get_name(self.image, _snap_id, image_name, &size)
4225
4226 if ret != 0:
4227 raise make_ex(ret, 'error snap_get_name.')
4228 return decode_cstr(image_name)
4229 finally:
4230 free(image_name)
4231
4232 @requires_not_closed
4233 def snap_get_id(self, snap_name):
4234 """
4235 Get snapshot id by name.
4236
4237 :param snap_name: the snapshot name
4238 :type snap_name: str
4239 :returns: int - snapshot id
4240 :raises: :class:`ImageNotFound`
4241 """
4242 snap_name = cstr(snap_name, 'snap_name')
4243 cdef:
4244 const char *_snap_name = snap_name
4245 uint64_t snap_id
4246 with nogil:
4247 ret = rbd_snap_get_id(self.image, _snap_name, &snap_id)
4248 if ret != 0:
4249 raise make_ex(ret, 'error snap_get_id.')
4250 return snap_id
4251
4252 @requires_not_closed
4253 def read(self, offset, length, fadvise_flags=0):
4254 """
4255 Read data from the image. Raises :class:`InvalidArgument` if
4256 part of the range specified is outside the image.
4257
4258 :param offset: the offset to start reading at
4259 :type offset: int
4260 :param length: how many bytes to read
4261 :type length: int
4262 :param fadvise_flags: fadvise flags for this read
4263 :type fadvise_flags: int
4264 :returns: str - the data read
4265 :raises: :class:`InvalidArgument`, :class:`IOError`
4266 """
4267
4268 # This usage of the Python API allows us to construct a string
4269 # that librbd directly reads into, avoiding an extra copy. Although
4270 # strings are normally immutable, this usage is explicitly supported
4271 # for freshly created string objects.
4272 cdef:
4273 char *ret_buf
4274 uint64_t _offset = offset
4275 size_t _length = length
4276 int _fadvise_flags = fadvise_flags
4277 PyObject* ret_s = NULL
4278 ret_s = PyBytes_FromStringAndSize(NULL, length)
4279 try:
4280 ret_buf = PyBytes_AsString(ret_s)
4281 with nogil:
4282 ret = rbd_read2(self.image, _offset, _length, ret_buf,
4283 _fadvise_flags)
4284 if ret < 0:
4285 raise make_ex(ret, 'error reading %s %ld~%ld' % (self.name, offset, length))
4286
4287 if ret != <ssize_t>length:
4288 _PyBytes_Resize(&ret_s, ret)
4289
4290 return <object>ret_s
4291 finally:
4292 # We DECREF unconditionally: the cast to object above will have
4293 # INCREFed if necessary. This also takes care of exceptions,
4294 # including if _PyString_Resize fails (that will free the string
4295 # itself and set ret_s to NULL, hence XDECREF).
4296 ref.Py_XDECREF(ret_s)
4297
4298 @requires_not_closed
4299 def diff_iterate(self, offset, length, from_snapshot, iterate_cb,
4300 include_parent = True, whole_object = False):
4301 """
4302 Iterate over the changed extents of an image.
4303
4304 This will call iterate_cb with three arguments:
4305
4306 (offset, length, exists)
4307
4308 where the changed extent starts at offset bytes, continues for
4309 length bytes, and is full of data (if exists is True) or zeroes
4310 (if exists is False).
4311
4312 If from_snapshot is None, it is interpreted as the beginning
4313 of time and this generates all allocated extents.
4314
4315 The end version is whatever is currently selected (via set_snap)
4316 for the image.
4317
4318 iterate_cb may raise an exception, which will abort the diff and will be
4319 propagated to the caller.
4320
4321 Raises :class:`InvalidArgument` if from_snapshot is after
4322 the currently set snapshot.
4323
4324 Raises :class:`ImageNotFound` if from_snapshot is not the name
4325 of a snapshot of the image.
4326
4327 :param offset: start offset in bytes
4328 :type offset: int
4329 :param length: size of region to report on, in bytes
4330 :type length: int
4331 :param from_snapshot: starting snapshot name, or None
4332 :type from_snapshot: str or None
4333 :param iterate_cb: function to call for each extent
4334 :type iterate_cb: function acception arguments for offset,
4335 length, and exists
4336 :param include_parent: True if full history diff should include parent
4337 :type include_parent: bool
4338 :param whole_object: True if diff extents should cover whole object
4339 :type whole_object: bool
4340 :raises: :class:`InvalidArgument`, :class:`IOError`,
4341 :class:`ImageNotFound`
4342 """
4343 from_snapshot = cstr(from_snapshot, 'from_snapshot', opt=True)
4344 cdef:
4345 char *_from_snapshot = opt_str(from_snapshot)
4346 uint64_t _offset = offset, _length = length
4347 uint8_t _include_parent = include_parent
4348 uint8_t _whole_object = whole_object
4349 with nogil:
4350 ret = rbd_diff_iterate2(self.image, _from_snapshot, _offset,
4351 _length, _include_parent, _whole_object,
4352 &diff_iterate_cb, <void *>iterate_cb)
4353 if ret < 0:
4354 msg = 'error generating diff from snapshot %s' % from_snapshot
4355 raise make_ex(ret, msg)
4356
4357 @requires_not_closed
4358 def write(self, data, offset, fadvise_flags=0):
4359 """
4360 Write data to the image. Raises :class:`InvalidArgument` if
4361 part of the write would fall outside the image.
4362
4363 :param data: the data to be written
4364 :type data: bytes
4365 :param offset: where to start writing data
4366 :type offset: int
4367 :param fadvise_flags: fadvise flags for this write
4368 :type fadvise_flags: int
4369 :returns: int - the number of bytes written
4370 :raises: :class:`IncompleteWriteError`, :class:`LogicError`,
4371 :class:`InvalidArgument`, :class:`IOError`
4372 """
4373 if not isinstance(data, bytes):
4374 raise TypeError('data must be a byte string')
4375 cdef:
4376 uint64_t _offset = offset, length = len(data)
4377 char *_data = data
4378 int _fadvise_flags = fadvise_flags
4379 with nogil:
4380 ret = rbd_write2(self.image, _offset, length, _data, _fadvise_flags)
4381
4382 if ret == <ssize_t>length:
4383 return ret
4384 elif ret < 0:
4385 raise make_ex(ret, "error writing to %s" % self.name)
4386 elif ret < <ssize_t>length:
4387 raise IncompleteWriteError("Wrote only %ld out of %ld bytes" % (ret, length))
4388 else:
4389 raise LogicError("logic error: rbd_write(%s) \
4390 returned %d, but %d was the maximum number of bytes it could have \
4391 written." % (self.name, ret, length))
4392
4393 @requires_not_closed
4394 def discard(self, offset, length):
4395 """
4396 Trim the range from the image. It will be logically filled
4397 with zeroes.
4398 """
4399 cdef uint64_t _offset = offset, _length = length
4400 with nogil:
4401 ret = rbd_discard(self.image, _offset, _length)
4402 if ret < 0:
4403 msg = 'error discarding region %d~%d' % (offset, length)
4404 raise make_ex(ret, msg)
4405
4406 @requires_not_closed
4407 def flush(self):
4408 """
4409 Block until all writes are fully flushed if caching is enabled.
4410 """
4411 with nogil:
4412 ret = rbd_flush(self.image)
4413 if ret < 0:
4414 raise make_ex(ret, 'error flushing image')
4415
4416 @requires_not_closed
4417 def invalidate_cache(self):
4418 """
4419 Drop any cached data for the image.
4420 """
4421 with nogil:
4422 ret = rbd_invalidate_cache(self.image)
4423 if ret < 0:
4424 raise make_ex(ret, 'error invalidating cache')
4425
4426 @requires_not_closed
4427 def stripe_unit(self):
4428 """
4429 Return the stripe unit used for the image.
4430 """
4431 cdef uint64_t stripe_unit
4432 with nogil:
4433 ret = rbd_get_stripe_unit(self.image, &stripe_unit)
4434 if ret != 0:
4435 raise make_ex(ret, 'error getting stripe unit for image %s' % (self.name))
4436 return stripe_unit
4437
4438 @requires_not_closed
4439 def stripe_count(self):
4440 """
4441 Return the stripe count used for the image.
4442 """
4443 cdef uint64_t stripe_count
4444 with nogil:
4445 ret = rbd_get_stripe_count(self.image, &stripe_count)
4446 if ret != 0:
4447 raise make_ex(ret, 'error getting stripe count for image %s' % (self.name))
4448 return stripe_count
4449
4450 @requires_not_closed
4451 def create_timestamp(self):
4452 """
4453 Return the create timestamp for the image.
4454 """
4455 cdef:
4456 timespec timestamp
4457 with nogil:
4458 ret = rbd_get_create_timestamp(self.image, &timestamp)
4459 if ret != 0:
4460 raise make_ex(ret, 'error getting create timestamp for image: %s' % (self.name))
4461 return datetime.utcfromtimestamp(timestamp.tv_sec)
4462
4463 @requires_not_closed
4464 def access_timestamp(self):
4465 """
4466 Return the access timestamp for the image.
4467 """
4468 cdef:
4469 timespec timestamp
4470 with nogil:
4471 ret = rbd_get_access_timestamp(self.image, &timestamp)
4472 if ret != 0:
4473 raise make_ex(ret, 'error getting access timestamp for image: %s' % (self.name))
4474 return datetime.fromtimestamp(timestamp.tv_sec)
4475
4476 @requires_not_closed
4477 def modify_timestamp(self):
4478 """
4479 Return the modify timestamp for the image.
4480 """
4481 cdef:
4482 timespec timestamp
4483 with nogil:
4484 ret = rbd_get_modify_timestamp(self.image, &timestamp)
4485 if ret != 0:
4486 raise make_ex(ret, 'error getting modify timestamp for image: %s' % (self.name))
4487 return datetime.fromtimestamp(timestamp.tv_sec)
4488
4489 @requires_not_closed
4490 def flatten(self, on_progress=None):
4491 """
4492 Flatten clone image (copy all blocks from parent to child)
4493 :param on_progress: optional progress callback function
4494 :type on_progress: callback function
4495 """
4496 cdef:
4497 librbd_progress_fn_t _prog_cb = &no_op_progress_callback
4498 void *_prog_arg = NULL
4499 if on_progress:
4500 _prog_cb = &progress_callback
4501 _prog_arg = <void *>on_progress
4502 with nogil:
4503 ret = rbd_flatten_with_progress(self.image, _prog_cb, _prog_arg)
4504 if ret < 0:
4505 raise make_ex(ret, "error flattening %s" % self.name)
4506
4507 @requires_not_closed
4508 def sparsify(self, sparse_size):
4509 """
4510 Reclaim space for zeroed image extents
4511 """
4512 cdef:
4513 size_t _sparse_size = sparse_size
4514 with nogil:
4515 ret = rbd_sparsify(self.image, _sparse_size)
4516 if ret < 0:
4517 raise make_ex(ret, "error sparsifying %s" % self.name)
4518
4519 @requires_not_closed
4520 def rebuild_object_map(self):
4521 """
4522 Rebuild the object map for the image HEAD or currently set snapshot
4523 """
4524 cdef librbd_progress_fn_t prog_cb = &no_op_progress_callback
4525 with nogil:
4526 ret = rbd_rebuild_object_map(self.image, prog_cb, NULL)
4527 if ret < 0:
4528 raise make_ex(ret, "error rebuilding object map %s" % self.name)
4529
4530 @requires_not_closed
4531 def list_children(self):
4532 """
4533 List children of the currently set snapshot (set via set_snap()).
4534
4535 :returns: list - a list of (pool name, image name) tuples
4536 """
4537 cdef:
4538 rbd_linked_image_spec_t *children = NULL
4539 size_t num_children = 10
4540
4541 try:
4542 while True:
4543 children = <rbd_linked_image_spec_t*>realloc_chk(
4544 children, num_children * sizeof(rbd_linked_image_spec_t))
4545 with nogil:
4546 ret = rbd_list_children3(self.image, children,
4547 &num_children)
4548 if ret >= 0:
4549 break
4550 elif ret != -errno.ERANGE:
4551 raise make_ex(ret, 'error listing children.')
4552
4553 return [(decode_cstr(x.pool_name), decode_cstr(x.image_name)) for x
4554 in children[:num_children] if not x.trash]
4555 finally:
4556 if children:
4557 rbd_linked_image_spec_list_cleanup(children, num_children)
4558 free(children)
4559
4560 @requires_not_closed
4561 def list_children2(self):
4562 """
4563 Iterate over the children of the image or its snapshot.
4564
4565 :returns: :class:`ChildIterator`
4566 """
4567 return ChildIterator(self)
4568
4569 @requires_not_closed
4570 def list_descendants(self):
4571 """
4572 Iterate over the descendants of the image.
4573
4574 :returns: :class:`ChildIterator`
4575 """
4576 return ChildIterator(self, True)
4577
4578 @requires_not_closed
4579 def list_lockers(self):
4580 """
4581 List clients that have locked the image and information
4582 about the lock.
4583
4584 :returns: dict - contains the following keys:
4585
4586 * ``tag`` - the tag associated with the lock (every
4587 additional locker must use the same tag)
4588 * ``exclusive`` - boolean indicating whether the
4589 lock is exclusive or shared
4590 * ``lockers`` - a list of (client, cookie, address)
4591 tuples
4592 """
4593 cdef:
4594 size_t clients_size = 512, cookies_size = 512
4595 size_t addrs_size = 512, tag_size = 512
4596 int exclusive = 0
4597 char *c_clients = NULL
4598 char *c_cookies = NULL
4599 char *c_addrs = NULL
4600 char *c_tag = NULL
4601
4602 try:
4603 while True:
4604 c_clients = <char *>realloc_chk(c_clients, clients_size)
4605 c_cookies = <char *>realloc_chk(c_cookies, cookies_size)
4606 c_addrs = <char *>realloc_chk(c_addrs, addrs_size)
4607 c_tag = <char *>realloc_chk(c_tag, tag_size)
4608 with nogil:
4609 ret = rbd_list_lockers(self.image, &exclusive,
4610 c_tag, &tag_size,
4611 c_clients, &clients_size,
4612 c_cookies, &cookies_size,
4613 c_addrs, &addrs_size)
4614 if ret >= 0:
4615 break
4616 elif ret != -errno.ERANGE:
4617 raise make_ex(ret, 'error listing images')
4618 if ret == 0:
4619 return []
4620 clients = map(decode_cstr, c_clients[:clients_size - 1].split(b'\0'))
4621 cookies = map(decode_cstr, c_cookies[:cookies_size - 1].split(b'\0'))
4622 addrs = map(decode_cstr, c_addrs[:addrs_size - 1].split(b'\0'))
4623 return {
4624 'tag' : decode_cstr(c_tag),
4625 'exclusive' : exclusive == 1,
4626 'lockers' : list(zip(clients, cookies, addrs)),
4627 }
4628 finally:
4629 free(c_clients)
4630 free(c_cookies)
4631 free(c_addrs)
4632 free(c_tag)
4633
4634 @requires_not_closed
4635 def lock_acquire(self, lock_mode):
4636 """
4637 Acquire a managed lock on the image.
4638
4639 :param lock_mode: lock mode to set
4640 :type lock_mode: int
4641 :raises: :class:`ImageBusy` if the lock could not be acquired
4642 """
4643 cdef:
4644 rbd_lock_mode_t _lock_mode = lock_mode
4645 with nogil:
4646 ret = rbd_lock_acquire(self.image, _lock_mode)
4647 if ret < 0:
4648 raise make_ex(ret, 'error acquiring lock on image')
4649
4650 @requires_not_closed
4651 def lock_release(self):
4652 """
4653 Release a managed lock on the image that was previously acquired.
4654 """
4655 with nogil:
4656 ret = rbd_lock_release(self.image)
4657 if ret < 0:
4658 raise make_ex(ret, 'error releasing lock on image')
4659
4660 @requires_not_closed
4661 def lock_get_owners(self):
4662 """
4663 Iterate over the lock owners of an image.
4664
4665 :returns: :class:`LockOwnerIterator`
4666 """
4667 return LockOwnerIterator(self)
4668
4669 @requires_not_closed
4670 def lock_break(self, lock_mode, lock_owner):
4671 """
4672 Break the image lock held by a another client.
4673
4674 :param lock_owner: the owner of the lock to break
4675 :type lock_owner: str
4676 """
4677 lock_owner = cstr(lock_owner, 'lock_owner')
4678 cdef:
4679 rbd_lock_mode_t _lock_mode = lock_mode
4680 char *_lock_owner = lock_owner
4681 with nogil:
4682 ret = rbd_lock_break(self.image, _lock_mode, _lock_owner)
4683 if ret < 0:
4684 raise make_ex(ret, 'error breaking lock on image')
4685
4686 @requires_not_closed
4687 def lock_exclusive(self, cookie):
4688 """
4689 Take an exclusive lock on the image.
4690
4691 :raises: :class:`ImageBusy` if a different client or cookie locked it
4692 :class:`ImageExists` if the same client and cookie locked it
4693 """
4694 cookie = cstr(cookie, 'cookie')
4695 cdef char *_cookie = cookie
4696 with nogil:
4697 ret = rbd_lock_exclusive(self.image, _cookie)
4698 if ret < 0:
4699 raise make_ex(ret, 'error acquiring exclusive lock on image')
4700
4701 @requires_not_closed
4702 def lock_shared(self, cookie, tag):
4703 """
4704 Take a shared lock on the image. The tag must match
4705 that of the existing lockers, if any.
4706
4707 :raises: :class:`ImageBusy` if a different client or cookie locked it
4708 :class:`ImageExists` if the same client and cookie locked it
4709 """
4710 cookie = cstr(cookie, 'cookie')
4711 tag = cstr(tag, 'tag')
4712 cdef:
4713 char *_cookie = cookie
4714 char *_tag = tag
4715 with nogil:
4716 ret = rbd_lock_shared(self.image, _cookie, _tag)
4717 if ret < 0:
4718 raise make_ex(ret, 'error acquiring shared lock on image')
4719
4720 @requires_not_closed
4721 def unlock(self, cookie):
4722 """
4723 Release a lock on the image that was locked by this rados client.
4724 """
4725 cookie = cstr(cookie, 'cookie')
4726 cdef char *_cookie = cookie
4727 with nogil:
4728 ret = rbd_unlock(self.image, _cookie)
4729 if ret < 0:
4730 raise make_ex(ret, 'error unlocking image')
4731
4732 @requires_not_closed
4733 def break_lock(self, client, cookie):
4734 """
4735 Release a lock held by another rados client.
4736 """
4737 client = cstr(client, 'client')
4738 cookie = cstr(cookie, 'cookie')
4739 cdef:
4740 char *_client = client
4741 char *_cookie = cookie
4742 with nogil:
4743 ret = rbd_break_lock(self.image, _client, _cookie)
4744 if ret < 0:
4745 raise make_ex(ret, 'error unlocking image')
4746
4747 @requires_not_closed
4748 def mirror_image_enable(self, mode=RBD_MIRROR_IMAGE_MODE_JOURNAL):
4749 """
4750 Enable mirroring for the image.
4751 """
4752 cdef rbd_mirror_image_mode_t c_mode = mode
4753 with nogil:
4754 ret = rbd_mirror_image_enable2(self.image, c_mode)
4755 if ret < 0:
4756 raise make_ex(ret, 'error enabling mirroring for image %s' % self.name)
4757
4758 @requires_not_closed
4759 def mirror_image_disable(self, force):
4760 """
4761 Disable mirroring for the image.
4762
4763 :param force: force disabling
4764 :type force: bool
4765 """
4766 cdef bint c_force = force
4767 with nogil:
4768 ret = rbd_mirror_image_disable(self.image, c_force)
4769 if ret < 0:
4770 raise make_ex(ret, 'error disabling mirroring for image %s' % self.name)
4771
4772 @requires_not_closed
4773 def mirror_image_promote(self, force):
4774 """
4775 Promote the image to primary for mirroring.
4776
4777 :param force: force promoting
4778 :type force: bool
4779 """
4780 cdef bint c_force = force
4781 with nogil:
4782 ret = rbd_mirror_image_promote(self.image, c_force)
4783 if ret < 0:
4784 raise make_ex(ret, 'error promoting image %s to primary' % self.name)
4785
4786 @requires_not_closed
4787 def mirror_image_demote(self):
4788 """
4789 Demote the image to secondary for mirroring.
4790 """
4791 with nogil:
4792 ret = rbd_mirror_image_demote(self.image)
4793 if ret < 0:
4794 raise make_ex(ret, 'error demoting image %s to secondary' % self.name)
4795
4796 @requires_not_closed
4797 def mirror_image_resync(self):
4798 """
4799 Flag the image to resync.
4800 """
4801 with nogil:
4802 ret = rbd_mirror_image_resync(self.image)
4803 if ret < 0:
4804 raise make_ex(ret, 'error to resync image %s' % self.name)
4805
4806 @requires_not_closed
4807 def mirror_image_create_snapshot(self):
4808 """
4809 Create mirror snapshot.
4810
4811 :param force: ignore mirror snapshot limit
4812 :type force: bool
4813 :returns: int - the snapshot Id
4814 """
4815 cdef:
4816 uint64_t snap_id
4817 with nogil:
4818 ret = rbd_mirror_image_create_snapshot(self.image, &snap_id)
4819 if ret < 0:
4820 raise make_ex(ret, 'error creating mirror snapshot for image %s' %
4821 self.name)
4822 return snap_id
4823
4824 @requires_not_closed
4825 def mirror_image_get_info(self):
4826 """
4827 Get mirror info for the image.
4828
4829 :returns: dict - contains the following keys:
4830
4831 * ``global_id`` (str) - image global id
4832
4833 * ``state`` (int) - mirror state
4834
4835 * ``primary`` (bool) - is image primary
4836 """
4837 cdef rbd_mirror_image_info_t c_info
4838 with nogil:
4839 ret = rbd_mirror_image_get_info(self.image, &c_info, sizeof(c_info))
4840 if ret != 0:
4841 raise make_ex(ret, 'error getting mirror info for image %s' % self.name)
4842 info = {
4843 'global_id' : decode_cstr(c_info.global_id),
4844 'state' : int(c_info.state),
4845 'primary' : c_info.primary,
4846 }
4847 rbd_mirror_image_get_info_cleanup(&c_info)
4848 return info
4849
4850 @requires_not_closed
4851 def mirror_image_get_mode(self):
4852 """
4853 Get mirror mode for the image.
4854
4855 :returns: int - mirror mode
4856 """
4857 cdef rbd_mirror_image_mode_t c_mode
4858 with nogil:
4859 ret = rbd_mirror_image_get_mode(self.image, &c_mode)
4860 if ret != 0:
4861 raise make_ex(ret, 'error getting mirror mode for image %s' % self.name)
4862 return int(c_mode)
4863
4864 @requires_not_closed
4865 def mirror_image_get_status(self):
4866 """
4867 Get mirror status for the image.
4868
4869 :returns: dict - contains the following keys:
4870
4871 * ``name`` (str) - mirror image name
4872
4873 * ``id`` (str) - mirror image id
4874
4875 * ``info`` (dict) - mirror image info
4876
4877 * ``state`` (int) - status mirror state
4878
4879 * ``description`` (str) - status description
4880
4881 * ``last_update`` (datetime) - last status update time
4882
4883 * ``up`` (bool) - is mirroring agent up
4884
4885 * ``remote_statuses`` (array) -
4886
4887 * ``mirror_uuid`` (str) - remote mirror uuid
4888
4889 * ``state`` (int) - status mirror state
4890
4891 * ``description`` (str) - status description
4892
4893 * ``last_update`` (datetime) - last status update time
4894
4895 * ``up`` (bool) - is mirroring agent up
4896 """
4897 cdef:
4898 rbd_mirror_image_site_status_t *s_status
4899 rbd_mirror_image_global_status_t c_status
4900 try:
4901 with nogil:
4902 ret = rbd_mirror_image_get_global_status(self.image, &c_status,
4903 sizeof(c_status))
4904 if ret != 0:
4905 raise make_ex(ret, 'error getting mirror status for image %s' % self.name)
4906
4907 local_status = None
4908 site_statuses = []
4909 for i in range(c_status.site_statuses_count):
4910 s_status = &c_status.site_statuses[i]
4911 site_status = {
4912 'state' : s_status.state,
4913 'description' : decode_cstr(s_status.description),
4914 'last_update' : datetime.utcfromtimestamp(s_status.last_update),
4915 'up' : s_status.up,
4916 }
4917 mirror_uuid = decode_cstr(s_status.mirror_uuid)
4918 if mirror_uuid == '':
4919 local_status = site_status
4920 else:
4921 site_statuses['mirror_uuid'] = mirror_uuid
4922 site_statuses += site_status
4923 status = {
4924 'name': decode_cstr(c_status.name),
4925 'id' : self.id(),
4926 'info': {
4927 'global_id' : decode_cstr(c_status.info.global_id),
4928 'state' : int(c_status.info.state),
4929 'primary' : c_status.info.primary,
4930 },
4931 'remote_statuses': site_statuses,
4932 }
4933 if local_status:
4934 status.update(local_status)
4935 finally:
4936 rbd_mirror_image_global_status_cleanup(&c_status)
4937 return status
4938
4939 @requires_not_closed
4940 def mirror_image_get_instance_id(self):
4941 """
4942 Get mirror instance id for the image.
4943
4944 :returns: str - instance id
4945 """
4946 cdef:
4947 int ret = -errno.ERANGE
4948 size_t size = 32
4949 char *instance_id = NULL
4950 try:
4951 while ret == -errno.ERANGE and size <= 4096:
4952 instance_id = <char *>realloc_chk(instance_id, size)
4953 with nogil:
4954 ret = rbd_mirror_image_get_instance_id(self.image,
4955 instance_id, &size)
4956 if ret != 0:
4957 raise make_ex(ret,
4958 'error getting mirror instance id for image %s' %
4959 self.name)
4960 return decode_cstr(instance_id)
4961 finally:
4962 free(instance_id)
4963
4964 @requires_not_closed
4965 def aio_read(self, offset, length, oncomplete, fadvise_flags=0):
4966 """
4967 Asynchronously read data from the image
4968
4969 Raises :class:`InvalidArgument` if part of the range specified is
4970 outside the image.
4971
4972 oncomplete will be called with the returned read value as
4973 well as the completion:
4974
4975 oncomplete(completion, data_read)
4976
4977 :param offset: the offset to start reading at
4978 :type offset: int
4979 :param length: how many bytes to read
4980 :type length: int
4981 :param oncomplete: what to do when the read is complete
4982 :type oncomplete: completion
4983 :param fadvise_flags: fadvise flags for this read
4984 :type fadvise_flags: int
4985 :returns: :class:`Completion` - the completion object
4986 :raises: :class:`InvalidArgument`, :class:`IOError`
4987 """
4988 cdef:
4989 char *ret_buf
4990 uint64_t _offset = offset
4991 size_t _length = length
4992 int _fadvise_flags = fadvise_flags
4993 Completion completion
4994
4995 def oncomplete_(completion_v):
4996 cdef Completion _completion_v = completion_v
4997 return_value = _completion_v.get_return_value()
4998 if return_value > 0 and return_value != length:
4999 _PyBytes_Resize(&_completion_v.buf, return_value)
5000 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
5001
5002 completion = self.__get_completion(oncomplete_)
5003 completion.buf = PyBytes_FromStringAndSize(NULL, length)
5004 ret_buf = PyBytes_AsString(completion.buf)
5005 try:
5006 completion.__persist()
5007 with nogil:
5008 ret = rbd_aio_read2(self.image, _offset, _length, ret_buf,
5009 completion.rbd_comp, _fadvise_flags)
5010 if ret < 0:
5011 raise make_ex(ret, 'error reading %s %ld~%ld' %
5012 (self.name, offset, length))
5013 except:
5014 completion.__unpersist()
5015 raise
5016
5017 return completion
5018
5019 @requires_not_closed
5020 def aio_write(self, data, offset, oncomplete, fadvise_flags=0):
5021 """
5022 Asynchronously write data to the image
5023
5024 Raises :class:`InvalidArgument` if part of the write would fall outside
5025 the image.
5026
5027 oncomplete will be called with the completion:
5028
5029 oncomplete(completion)
5030
5031 :param data: the data to be written
5032 :type data: bytes
5033 :param offset: the offset to start writing at
5034 :type offset: int
5035 :param oncomplete: what to do when the write is complete
5036 :type oncomplete: completion
5037 :param fadvise_flags: fadvise flags for this write
5038 :type fadvise_flags: int
5039 :returns: :class:`Completion` - the completion object
5040 :raises: :class:`InvalidArgument`, :class:`IOError`
5041 """
5042 cdef:
5043 uint64_t _offset = offset
5044 char *_data = data
5045 size_t _length = len(data)
5046 int _fadvise_flags = fadvise_flags
5047 Completion completion
5048
5049 completion = self.__get_completion(oncomplete)
5050 try:
5051 completion.__persist()
5052 with nogil:
5053 ret = rbd_aio_write2(self.image, _offset, _length, _data,
5054 completion.rbd_comp, _fadvise_flags)
5055 if ret < 0:
5056 raise make_ex(ret, 'error writing %s %ld~%ld' %
5057 (self.name, offset, _length))
5058 except:
5059 completion.__unpersist()
5060 raise
5061
5062 return completion
5063
5064 @requires_not_closed
5065 def aio_discard(self, offset, length, oncomplete):
5066 """
5067 Asynchronously trim the range from the image. It will be logically
5068 filled with zeroes.
5069 """
5070 cdef:
5071 uint64_t _offset = offset
5072 size_t _length = length
5073 Completion completion
5074
5075 completion = self.__get_completion(oncomplete)
5076 try:
5077 completion.__persist()
5078 with nogil:
5079 ret = rbd_aio_discard(self.image, _offset, _length,
5080 completion.rbd_comp)
5081 if ret < 0:
5082 raise make_ex(ret, 'error discarding %s %ld~%ld' %
5083 (self.name, offset, _length))
5084 except:
5085 completion.__unpersist()
5086 raise
5087
5088 return completion
5089
5090 @requires_not_closed
5091 def aio_flush(self, oncomplete):
5092 """
5093 Asynchronously wait until all writes are fully flushed if caching is
5094 enabled.
5095 """
5096 cdef Completion completion = self.__get_completion(oncomplete)
5097 try:
5098 completion.__persist()
5099 with nogil:
5100 ret = rbd_aio_flush(self.image, completion.rbd_comp)
5101 if ret < 0:
5102 raise make_ex(ret, 'error flushing')
5103 except:
5104 completion.__unpersist()
5105 raise
5106
5107 return completion
5108
5109 @requires_not_closed
5110 def metadata_get(self, key):
5111 """
5112 Get image metadata for the given key.
5113
5114 :param key: metadata key
5115 :type key: str
5116 :returns: str - metadata value
5117 """
5118 key = cstr(key, 'key')
5119 cdef:
5120 char *_key = key
5121 size_t size = 4096
5122 char *value = NULL
5123 int ret
5124 try:
5125 while True:
5126 value = <char *>realloc_chk(value, size)
5127 with nogil:
5128 ret = rbd_metadata_get(self.image, _key, value, &size)
5129 if ret != -errno.ERANGE:
5130 break
5131 if ret == -errno.ENOENT:
5132 raise KeyError('no metadata %s for image %s' % (key, self.name))
5133 if ret != 0:
5134 raise make_ex(ret, 'error getting metadata %s for image %s' %
5135 (key, self.name))
5136 return decode_cstr(value)
5137 finally:
5138 free(value)
5139
5140 @requires_not_closed
5141 def metadata_set(self, key, value):
5142 """
5143 Set image metadata for the given key.
5144
5145 :param key: metadata key
5146 :type key: str
5147 :param value: metadata value
5148 :type value: str
5149 """
5150 key = cstr(key, 'key')
5151 value = cstr(value, 'value')
5152 cdef:
5153 char *_key = key
5154 char *_value = value
5155 with nogil:
5156 ret = rbd_metadata_set(self.image, _key, _value)
5157
5158 if ret != 0:
5159 raise make_ex(ret, 'error setting metadata %s for image %s' %
5160 (key, self.name))
5161
5162 @requires_not_closed
5163 def metadata_remove(self, key):
5164 """
5165 Remove image metadata for the given key.
5166
5167 :param key: metadata key
5168 :type key: str
5169 """
5170 key = cstr(key, 'key')
5171 cdef:
5172 char *_key = key
5173 with nogil:
5174 ret = rbd_metadata_remove(self.image, _key)
5175
5176 if ret == -errno.ENOENT:
5177 raise KeyError('no metadata %s for image %s' % (key, self.name))
5178 if ret != 0:
5179 raise make_ex(ret, 'error removing metadata %s for image %s' %
5180 (key, self.name))
5181
5182 @requires_not_closed
5183 def metadata_list(self):
5184 """
5185 List image metadata.
5186
5187 :returns: :class:`MetadataIterator`
5188 """
5189 return MetadataIterator(self)
5190
5191 @requires_not_closed
5192 def watchers_list(self):
5193 """
5194 List image watchers.
5195
5196 :returns: :class:`WatcherIterator`
5197 """
5198 return WatcherIterator(self)
5199
5200 @requires_not_closed
5201 def config_list(self):
5202 """
5203 List image-level config overrides.
5204
5205 :returns: :class:`ConfigImageIterator`
5206 """
5207 return ConfigImageIterator(self)
5208
5209 @requires_not_closed
5210 def config_set(self, key, value):
5211 """
5212 Set an image-level configuration override.
5213
5214 :param key: key
5215 :type key: str
5216 :param value: value
5217 :type value: str
5218 """
5219 conf_key = 'conf_' + key
5220 conf_key = cstr(conf_key, 'key')
5221 value = cstr(value, 'value')
5222 cdef:
5223 char *_key = conf_key
5224 char *_value = value
5225 with nogil:
5226 ret = rbd_metadata_set(self.image, _key, _value)
5227
5228 if ret != 0:
5229 raise make_ex(ret, 'error setting config %s for image %s' %
5230 (key, self.name))
5231
5232 @requires_not_closed
5233 def config_get(self, key):
5234 """
5235 Get an image-level configuration override.
5236
5237 :param key: key
5238 :type key: str
5239 :returns: str - value
5240 """
5241 conf_key = 'conf_' + key
5242 conf_key = cstr(conf_key, 'key')
5243 cdef:
5244 char *_key = conf_key
5245 size_t size = 4096
5246 char *value = NULL
5247 int ret
5248 try:
5249 while True:
5250 value = <char *>realloc_chk(value, size)
5251 with nogil:
5252 ret = rbd_metadata_get(self.image, _key, value, &size)
5253 if ret != -errno.ERANGE:
5254 break
5255 if ret == -errno.ENOENT:
5256 raise KeyError('no config %s for image %s' % (key, self.name))
5257 if ret != 0:
5258 raise make_ex(ret, 'error getting config %s for image %s' %
5259 (key, self.name))
5260 return decode_cstr(value)
5261 finally:
5262 free(value)
5263
5264 @requires_not_closed
5265 def config_remove(self, key):
5266 """
5267 Remove an image-level configuration override.
5268
5269 :param key: key
5270 :type key: str
5271 """
5272 conf_key = 'conf_' + key
5273 conf_key = cstr(conf_key, 'key')
5274 cdef:
5275 char *_key = conf_key
5276 with nogil:
5277 ret = rbd_metadata_remove(self.image, _key)
5278
5279 if ret == -errno.ENOENT:
5280 raise KeyError('no config %s for image %s' % (key, self.name))
5281 if ret != 0:
5282 raise make_ex(ret, 'error removing config %s for image %s' %
5283 (key, self.name))
5284
5285 @requires_not_closed
5286 def snap_get_namespace_type(self, snap_id):
5287 """
5288 Get the snapshot namespace type.
5289 :param snap_id: the snapshot id of a snap shot
5290 :type key: int
5291 """
5292 cdef:
5293 rbd_snap_namespace_type_t namespace_type
5294 uint64_t _snap_id = snap_id
5295 with nogil:
5296 ret = rbd_snap_get_namespace_type(self.image, _snap_id, &namespace_type)
5297 if ret != 0:
5298 raise make_ex(ret, 'error getting snapshot namespace type for image: %s, snap_id: %d' % (self.name, snap_id))
5299
5300 return namespace_type
5301
5302 @requires_not_closed
5303 def snap_get_group_namespace(self, snap_id):
5304 """
5305 get the group namespace details.
5306 :param snap_id: the snapshot id of the group snapshot
5307 :type key: int
5308 :returns: dict - contains the following keys:
5309
5310 * ``pool`` (int) - pool id
5311
5312 * ``name`` (str) - group name
5313
5314 * ``snap_name`` (str) - group snap name
5315 """
5316 cdef:
5317 rbd_snap_group_namespace_t group_namespace
5318 uint64_t _snap_id = snap_id
5319 with nogil:
5320 ret = rbd_snap_get_group_namespace(self.image, _snap_id,
5321 &group_namespace,
5322 sizeof(rbd_snap_group_namespace_t))
5323 if ret != 0:
5324 raise make_ex(ret, 'error getting snapshot group namespace for image: %s, snap_id: %d' % (self.name, snap_id))
5325
5326 info = {
5327 'pool' : group_namespace.group_pool,
5328 'name' : decode_cstr(group_namespace.group_name),
5329 'snap_name' : decode_cstr(group_namespace.group_snap_name)
5330 }
5331 rbd_snap_group_namespace_cleanup(&group_namespace,
5332 sizeof(rbd_snap_group_namespace_t))
5333 return info
5334
5335 @requires_not_closed
5336 def snap_get_trash_namespace(self, snap_id):
5337 """
5338 get the trash namespace details.
5339 :param snap_id: the snapshot id of the trash snapshot
5340 :type key: int
5341 :returns: dict - contains the following keys:
5342
5343 * ``original_name`` (str) - original snap name
5344 """
5345 cdef:
5346 uint64_t _snap_id = snap_id
5347 size_t _size = 512
5348 char *_name = NULL
5349 try:
5350 while True:
5351 _name = <char*>realloc_chk(_name, _size);
5352 with nogil:
5353 ret = rbd_snap_get_trash_namespace(self.image, _snap_id,
5354 _name, _size)
5355 if ret >= 0:
5356 break
5357 elif ret != -errno.ERANGE:
5358 raise make_ex(ret, 'error getting snapshot trash '
5359 'namespace image: %s, snap_id: %d' % (self.name, snap_id))
5360 return {
5361 'original_name' : decode_cstr(_name)
5362 }
5363 finally:
5364 free(_name)
5365
5366 @requires_not_closed
5367 def snap_get_mirror_namespace(self, snap_id):
5368 """
5369 get the mirror namespace details.
5370 :param snap_id: the snapshot id of the mirror snapshot
5371 :type key: int
5372 :returns: dict - contains the following keys:
5373
5374 * ``state`` (int) - the snapshot state
5375
5376 * ``mirror_peer_uuids`` (list) - mirror peer uuids
5377
5378 * ``complete`` (bool) - True if snapshot is complete
5379
5380 * ``primary_mirror_uuid`` (str) - primary mirror uuid
5381
5382 * ``primary_snap_id`` (int) - primary snapshot Id
5383
5384 * ``last_copied_object_number`` (int) - last copied object number
5385 """
5386 cdef:
5387 rbd_snap_mirror_namespace_t sn
5388 uint64_t _snap_id = snap_id
5389 with nogil:
5390 ret = rbd_snap_get_mirror_namespace(
5391 self.image, _snap_id, &sn,
5392 sizeof(rbd_snap_mirror_namespace_t))
5393 if ret != 0:
5394 raise make_ex(ret, 'error getting snapshot mirror '
5395 'namespace for image: %s, snap_id: %d' %
5396 (self.name, snap_id))
5397 uuids = []
5398 cdef char *p = sn.mirror_peer_uuids
5399 for i in range(sn.mirror_peer_uuids_count):
5400 uuid = decode_cstr(p)
5401 uuids.append(uuid)
5402 p += len(uuid) + 1
5403 info = {
5404 'state' : sn.state,
5405 'mirror_peer_uuids' : uuids,
5406 'complete' : sn.complete,
5407 'primary_mirror_uuid' : decode_cstr(sn.primary_mirror_uuid),
5408 'primary_snap_id' : sn.primary_snap_id,
5409 'last_copied_object_number' : sn.last_copied_object_number,
5410 }
5411 rbd_snap_mirror_namespace_cleanup(
5412 &sn, sizeof(rbd_snap_mirror_namespace_t))
5413 return info
5414
5415
5416 cdef class ImageIterator(object):
5417 """
5418 Iterator over RBD images in a pool
5419
5420 Yields a dictionary containing information about the images
5421
5422 Keys are:
5423
5424 * ``id`` (str) - image id
5425
5426 * ``name`` (str) - image name
5427 """
5428 cdef rados_ioctx_t ioctx
5429 cdef rbd_image_spec_t *images
5430 cdef size_t num_images
5431
5432 def __init__(self, ioctx):
5433 self.ioctx = convert_ioctx(ioctx)
5434 self.images = NULL
5435 self.num_images = 1024
5436 while True:
5437 self.images = <rbd_image_spec_t*>realloc_chk(
5438 self.images, self.num_images * sizeof(rbd_image_spec_t))
5439 with nogil:
5440 ret = rbd_list2(self.ioctx, self.images, &self.num_images)
5441 if ret >= 0:
5442 break
5443 elif ret == -errno.ERANGE:
5444 self.num_images *= 2
5445 else:
5446 raise make_ex(ret, 'error listing images.')
5447
5448 def __iter__(self):
5449 for i in range(self.num_images):
5450 yield {
5451 'id' : decode_cstr(self.images[i].id),
5452 'name' : decode_cstr(self.images[i].name)
5453 }
5454
5455 def __dealloc__(self):
5456 if self.images:
5457 rbd_image_spec_list_cleanup(self.images, self.num_images)
5458 free(self.images)
5459
5460
5461 cdef class LockOwnerIterator(object):
5462 """
5463 Iterator over managed lock owners for an image
5464
5465 Yields a dictionary containing information about the image's lock
5466
5467 Keys are:
5468
5469 * ``mode`` (int) - active lock mode
5470
5471 * ``owner`` (str) - lock owner name
5472 """
5473
5474 cdef:
5475 rbd_lock_mode_t lock_mode
5476 char **lock_owners
5477 size_t num_lock_owners
5478 object image
5479
5480 def __init__(self, Image image):
5481 image.require_not_closed()
5482
5483 self.image = image
5484 self.lock_owners = NULL
5485 self.num_lock_owners = 8
5486 while True:
5487 self.lock_owners = <char**>realloc_chk(self.lock_owners,
5488 self.num_lock_owners *
5489 sizeof(char*))
5490 with nogil:
5491 ret = rbd_lock_get_owners(image.image, &self.lock_mode,
5492 self.lock_owners,
5493 &self.num_lock_owners)
5494 if ret >= 0:
5495 break
5496 elif ret == -errno.ENOENT:
5497 self.num_lock_owners = 0
5498 break
5499 elif ret != -errno.ERANGE:
5500 raise make_ex(ret, 'error listing lock owners for image %s' % image.name)
5501
5502 def __iter__(self):
5503 for i in range(self.num_lock_owners):
5504 yield {
5505 'mode' : int(self.lock_mode),
5506 'owner' : decode_cstr(self.lock_owners[i]),
5507 }
5508
5509 def __dealloc__(self):
5510 if self.lock_owners:
5511 rbd_lock_get_owners_cleanup(self.lock_owners, self.num_lock_owners)
5512 free(self.lock_owners)
5513
5514 cdef class MetadataIterator(object):
5515 """
5516 Iterator over metadata list for an image.
5517
5518 Yields ``(key, value)`` tuple.
5519
5520 * ``key`` (str) - metadata key
5521 * ``value`` (str) - metadata value
5522 """
5523
5524 cdef:
5525 cdef object image
5526 rbd_image_t c_image
5527 char *last_read
5528 uint64_t max_read
5529 object next_chunk
5530
5531 def __init__(self, Image image):
5532 image.require_not_closed()
5533
5534 self.image = image
5535 self.c_image = image.image
5536 self.last_read = strdup("")
5537 self.max_read = 32
5538 self.get_next_chunk()
5539
5540 def __iter__(self):
5541 while len(self.next_chunk) > 0:
5542 for pair in self.next_chunk:
5543 yield pair
5544 if len(self.next_chunk) < self.max_read:
5545 break
5546 self.get_next_chunk()
5547
5548 def __dealloc__(self):
5549 if self.last_read:
5550 free(self.last_read)
5551
5552 def get_next_chunk(self):
5553 self.image.require_not_closed()
5554
5555 cdef:
5556 char *c_keys = NULL
5557 size_t keys_size = 4096
5558 char *c_vals = NULL
5559 size_t vals_size = 4096
5560 try:
5561 while True:
5562 c_keys = <char *>realloc_chk(c_keys, keys_size)
5563 c_vals = <char *>realloc_chk(c_vals, vals_size)
5564 with nogil:
5565 ret = rbd_metadata_list(self.c_image, self.last_read,
5566 self.max_read, c_keys, &keys_size,
5567 c_vals, &vals_size)
5568 if ret >= 0:
5569 break
5570 elif ret != -errno.ERANGE:
5571 raise make_ex(ret, 'error listing metadata for image %s' %
5572 self.image.name)
5573 keys = [decode_cstr(key) for key in
5574 c_keys[:keys_size].split(b'\0') if key]
5575 vals = [decode_cstr(val) for val in
5576 c_vals[:vals_size].split(b'\0') if val]
5577 if len(keys) > 0:
5578 last_read = cstr(keys[-1], 'last_read')
5579 free(self.last_read)
5580 self.last_read = strdup(last_read)
5581 self.next_chunk = list(zip(keys, vals))
5582 finally:
5583 free(c_keys)
5584 free(c_vals)
5585
5586 cdef class SnapIterator(object):
5587 """
5588 Iterator over snapshot info for an image.
5589
5590 Yields a dictionary containing information about a snapshot.
5591
5592 Keys are:
5593
5594 * ``id`` (int) - numeric identifier of the snapshot
5595
5596 * ``size`` (int) - size of the image at the time of snapshot (in bytes)
5597
5598 * ``name`` (str) - name of the snapshot
5599
5600 * ``namespace`` (int) - enum for snap namespace
5601
5602 * ``group`` (dict) - optional for group namespace snapshots
5603
5604 * ``trash`` (dict) - optional for trash namespace snapshots
5605
5606 * ``mirror`` (dict) - optional for mirror namespace snapshots
5607 """
5608
5609 cdef rbd_snap_info_t *snaps
5610 cdef int num_snaps
5611 cdef object image
5612
5613 def __init__(self, Image image):
5614 image.require_not_closed()
5615
5616 self.image = image
5617 self.snaps = NULL
5618 self.num_snaps = 10
5619 while True:
5620 self.snaps = <rbd_snap_info_t*>realloc_chk(self.snaps,
5621 self.num_snaps *
5622 sizeof(rbd_snap_info_t))
5623 with nogil:
5624 ret = rbd_snap_list(image.image, self.snaps, &self.num_snaps)
5625 if ret >= 0:
5626 self.num_snaps = ret
5627 break
5628 elif ret != -errno.ERANGE:
5629 raise make_ex(ret, 'error listing snapshots for image %s' % image.name)
5630
5631 def __iter__(self):
5632 for i in range(self.num_snaps):
5633 s = {
5634 'id' : self.snaps[i].id,
5635 'size' : self.snaps[i].size,
5636 'name' : decode_cstr(self.snaps[i].name),
5637 'namespace' : self.image.snap_get_namespace_type(self.snaps[i].id)
5638 }
5639 if s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_GROUP:
5640 try:
5641 group = self.image.snap_get_group_namespace(self.snaps[i].id)
5642 except:
5643 group = None
5644 s['group'] = group
5645 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_TRASH:
5646 try:
5647 trash = self.image.snap_get_trash_namespace(self.snaps[i].id)
5648 except:
5649 trash = None
5650 s['trash'] = trash
5651 elif s['namespace'] == RBD_SNAP_NAMESPACE_TYPE_MIRROR:
5652 try:
5653 mirror = self.image.snap_get_mirror_namespace(
5654 self.snaps[i].id)
5655 except:
5656 mirror = None
5657 s['mirror'] = mirror
5658 yield s
5659
5660 def __dealloc__(self):
5661 if self.snaps:
5662 rbd_snap_list_end(self.snaps)
5663 free(self.snaps)
5664
5665 cdef class TrashIterator(object):
5666 """
5667 Iterator over trash entries.
5668
5669 Yields a dictionary containing trash info of an image.
5670
5671 Keys are:
5672
5673 * `id` (str) - image id
5674
5675 * `name` (str) - image name
5676
5677 * `source` (str) - source of deletion
5678
5679 * `deletion_time` (datetime) - time of deletion
5680
5681 * `deferment_end_time` (datetime) - time that an image is allowed to be
5682 removed from trash
5683 """
5684
5685 cdef:
5686 rados_ioctx_t ioctx
5687 size_t num_entries
5688 rbd_trash_image_info_t *entries
5689
5690 def __init__(self, ioctx):
5691 self.ioctx = convert_ioctx(ioctx)
5692 self.num_entries = 1024
5693 self.entries = NULL
5694 while True:
5695 self.entries = <rbd_trash_image_info_t*>realloc_chk(self.entries,
5696 self.num_entries *
5697 sizeof(rbd_trash_image_info_t))
5698 with nogil:
5699 ret = rbd_trash_list(self.ioctx, self.entries, &self.num_entries)
5700 if ret >= 0:
5701 self.num_entries = ret
5702 break
5703 elif ret != -errno.ERANGE:
5704 raise make_ex(ret, 'error listing trash entries')
5705
5706 __source_string = ['USER', 'MIRRORING']
5707
5708 def __iter__(self):
5709 for i in range(self.num_entries):
5710 yield {
5711 'id' : decode_cstr(self.entries[i].id),
5712 'name' : decode_cstr(self.entries[i].name),
5713 'source' : TrashIterator.__source_string[self.entries[i].source],
5714 'deletion_time' : datetime.utcfromtimestamp(self.entries[i].deletion_time),
5715 'deferment_end_time' : datetime.utcfromtimestamp(self.entries[i].deferment_end_time)
5716 }
5717
5718 def __dealloc__(self):
5719 rbd_trash_list_cleanup(self.entries, self.num_entries)
5720 if self.entries:
5721 free(self.entries)
5722
5723 cdef class ChildIterator(object):
5724 """
5725 Iterator over child info for the image or its snapshot.
5726
5727 Yields a dictionary containing information about a child.
5728
5729 Keys are:
5730
5731 * ``pool`` (str) - name of the pool
5732
5733 * ``pool_namespace`` (str) - namespace of the pool
5734
5735 * ``image`` (str) - name of the child
5736
5737 * ``id`` (str) - id of the child
5738
5739 * ``trash`` (bool) - True if child is in trash bin
5740 """
5741
5742 cdef rbd_linked_image_spec_t *children
5743 cdef size_t num_children
5744 cdef object image
5745
5746 def __init__(self, Image image, descendants=False):
5747 image.require_not_closed()
5748
5749 self.image = image
5750 self.children = NULL
5751 self.num_children = 10
5752 while True:
5753 self.children = <rbd_linked_image_spec_t*>realloc_chk(
5754 self.children, self.num_children * sizeof(rbd_linked_image_spec_t))
5755 if descendants:
5756 with nogil:
5757 ret = rbd_list_descendants(image.image, self.children,
5758 &self.num_children)
5759 else:
5760 with nogil:
5761 ret = rbd_list_children3(image.image, self.children,
5762 &self.num_children)
5763 if ret >= 0:
5764 break
5765 elif ret != -errno.ERANGE:
5766 raise make_ex(ret, 'error listing children.')
5767
5768 def __iter__(self):
5769 for i in range(self.num_children):
5770 yield {
5771 'pool' : decode_cstr(self.children[i].pool_name),
5772 'pool_namespace' : decode_cstr(self.children[i].pool_namespace),
5773 'image' : decode_cstr(self.children[i].image_name),
5774 'id' : decode_cstr(self.children[i].image_id),
5775 'trash' : self.children[i].trash
5776 }
5777
5778 def __dealloc__(self):
5779 if self.children:
5780 rbd_linked_image_spec_list_cleanup(self.children, self.num_children)
5781 free(self.children)
5782
5783 cdef class WatcherIterator(object):
5784 """
5785 Iterator over watchers of an image.
5786
5787 Yields a dictionary containing information about a watcher.
5788
5789 Keys are:
5790
5791 * ``addr`` (str) - address of the watcher
5792
5793 * ``id`` (int) - id of the watcher
5794
5795 * ``cookie`` (int) - the watcher's cookie
5796 """
5797
5798 cdef rbd_image_watcher_t *watchers
5799 cdef size_t num_watchers
5800 cdef object image
5801
5802 def __init__(self, Image image):
5803 image.require_not_closed()
5804
5805 self.image = image
5806 self.watchers = NULL
5807 self.num_watchers = 10
5808 while True:
5809 self.watchers = <rbd_image_watcher_t*>realloc_chk(self.watchers,
5810 self.num_watchers *
5811 sizeof(rbd_image_watcher_t))
5812 with nogil:
5813 ret = rbd_watchers_list(image.image, self.watchers, &self.num_watchers)
5814 if ret >= 0:
5815 break
5816 elif ret != -errno.ERANGE:
5817 raise make_ex(ret, 'error listing watchers.')
5818
5819 def __iter__(self):
5820 for i in range(self.num_watchers):
5821 yield {
5822 'addr' : decode_cstr(self.watchers[i].addr),
5823 'id' : self.watchers[i].id,
5824 'cookie' : self.watchers[i].cookie
5825 }
5826
5827 def __dealloc__(self):
5828 if self.watchers:
5829 rbd_watchers_list_cleanup(self.watchers, self.num_watchers)
5830 free(self.watchers)
5831
5832 cdef class ConfigImageIterator(object):
5833 """
5834 Iterator over image-level overrides for an image.
5835
5836 Yields a dictionary containing information about an override.
5837
5838 Keys are:
5839
5840 * ``name`` (str) - override name
5841
5842 * ``value`` (str) - override value
5843
5844 * ``source`` (str) - override source
5845 """
5846
5847 cdef:
5848 rbd_config_option_t *options
5849 int num_options
5850
5851 def __init__(self, Image image):
5852 image.require_not_closed()
5853
5854 self.options = NULL
5855 self.num_options = 32
5856 while True:
5857 self.options = <rbd_config_option_t *>realloc_chk(
5858 self.options, self.num_options * sizeof(rbd_config_option_t))
5859 with nogil:
5860 ret = rbd_config_image_list(image.image, self.options,
5861 &self.num_options)
5862 if ret < 0:
5863 if ret == -errno.ERANGE:
5864 continue
5865 self.num_options = 0
5866 raise make_ex(ret, 'error listing config options')
5867 break
5868
5869 def __iter__(self):
5870 for i in range(self.num_options):
5871 yield {
5872 'name' : decode_cstr(self.options[i].name),
5873 'value' : decode_cstr(self.options[i].value),
5874 'source' : self.options[i].source,
5875 }
5876
5877 def __dealloc__(self):
5878 if self.options:
5879 rbd_config_image_list_cleanup(self.options, self.num_options)
5880 free(self.options)
5881
5882 cdef class GroupImageIterator(object):
5883 """
5884 Iterator over image info for a group.
5885
5886 Yields a dictionary containing information about an image.
5887
5888 Keys are:
5889
5890 * ``name`` (str) - name of the image
5891
5892 * ``pool`` (int) - id of the pool this image belongs to
5893
5894 * ``state`` (int) - state of the image
5895 """
5896
5897 cdef rbd_group_image_info_t *images
5898 cdef size_t num_images
5899 cdef object group
5900
5901 def __init__(self, Group group):
5902 self.group = group
5903 self.images = NULL
5904 self.num_images = 10
5905 while True:
5906 self.images = <rbd_group_image_info_t*>realloc_chk(self.images,
5907 self.num_images *
5908 sizeof(rbd_group_image_info_t))
5909 with nogil:
5910 ret = rbd_group_image_list(group._ioctx, group._name,
5911 self.images,
5912 sizeof(rbd_group_image_info_t),
5913 &self.num_images)
5914
5915 if ret >= 0:
5916 break
5917 elif ret != -errno.ERANGE:
5918 raise make_ex(ret, 'error listing images for group %s' % group.name, group_errno_to_exception)
5919
5920 def __iter__(self):
5921 for i in range(self.num_images):
5922 yield {
5923 'name' : decode_cstr(self.images[i].name),
5924 'pool' : self.images[i].pool,
5925 'state' : self.images[i].state,
5926 }
5927
5928 def __dealloc__(self):
5929 if self.images:
5930 rbd_group_image_list_cleanup(self.images,
5931 sizeof(rbd_group_image_info_t),
5932 self.num_images)
5933 free(self.images)
5934
5935 cdef class GroupSnapIterator(object):
5936 """
5937 Iterator over snaps specs for a group.
5938
5939 Yields a dictionary containing information about a snapshot.
5940
5941 Keys are:
5942
5943 * ``name`` (str) - name of the snapshot
5944
5945 * ``state`` (int) - state of the snapshot
5946 """
5947
5948 cdef rbd_group_snap_info_t *snaps
5949 cdef size_t num_snaps
5950 cdef object group
5951
5952 def __init__(self, Group group):
5953 self.group = group
5954 self.snaps = NULL
5955 self.num_snaps = 10
5956 while True:
5957 self.snaps = <rbd_group_snap_info_t*>realloc_chk(self.snaps,
5958 self.num_snaps *
5959 sizeof(rbd_group_snap_info_t))
5960 with nogil:
5961 ret = rbd_group_snap_list(group._ioctx, group._name, self.snaps,
5962 sizeof(rbd_group_snap_info_t),
5963 &self.num_snaps)
5964
5965 if ret >= 0:
5966 break
5967 elif ret != -errno.ERANGE:
5968 raise make_ex(ret, 'error listing snapshots for group %s' % group.name, group_errno_to_exception)
5969
5970 def __iter__(self):
5971 for i in range(self.num_snaps):
5972 yield {
5973 'name' : decode_cstr(self.snaps[i].name),
5974 'state' : self.snaps[i].state,
5975 }
5976
5977 def __dealloc__(self):
5978 if self.snaps:
5979 rbd_group_snap_list_cleanup(self.snaps,
5980 sizeof(rbd_group_snap_info_t),
5981 self.num_snaps)
5982 free(self.snaps)