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