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