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