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