1 # cython: embedsignature=True
3 This module is a thin wrapper around librados.
5 Error codes from librados are turned into exceptions that subclass
6 :class:`Error`. Almost all methods may raise :class:`Error(the base class of all rados exceptions), :class:`PermissionError`
7 (the base class of all rados exceptions), :class:`PermissionError`
8 and :class:`IOError`, in addition to those documented for the
11 # Copyright 2011 Josh Durgin
12 # Copyright 2011, Hannu Valtonen <hannu.valtonen@ormod.com>
13 # Copyright 2015 Hector Martin <marcan@marcan.st>
14 # Copyright 2016 Mehdi Abaakouk <sileht@redhat.com>
16 from cpython cimport PyObject, ref
17 from cpython.pycapsule cimport *
18 from libc cimport errno
19 from libc.stdint cimport *
20 from libc.stdlib cimport malloc, realloc, free
27 from collections.abc import Callable
29 from collections import Callable
30 from datetime import datetime
31 from functools import partial, wraps
32 from itertools import chain
34 # Are we running Python 2.x
35 if sys.version_info[0] < 3:
41 cdef extern from "Python.h":
42 # These are in cpython/string.pxd, but use "object" types instead of
43 # PyObject*, which invokes assumptions in cpython that we need to
44 # legitimately break to implement zero-copy string buffers in Ioctx.read().
45 # This is valid use of the Python API and documented as a special case.
46 PyObject *PyBytes_FromStringAndSize(char *v, Py_ssize_t len) except NULL
47 char* PyBytes_AsString(PyObject *string) except NULL
48 int _PyBytes_Resize(PyObject **string, Py_ssize_t newsize) except -1
49 void PyEval_InitThreads()
52 cdef extern from "time.h":
53 ctypedef long int time_t
54 ctypedef long int suseconds_t
57 cdef extern from "sys/time.h":
63 cdef extern from "rados/rados_types.h" nogil:
64 cdef char* _LIBRADOS_ALL_NSPACES "LIBRADOS_ALL_NSPACES"
67 cdef extern from "rados/librados.h" nogil:
69 _LIBRADOS_OP_FLAG_EXCL "LIBRADOS_OP_FLAG_EXCL"
70 _LIBRADOS_OP_FLAG_FAILOK "LIBRADOS_OP_FLAG_FAILOK"
71 _LIBRADOS_OP_FLAG_FADVISE_RANDOM "LIBRADOS_OP_FLAG_FADVISE_RANDOM"
72 _LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL "LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL"
73 _LIBRADOS_OP_FLAG_FADVISE_WILLNEED "LIBRADOS_OP_FLAG_FADVISE_WILLNEED"
74 _LIBRADOS_OP_FLAG_FADVISE_DONTNEED "LIBRADOS_OP_FLAG_FADVISE_DONTNEED"
75 _LIBRADOS_OP_FLAG_FADVISE_NOCACHE "LIBRADOS_OP_FLAG_FADVISE_NOCACHE"
79 _LIBRADOS_OPERATION_NOFLAG "LIBRADOS_OPERATION_NOFLAG"
80 _LIBRADOS_OPERATION_BALANCE_READS "LIBRADOS_OPERATION_BALANCE_READS"
81 _LIBRADOS_OPERATION_LOCALIZE_READS "LIBRADOS_OPERATION_LOCALIZE_READS"
82 _LIBRADOS_OPERATION_ORDER_READS_WRITES "LIBRADOS_OPERATION_ORDER_READS_WRITES"
83 _LIBRADOS_OPERATION_IGNORE_CACHE "LIBRADOS_OPERATION_IGNORE_CACHE"
84 _LIBRADOS_OPERATION_SKIPRWLOCKS "LIBRADOS_OPERATION_SKIPRWLOCKS"
85 _LIBRADOS_OPERATION_IGNORE_OVERLAY "LIBRADOS_OPERATION_IGNORE_OVERLAY"
86 _LIBRADOS_CREATE_EXCLUSIVE "LIBRADOS_CREATE_EXCLUSIVE"
87 _LIBRADOS_CREATE_IDEMPOTENT "LIBRADOS_CREATE_IDEMPOTENT"
89 cdef uint64_t _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
91 ctypedef void* rados_xattrs_iter_t
92 ctypedef void* rados_omap_iter_t
93 ctypedef void* rados_list_ctx_t
94 ctypedef uint64_t rados_snap_t
95 ctypedef void *rados_write_op_t
96 ctypedef void *rados_read_op_t
97 ctypedef void *rados_completion_t
98 ctypedef void (*rados_callback_t)(rados_completion_t cb, void *arg)
99 ctypedef void (*rados_log_callback_t)(void *arg, const char *line, const char *who,
100 uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg)
101 ctypedef void (*rados_log_callback2_t)(void *arg, const char *line, const char *channel, const char *who, const char *name,
102 uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg)
105 cdef struct rados_cluster_stat_t:
111 cdef struct rados_pool_stat_t:
115 uint64_t num_object_clones
116 uint64_t num_object_copies
117 uint64_t num_objects_missing_on_primary
118 uint64_t num_objects_unfound
119 uint64_t num_objects_degraded
125 void rados_buffer_free(char *buf)
127 void rados_version(int *major, int *minor, int *extra)
128 int rados_create2(rados_t *pcluster, const char *const clustername,
129 const char * const name, uint64_t flags)
130 int rados_create_with_context(rados_t *cluster, rados_config_t cct)
131 int rados_connect(rados_t cluster)
132 void rados_shutdown(rados_t cluster)
133 uint64_t rados_get_instance_id(rados_t cluster)
134 int rados_conf_read_file(rados_t cluster, const char *path)
135 int rados_conf_parse_argv_remainder(rados_t cluster, int argc, const char **argv, const char **remargv)
136 int rados_conf_parse_env(rados_t cluster, const char *var)
137 int rados_conf_set(rados_t cluster, char *option, const char *value)
138 int rados_conf_get(rados_t cluster, char *option, char *buf, size_t len)
140 int rados_ioctx_pool_stat(rados_ioctx_t io, rados_pool_stat_t *stats)
141 int64_t rados_pool_lookup(rados_t cluster, const char *pool_name)
142 int rados_pool_reverse_lookup(rados_t cluster, int64_t id, char *buf, size_t maxlen)
143 int rados_pool_create(rados_t cluster, const char *pool_name)
144 int rados_pool_create_with_crush_rule(rados_t cluster, const char *pool_name, uint8_t crush_rule_num)
145 int rados_pool_create_with_auid(rados_t cluster, const char *pool_name, uint64_t auid)
146 int rados_pool_create_with_all(rados_t cluster, const char *pool_name, uint64_t auid, uint8_t crush_rule_num)
147 int rados_pool_get_base_tier(rados_t cluster, int64_t pool, int64_t *base_tier)
148 int rados_pool_list(rados_t cluster, char *buf, size_t len)
149 int rados_pool_delete(rados_t cluster, const char *pool_name)
150 int rados_inconsistent_pg_list(rados_t cluster, int64_t pool, char *buf, size_t len)
152 int rados_cluster_stat(rados_t cluster, rados_cluster_stat_t *result)
153 int rados_cluster_fsid(rados_t cluster, char *buf, size_t len)
154 int rados_blacklist_add(rados_t cluster, char *client_address, uint32_t expire_seconds)
155 int rados_getaddrs(rados_t cluster, char** addrs)
156 int rados_application_enable(rados_ioctx_t io, const char *app_name,
158 void rados_set_osdmap_full_try(rados_ioctx_t io)
159 void rados_unset_osdmap_full_try(rados_ioctx_t io)
160 int rados_application_list(rados_ioctx_t io, char *values,
162 int rados_application_metadata_get(rados_ioctx_t io, const char *app_name,
163 const char *key, char *value,
165 int rados_application_metadata_set(rados_ioctx_t io, const char *app_name,
166 const char *key, const char *value)
167 int rados_application_metadata_remove(rados_ioctx_t io,
168 const char *app_name, const char *key)
169 int rados_application_metadata_list(rados_ioctx_t io,
170 const char *app_name, char *keys,
171 size_t *key_len, char *values,
173 int rados_ping_monitor(rados_t cluster, const char *mon_id, char **outstr, size_t *outstrlen)
174 int rados_mon_command(rados_t cluster, const char **cmd, size_t cmdlen,
175 const char *inbuf, size_t inbuflen,
176 char **outbuf, size_t *outbuflen,
177 char **outs, size_t *outslen)
178 int rados_mgr_command(rados_t cluster, const char **cmd, size_t cmdlen,
179 const char *inbuf, size_t inbuflen,
180 char **outbuf, size_t *outbuflen,
181 char **outs, size_t *outslen)
182 int rados_mgr_command_target(rados_t cluster,
184 const char **cmd, size_t cmdlen,
185 const char *inbuf, size_t inbuflen,
186 char **outbuf, size_t *outbuflen,
187 char **outs, size_t *outslen)
188 int rados_mon_command_target(rados_t cluster, const char *name, const char **cmd, size_t cmdlen,
189 const char *inbuf, size_t inbuflen,
190 char **outbuf, size_t *outbuflen,
191 char **outs, size_t *outslen)
192 int rados_osd_command(rados_t cluster, int osdid, const char **cmd, size_t cmdlen,
193 const char *inbuf, size_t inbuflen,
194 char **outbuf, size_t *outbuflen,
195 char **outs, size_t *outslen)
196 int rados_pg_command(rados_t cluster, const char *pgstr, const char **cmd, size_t cmdlen,
197 const char *inbuf, size_t inbuflen,
198 char **outbuf, size_t *outbuflen,
199 char **outs, size_t *outslen)
200 int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg)
201 int rados_monitor_log2(rados_t cluster, const char *level, rados_log_callback2_t cb, void *arg)
203 int rados_wait_for_latest_osdmap(rados_t cluster)
205 int rados_service_register(rados_t cluster, const char *service, const char *daemon, const char *metadata_dict)
206 int rados_service_update_status(rados_t cluster, const char *status_dict)
208 int rados_ioctx_create(rados_t cluster, const char *pool_name, rados_ioctx_t *ioctx)
209 int rados_ioctx_create2(rados_t cluster, int64_t pool_id, rados_ioctx_t *ioctx)
210 void rados_ioctx_destroy(rados_ioctx_t io)
211 void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key)
212 void rados_ioctx_set_namespace(rados_ioctx_t io, const char * nspace)
214 uint64_t rados_get_last_version(rados_ioctx_t io)
215 int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime)
216 int rados_write(rados_ioctx_t io, const char *oid, const char *buf, size_t len, uint64_t off)
217 int rados_write_full(rados_ioctx_t io, const char *oid, const char *buf, size_t len)
218 int rados_writesame(rados_ioctx_t io, const char *oid, const char *buf, size_t data_len, size_t write_len, uint64_t off)
219 int rados_append(rados_ioctx_t io, const char *oid, const char *buf, size_t len)
220 int rados_read(rados_ioctx_t io, const char *oid, char *buf, size_t len, uint64_t off)
221 int rados_remove(rados_ioctx_t io, const char *oid)
222 int rados_trunc(rados_ioctx_t io, const char *oid, uint64_t size)
223 int rados_getxattr(rados_ioctx_t io, const char *o, const char *name, char *buf, size_t len)
224 int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len)
225 int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name)
226 int rados_getxattrs(rados_ioctx_t io, const char *oid, rados_xattrs_iter_t *iter)
227 int rados_getxattrs_next(rados_xattrs_iter_t iter, const char **name, const char **val, size_t *len)
228 void rados_getxattrs_end(rados_xattrs_iter_t iter)
230 int rados_nobjects_list_open(rados_ioctx_t io, rados_list_ctx_t *ctx)
231 int rados_nobjects_list_next(rados_list_ctx_t ctx, const char **entry, const char **key, const char **nspace)
232 void rados_nobjects_list_close(rados_list_ctx_t ctx)
234 int rados_ioctx_pool_requires_alignment2(rados_ioctx_t io, int * requires)
235 int rados_ioctx_pool_required_alignment2(rados_ioctx_t io, uint64_t * alignment)
237 int rados_ioctx_snap_rollback(rados_ioctx_t io, const char * oid, const char * snapname)
238 int rados_ioctx_snap_create(rados_ioctx_t io, const char * snapname)
239 int rados_ioctx_snap_remove(rados_ioctx_t io, const char * snapname)
240 int rados_ioctx_snap_lookup(rados_ioctx_t io, const char * name, rados_snap_t * id)
241 int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char * name, int maxlen)
242 void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t snap)
243 int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t * snaps, int maxlen)
244 int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t * t)
245 uint64_t rados_ioctx_get_id(rados_ioctx_t io)
246 int rados_ioctx_get_pool_name(rados_ioctx_t io, char *buf, unsigned maxlen)
248 int rados_ioctx_selfmanaged_snap_create(rados_ioctx_t io,
249 rados_snap_t *snapid)
250 int rados_ioctx_selfmanaged_snap_remove(rados_ioctx_t io,
252 int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io,
253 rados_snap_t snap_seq,
256 int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io, const char *oid,
259 int rados_lock_exclusive(rados_ioctx_t io, const char * oid, const char * name,
260 const char * cookie, const char * desc,
261 timeval * duration, uint8_t flags)
262 int rados_lock_shared(rados_ioctx_t io, const char * o, const char * name,
263 const char * cookie, const char * tag, const char * desc,
264 timeval * duration, uint8_t flags)
265 int rados_unlock(rados_ioctx_t io, const char * o, const char * name, const char * cookie)
267 rados_write_op_t rados_create_write_op()
268 void rados_release_write_op(rados_write_op_t write_op)
270 rados_read_op_t rados_create_read_op()
271 void rados_release_read_op(rados_read_op_t read_op)
273 int rados_aio_create_completion2(void * cb_arg, rados_callback_t cb_complete, rados_completion_t * pc)
274 void rados_aio_release(rados_completion_t c)
275 int rados_aio_stat(rados_ioctx_t io, const char *oid, rados_completion_t completion, uint64_t *psize, time_t *pmtime)
276 int rados_aio_write(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len, uint64_t off)
277 int rados_aio_append(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len)
278 int rados_aio_write_full(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len)
279 int rados_aio_writesame(rados_ioctx_t io, const char *oid, rados_completion_t completion, const char *buf, size_t data_len, size_t write_len, uint64_t off)
280 int rados_aio_remove(rados_ioctx_t io, const char * oid, rados_completion_t completion)
281 int rados_aio_read(rados_ioctx_t io, const char * oid, rados_completion_t completion, char * buf, size_t len, uint64_t off)
282 int rados_aio_flush(rados_ioctx_t io)
284 int rados_aio_get_return_value(rados_completion_t c)
285 int rados_aio_wait_for_complete_and_cb(rados_completion_t c)
286 int rados_aio_wait_for_complete(rados_completion_t c)
287 int rados_aio_is_complete(rados_completion_t c)
289 int rados_exec(rados_ioctx_t io, const char * oid, const char * cls, const char * method,
290 const char * in_buf, size_t in_len, char * buf, size_t out_len)
291 int rados_aio_exec(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * cls, const char * method,
292 const char * in_buf, size_t in_len, char * buf, size_t out_len)
294 int rados_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, const char * oid, time_t * mtime, int flags)
295 int rados_aio_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, time_t *mtime, int flags)
296 void rados_write_op_omap_set(rados_write_op_t write_op, const char * const* keys, const char * const* vals, const size_t * lens, size_t num)
297 void rados_write_op_omap_rm_keys(rados_write_op_t write_op, const char * const* keys, size_t keys_len)
298 void rados_write_op_omap_clear(rados_write_op_t write_op)
299 void rados_write_op_set_flags(rados_write_op_t write_op, int flags)
300 void rados_write_op_setxattr(rados_write_op_t write_op, const char *name, const char *value, size_t value_len)
301 void rados_write_op_rmxattr(rados_write_op_t write_op, const char *name)
303 void rados_write_op_create(rados_write_op_t write_op, int exclusive, const char *category)
304 void rados_write_op_append(rados_write_op_t write_op, const char *buffer, size_t len)
305 void rados_write_op_write_full(rados_write_op_t write_op, const char *buffer, size_t len)
306 void rados_write_op_assert_version(rados_write_op_t write_op, uint64_t ver)
307 void rados_write_op_write(rados_write_op_t write_op, const char *buffer, size_t len, uint64_t offset)
308 void rados_write_op_remove(rados_write_op_t write_op)
309 void rados_write_op_truncate(rados_write_op_t write_op, uint64_t offset)
310 void rados_write_op_zero(rados_write_op_t write_op, uint64_t offset, uint64_t len)
311 void rados_write_op_exec(rados_write_op_t write_op, const char *cls, const char *method, const char *in_buf, size_t in_len, int *prval)
312 void rados_write_op_writesame(rados_write_op_t write_op, const char *buffer, size_t data_len, size_t write_len, uint64_t offset)
313 void rados_read_op_omap_get_vals2(rados_read_op_t read_op, const char * start_after, const char * filter_prefix, uint64_t max_return, rados_omap_iter_t * iter, unsigned char *pmore, int * prval)
314 void rados_read_op_omap_get_keys2(rados_read_op_t read_op, const char * start_after, uint64_t max_return, rados_omap_iter_t * iter, unsigned char *pmore, int * prval)
315 void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op, const char * const* keys, size_t keys_len, rados_omap_iter_t * iter, int * prval)
316 int rados_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, const char * oid, int flags)
317 int rados_aio_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, int flags)
318 void rados_read_op_set_flags(rados_read_op_t read_op, int flags)
319 int rados_omap_get_next(rados_omap_iter_t iter, const char * const* key, const char * const* val, size_t * len)
320 void rados_omap_get_end(rados_omap_iter_t iter)
321 int rados_notify2(rados_ioctx_t io, const char * o, const char *buf, int buf_len, uint64_t timeout_ms, char **reply_buffer, size_t *reply_buffer_len)
324 LIBRADOS_OP_FLAG_EXCL = _LIBRADOS_OP_FLAG_EXCL
325 LIBRADOS_OP_FLAG_FAILOK = _LIBRADOS_OP_FLAG_FAILOK
326 LIBRADOS_OP_FLAG_FADVISE_RANDOM = _LIBRADOS_OP_FLAG_FADVISE_RANDOM
327 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL = _LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
328 LIBRADOS_OP_FLAG_FADVISE_WILLNEED = _LIBRADOS_OP_FLAG_FADVISE_WILLNEED
329 LIBRADOS_OP_FLAG_FADVISE_DONTNEED = _LIBRADOS_OP_FLAG_FADVISE_DONTNEED
330 LIBRADOS_OP_FLAG_FADVISE_NOCACHE = _LIBRADOS_OP_FLAG_FADVISE_NOCACHE
332 LIBRADOS_SNAP_HEAD = _LIBRADOS_SNAP_HEAD
334 LIBRADOS_OPERATION_NOFLAG = _LIBRADOS_OPERATION_NOFLAG
335 LIBRADOS_OPERATION_BALANCE_READS = _LIBRADOS_OPERATION_BALANCE_READS
336 LIBRADOS_OPERATION_LOCALIZE_READS = _LIBRADOS_OPERATION_LOCALIZE_READS
337 LIBRADOS_OPERATION_ORDER_READS_WRITES = _LIBRADOS_OPERATION_ORDER_READS_WRITES
338 LIBRADOS_OPERATION_IGNORE_CACHE = _LIBRADOS_OPERATION_IGNORE_CACHE
339 LIBRADOS_OPERATION_SKIPRWLOCKS = _LIBRADOS_OPERATION_SKIPRWLOCKS
340 LIBRADOS_OPERATION_IGNORE_OVERLAY = _LIBRADOS_OPERATION_IGNORE_OVERLAY
342 LIBRADOS_ALL_NSPACES = _LIBRADOS_ALL_NSPACES.decode('utf-8')
344 LIBRADOS_CREATE_EXCLUSIVE = _LIBRADOS_CREATE_EXCLUSIVE
345 LIBRADOS_CREATE_IDEMPOTENT = _LIBRADOS_CREATE_IDEMPOTENT
347 ANONYMOUS_AUID = 0xffffffffffffffff
351 class Error(Exception):
352 """ `Error` class, derived from `Exception` """
353 def __init__(self, message, errno=None):
354 super(Exception, self).__init__(message)
358 msg = super(Exception, self).__str__()
359 if self.errno is None:
361 return '[errno {0}] {1}'.format(self.errno, msg)
363 def __reduce__(self):
364 return (self.__class__, (self.message, self.errno))
366 class InvalidArgumentError(Error):
367 def __init__(self, message, errno=None):
368 super(InvalidArgumentError, self).__init__(
369 "RADOS invalid argument (%s)" % message, errno)
372 class OSError(Error):
373 """ `OSError` class, derived from `Error` """
376 class InterruptedOrTimeoutError(OSError):
377 """ `InterruptedOrTimeoutError` class, derived from `OSError` """
378 def __init__(self, message, errno=None):
379 super(InterruptedOrTimeoutError, self).__init__(
380 "RADOS interrupted or timeout (%s)" % message, errno)
383 class PermissionError(OSError):
384 """ `PermissionError` class, derived from `OSError` """
385 def __init__(self, message, errno=None):
386 super(PermissionError, self).__init__(
387 "RADOS permission error (%s)" % message, errno)
390 class PermissionDeniedError(OSError):
391 """ deal with EACCES related. """
392 def __init__(self, message, errno=None):
393 super(PermissionDeniedError, self).__init__(
394 "RADOS permission denied (%s)" % message, errno)
397 class ObjectNotFound(OSError):
398 """ `ObjectNotFound` class, derived from `OSError` """
399 def __init__(self, message, errno=None):
400 super(ObjectNotFound, self).__init__(
401 "RADOS object not found (%s)" % message, errno)
404 class NoData(OSError):
405 """ `NoData` class, derived from `OSError` """
406 def __init__(self, message, errno=None):
407 super(NoData, self).__init__(
408 "RADOS no data (%s)" % message, errno)
411 class ObjectExists(OSError):
412 """ `ObjectExists` class, derived from `OSError` """
413 def __init__(self, message, errno=None):
414 super(ObjectExists, self).__init__(
415 "RADOS object exists (%s)" % message, errno)
418 class ObjectBusy(OSError):
419 """ `ObjectBusy` class, derived from `IOError` """
420 def __init__(self, message, errno=None):
421 super(ObjectBusy, self).__init__(
422 "RADOS object busy (%s)" % message, errno)
425 class IOError(OSError):
426 """ `ObjectBusy` class, derived from `OSError` """
427 def __init__(self, message, errno=None):
428 super(IOError, self).__init__(
429 "RADOS I/O error (%s)" % message, errno)
432 class NoSpace(OSError):
433 """ `NoSpace` class, derived from `OSError` """
434 def __init__(self, message, errno=None):
435 super(NoSpace, self).__init__(
436 "RADOS no space (%s)" % message, errno)
439 class RadosStateError(Error):
440 """ `RadosStateError` class, derived from `Error` """
441 def __init__(self, message, errno=None):
442 super(RadosStateError, self).__init__(
443 "RADOS rados state (%s)" % message, errno)
446 class IoctxStateError(Error):
447 """ `IoctxStateError` class, derived from `Error` """
448 def __init__(self, message, errno=None):
449 super(IoctxStateError, self).__init__(
450 "RADOS Ioctx state error (%s)" % message, errno)
453 class ObjectStateError(Error):
454 """ `ObjectStateError` class, derived from `Error` """
455 def __init__(self, message, errno=None):
456 super(ObjectStateError, self).__init__(
457 "RADOS object state error (%s)" % message, errno)
460 class LogicError(Error):
461 """ `` class, derived from `Error` """
462 def __init__(self, message, errno=None):
463 super(LogicError, self).__init__(
464 "RADOS logic error (%s)" % message, errno)
467 class TimedOut(OSError):
468 """ `TimedOut` class, derived from `OSError` """
469 def __init__(self, message, errno=None):
470 super(TimedOut, self).__init__(
471 "RADOS timed out (%s)" % message, errno)
474 class InProgress(Error):
475 """ `InProgress` class, derived from `Error` """
476 def __init__(self, message, errno=None):
477 super(InProgress, self).__init__(
478 "RADOS in progress error (%s)" % message, errno)
481 class IsConnected(Error):
482 """ `IsConnected` class, derived from `Error` """
483 def __init__(self, message, errno=None):
484 super(IsConnected, self).__init__(
485 "RADOS is connected error (%s)" % message, errno)
488 IF UNAME_SYSNAME == "FreeBSD":
489 cdef errno_to_exception = {
490 errno.EPERM : PermissionError,
491 errno.ENOENT : ObjectNotFound,
493 errno.ENOSPC : NoSpace,
494 errno.EEXIST : ObjectExists,
495 errno.EBUSY : ObjectBusy,
496 errno.ENOATTR : NoData,
497 errno.EINTR : InterruptedOrTimeoutError,
498 errno.ETIMEDOUT : TimedOut,
499 errno.EACCES : PermissionDeniedError,
500 errno.EINPROGRESS : InProgress,
501 errno.EISCONN : IsConnected,
502 errno.EINVAL : InvalidArgumentError,
505 cdef errno_to_exception = {
506 errno.EPERM : PermissionError,
507 errno.ENOENT : ObjectNotFound,
509 errno.ENOSPC : NoSpace,
510 errno.EEXIST : ObjectExists,
511 errno.EBUSY : ObjectBusy,
512 errno.ENODATA : NoData,
513 errno.EINTR : InterruptedOrTimeoutError,
514 errno.ETIMEDOUT : TimedOut,
515 errno.EACCES : PermissionDeniedError,
516 errno.EINPROGRESS : InProgress,
517 errno.EISCONN : IsConnected,
518 errno.EINVAL : InvalidArgumentError,
522 cdef make_ex(ret, msg):
524 Translate a librados return code into an exception.
526 :param ret: the return code
528 :param msg: the error message to use
530 :returns: a subclass of :class:`Error`
533 if ret in errno_to_exception:
534 return errno_to_exception[ret](msg, errno=ret)
536 return OSError(msg, errno=ret)
539 # helper to specify an optional argument, where in addition to `cls`, `None`
545 # validate argument types of an instance method
546 # kwargs is an un-ordered dict, so use args instead
547 def requires(*types):
548 def is_type_of(v, t):
552 return isinstance(v, t)
554 def check_type(val, arg_name, arg_type):
555 if isinstance(arg_type, tuple):
556 if any(is_type_of(val, t) for t in arg_type):
558 type_names = ' or '.join('None' if t is None else t.__name__
560 raise TypeError('%s must be %s' % (arg_name, type_names))
562 if is_type_of(val, arg_type):
564 assert(arg_type is not None)
565 raise TypeError('%s must be %s' % (arg_name, arg_type.__name__))
568 # FIXME(sileht): this stop with
569 # AttributeError: 'method_descriptor' object has no attribute '__module__'
571 def validate_func(*args, **kwargs):
572 # ignore the `self` arg
573 pos_args = zip(args[1:], types)
574 named_args = ((kwargs[name], (name, spec)) for name, spec in types
576 for arg_val, (arg_name, arg_type) in chain(pos_args, named_args):
577 check_type(arg_val, arg_name, arg_type)
578 return f(*args, **kwargs)
583 def cstr(val, name, encoding="utf-8", opt=False):
585 Create a byte string from a Python string
587 :param basestring val: Python string
588 :param str name: Name of the string parameter, for exceptions
589 :param str encoding: Encoding to use
590 :param bool opt: If True, None is allowed
592 :raises: :class:`InvalidArgument`
594 if opt and val is None:
596 if isinstance(val, bytes):
598 elif isinstance(val, unicode):
599 return val.encode(encoding)
601 raise TypeError('%s must be a string' % name)
604 def cstr_list(list_str, name, encoding="utf-8"):
605 return [cstr(s, name) for s in list_str]
608 def decode_cstr(val, encoding="utf-8"):
610 Decode a byte string into a Python string.
612 :param bytes val: byte string
613 :rtype: unicode or None
618 return val.decode(encoding)
621 def flatten_dict(d, name):
622 items = chain.from_iterable(d.items())
623 return cstr(''.join(i + '\0' for i in items), name)
626 cdef char* opt_str(s) except? NULL:
632 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
633 cdef void *ret = realloc(ptr, size)
635 raise MemoryError("realloc failed")
639 cdef size_t * to_csize_t_array(list_int):
640 cdef size_t *ret = <size_t *>malloc(len(list_int) * sizeof(size_t))
642 raise MemoryError("malloc failed")
643 for i in range(len(list_int)):
644 ret[i] = <size_t>list_int[i]
648 cdef char ** to_bytes_array(list_bytes):
649 cdef char **ret = <char **>malloc(len(list_bytes) * sizeof(char *))
651 raise MemoryError("malloc failed")
652 for i in range(len(list_bytes)):
653 ret[i] = <char *>list_bytes[i]
658 cdef int __monitor_callback(void *arg, const char *line, const char *who,
659 uint64_t sec, uint64_t nsec, uint64_t seq,
660 const char *level, const char *msg) with gil:
661 cdef object cb_info = <object>arg
662 cb_info[0](cb_info[1], line, who, sec, nsec, seq, level, msg)
665 cdef int __monitor_callback2(void *arg, const char *line, const char *channel,
668 uint64_t sec, uint64_t nsec, uint64_t seq,
669 const char *level, const char *msg) with gil:
670 cdef object cb_info = <object>arg
671 cb_info[0](cb_info[1], line, channel, name, who, sec, nsec, seq, level, msg)
675 class Version(object):
676 """ Version information """
677 def __init__(self, major, minor, extra):
683 return "%d.%d.%d" % (self.major, self.minor, self.extra)
686 cdef class Rados(object):
687 """This class wraps librados functions"""
688 # NOTE(sileht): attributes declared in .pyd
690 def __init__(self, *args, **kwargs):
692 self.__setup(*args, **kwargs)
695 "special value that indicates no conffile should be read when creating a mount handle"
696 DEFAULT_CONF_FILES = -2
697 "special value that indicates the default conffiles should be read when creating a mount handle"
699 @requires(('rados_id', opt(str_type)), ('name', opt(str_type)),
700 ('clustername', opt(str_type)), ('conffile', (str_type, int)))
701 def __setup(self, rados_id=None, name=None, clustername=None,
702 conf_defaults=None, conffile=NO_CONF_FILE, conf=None, flags=0,
704 self.monitor_callback = None
705 self.monitor_callback2 = None
706 self.parsed_args = []
707 self.conf_defaults = conf_defaults
708 self.conffile = conffile
709 self.rados_id = rados_id
711 if rados_id and name:
712 raise Error("Rados(): can't supply both rados_id and name")
714 name = 'client.' + rados_id
716 name = 'client.admin'
717 if clustername is None:
720 name = cstr(name, 'name')
721 clustername = cstr(clustername, 'clustername')
724 char *_clustername = clustername
729 # Unpack void* (aka rados_config_t) from capsule
730 rados_config = <rados_config_t> PyCapsule_GetPointer(context, NULL)
732 ret = rados_create_with_context(&self.cluster, rados_config)
735 ret = rados_create2(&self.cluster, _clustername, _name, _flags)
737 raise Error("rados_initialize failed with error code: %d" % ret)
739 self.state = "configuring"
740 # order is important: conf_defaults, then conffile, then conf
742 for key, value in conf_defaults.items():
743 self.conf_set(key, value)
744 if conffile in (self.NO_CONF_FILE, None):
746 elif conffile in (self.DEFAULT_CONF_FILES, ''):
747 self.conf_read_file(None)
749 self.conf_read_file(conffile)
751 for key, value in conf.items():
752 self.conf_set(key, value)
756 Get associated client addresses with this RADOS session.
758 self.require_state("configuring", "connected")
766 ret = rados_getaddrs(self.cluster, &addrs)
768 raise make_ex(ret, "error calling getaddrs")
770 return decode_cstr(addrs)
774 def require_state(self, *args):
776 Checks if the Rados object is in a special state
778 :raises: :class:`RadosStateError`
780 if self.state in args:
782 raise RadosStateError("You cannot perform that operation on a \
783 Rados object in state %s." % self.state)
787 Disconnects from the cluster. Call this explicitly when a
788 Rados.connect()ed object is no longer used.
790 if self.state != "shutdown":
792 rados_shutdown(self.cluster)
793 self.state = "shutdown"
799 def __exit__(self, type_, value, traceback):
805 Get the version number of the ``librados`` C library.
807 :returns: a tuple of ``(major, minor, extra)`` components of the
814 rados_version(&major, &minor, &extra)
815 return Version(major, minor, extra)
817 @requires(('path', opt(str_type)))
818 def conf_read_file(self, path=None):
820 Configure the cluster handle using a Ceph config file.
822 :param path: path to the config file
825 self.require_state("configuring", "connected")
826 path = cstr(path, 'path', opt=True)
828 char *_path = opt_str(path)
830 ret = rados_conf_read_file(self.cluster, _path)
832 raise make_ex(ret, "error calling conf_read_file")
834 def conf_parse_argv(self, args):
836 Parse known arguments from args, and remove; returned
837 args contain only those unknown to ceph
839 self.require_state("configuring", "connected")
843 cargs = cstr_list(args, 'args')
845 int _argc = len(args)
846 char **_argv = to_bytes_array(cargs)
847 char **_remargv = NULL
850 _remargv = <char **>malloc(_argc * sizeof(char *))
852 ret = rados_conf_parse_argv_remainder(self.cluster, _argc,
854 <const char**>_remargv)
856 raise make_ex(ret, "error calling conf_parse_argv_remainder")
858 # _remargv was allocated with fixed argc; collapse return
859 # list to eliminate any missing args
860 retargs = [decode_cstr(a) for a in _remargv[:_argc]
862 self.parsed_args = args
868 def conf_parse_env(self, var='CEPH_ARGS'):
870 Parse known arguments from an environment variable, normally
873 self.require_state("configuring", "connected")
877 var = cstr(var, 'var')
881 ret = rados_conf_parse_env(self.cluster, _var)
883 raise make_ex(ret, "error calling conf_parse_env")
885 @requires(('option', str_type))
886 def conf_get(self, option):
888 Get the value of a configuration option
890 :param option: which option to read
893 :returns: str - value of the option or None
894 :raises: :class:`TypeError`
896 self.require_state("configuring", "connected")
897 option = cstr(option, 'option')
899 char *_option = option
905 ret_buf = <char *>realloc_chk(ret_buf, length)
907 ret = rados_conf_get(self.cluster, _option, ret_buf, length)
909 return decode_cstr(ret_buf)
910 elif ret == -errno.ENAMETOOLONG:
912 elif ret == -errno.ENOENT:
915 raise make_ex(ret, "error calling conf_get")
919 @requires(('option', str_type), ('val', str_type))
920 def conf_set(self, option, val):
922 Set the value of a configuration option
924 :param option: which option to set
926 :param option: value of the option
929 :raises: :class:`TypeError`, :class:`ObjectNotFound`
931 self.require_state("configuring", "connected")
932 option = cstr(option, 'option')
933 val = cstr(val, 'val')
935 char *_option = option
939 ret = rados_conf_set(self.cluster, _option, _val)
941 raise make_ex(ret, "error calling conf_set")
943 def ping_monitor(self, mon_id):
945 Ping a monitor to assess liveness
947 May be used as a simply way to assess liveness, or to obtain
948 information about the monitor in a simple way even in the
951 :param mon_id: the ID portion of the monitor's name (i.e., mon.<ID>)
953 :returns: the string reply from the monitor
956 self.require_state("configuring", "connected")
958 mon_id = cstr(mon_id, 'mon_id')
960 char *_mon_id = mon_id
965 ret = rados_ping_monitor(self.cluster, _mon_id, &outstr, &outstrlen)
968 raise make_ex(ret, "error calling ping_monitor")
971 my_outstr = outstr[:outstrlen]
972 rados_buffer_free(outstr)
973 return decode_cstr(my_outstr)
975 def connect(self, timeout=0):
977 Connect to the cluster. Use shutdown() to release resources.
979 self.require_state("configuring")
980 # NOTE(sileht): timeout was supported by old python API,
981 # but this is not something available in C API, so ignore
982 # for now and remove it later
984 ret = rados_connect(self.cluster)
986 raise make_ex(ret, "error connecting to the cluster")
987 self.state = "connected"
989 def get_instance_id(self):
991 Get a global id for current instance
993 self.require_state("connected")
995 ret = rados_get_instance_id(self.cluster)
998 def get_cluster_stats(self):
1000 Read usage info about the cluster
1002 This tells you total space, space used, space available, and number
1003 of objects. These are not updated immediately when data is written,
1004 they are eventually consistent.
1006 :returns: dict - contains the following keys:
1008 - ``kb`` (int) - total space
1010 - ``kb_used`` (int) - space used
1012 - ``kb_avail`` (int) - free space available
1014 - ``num_objects`` (int) - number of objects
1018 rados_cluster_stat_t stats
1021 ret = rados_cluster_stat(self.cluster, &stats)
1025 ret, "Rados.get_cluster_stats(%s): get_stats failed" % self.rados_id)
1026 return {'kb': stats.kb,
1027 'kb_used': stats.kb_used,
1028 'kb_avail': stats.kb_avail,
1029 'num_objects': stats.num_objects}
1031 @requires(('pool_name', str_type))
1032 def pool_exists(self, pool_name):
1034 Checks if a given pool exists.
1036 :param pool_name: name of the pool to check
1037 :type pool_name: str
1039 :raises: :class:`TypeError`, :class:`Error`
1040 :returns: bool - whether the pool exists, false otherwise.
1042 self.require_state("connected")
1044 pool_name = cstr(pool_name, 'pool_name')
1046 char *_pool_name = pool_name
1049 ret = rados_pool_lookup(self.cluster, _pool_name)
1052 elif ret == -errno.ENOENT:
1055 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
1057 @requires(('pool_name', str_type))
1058 def pool_lookup(self, pool_name):
1060 Returns a pool's ID based on its name.
1062 :param pool_name: name of the pool to look up
1063 :type pool_name: str
1065 :raises: :class:`TypeError`, :class:`Error`
1066 :returns: int - pool ID, or None if it doesn't exist
1068 self.require_state("connected")
1069 pool_name = cstr(pool_name, 'pool_name')
1071 char *_pool_name = pool_name
1074 ret = rados_pool_lookup(self.cluster, _pool_name)
1077 elif ret == -errno.ENOENT:
1080 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
1082 @requires(('pool_id', int))
1083 def pool_reverse_lookup(self, pool_id):
1085 Returns a pool's name based on its ID.
1087 :param pool_id: ID of the pool to look up
1090 :raises: :class:`TypeError`, :class:`Error`
1091 :returns: string - pool name, or None if it doesn't exist
1093 self.require_state("connected")
1095 int64_t _pool_id = pool_id
1101 name = <char *>realloc_chk(name, size)
1103 ret = rados_pool_reverse_lookup(self.cluster, _pool_id, name, size)
1106 elif ret != -errno.ERANGE and size <= 4096:
1108 elif ret == -errno.ENOENT:
1111 raise make_ex(ret, "error reverse looking up pool '%s'" % pool_id)
1113 return decode_cstr(name)
1118 @requires(('pool_name', str_type), ('crush_rule', opt(int)), ('auid', opt(int)))
1119 def create_pool(self, pool_name, crush_rule=None, auid=None):
1122 - with default settings: if crush_rule=None and auid=None
1123 - with a specific CRUSH rule: crush_rule given
1124 - with a specific auid: auid given
1125 - with a specific CRUSH rule and auid: crush_rule and auid given
1127 :param pool_name: name of the pool to create
1128 :type pool_name: str
1129 :param crush_rule: rule to use for placement in the new pool
1130 :type crush_rule: int
1131 :param auid: id of the owner of the new pool
1134 :raises: :class:`TypeError`, :class:`Error`
1136 self.require_state("connected")
1138 pool_name = cstr(pool_name, 'pool_name')
1140 char *_pool_name = pool_name
1144 if crush_rule is None and auid is None:
1146 ret = rados_pool_create(self.cluster, _pool_name)
1147 elif crush_rule is not None and auid is None:
1148 _crush_rule = crush_rule
1150 ret = rados_pool_create_with_crush_rule(self.cluster, _pool_name, _crush_rule)
1151 elif crush_rule is None and auid is not None:
1154 ret = rados_pool_create_with_auid(self.cluster, _pool_name, _auid)
1156 _crush_rule = crush_rule
1159 ret = rados_pool_create_with_all(self.cluster, _pool_name, _auid, _crush_rule)
1161 raise make_ex(ret, "error creating pool '%s'" % pool_name)
1163 @requires(('pool_id', int))
1164 def get_pool_base_tier(self, pool_id):
1168 :returns: base pool, or pool_id if tiering is not configured for the pool
1170 self.require_state("connected")
1172 int64_t base_tier = 0
1173 int64_t _pool_id = pool_id
1176 ret = rados_pool_get_base_tier(self.cluster, _pool_id, &base_tier)
1178 raise make_ex(ret, "get_pool_base_tier(%d)" % pool_id)
1179 return int(base_tier)
1181 @requires(('pool_name', str_type))
1182 def delete_pool(self, pool_name):
1184 Delete a pool and all data inside it.
1186 The pool is removed from the cluster immediately,
1187 but the actual data is deleted in the background.
1189 :param pool_name: name of the pool to delete
1190 :type pool_name: str
1192 :raises: :class:`TypeError`, :class:`Error`
1194 self.require_state("connected")
1196 pool_name = cstr(pool_name, 'pool_name')
1198 char *_pool_name = pool_name
1201 ret = rados_pool_delete(self.cluster, _pool_name)
1203 raise make_ex(ret, "error deleting pool '%s'" % pool_name)
1205 @requires(('pool_id', int))
1206 def get_inconsistent_pgs(self, pool_id):
1208 List inconsistent placement groups in the given pool
1210 :param pool_id: ID of the pool in which PGs are listed
1212 :returns: list - inconsistent placement groups
1214 self.require_state("connected")
1216 int64_t pool = pool_id
1222 pgs = <char *>realloc_chk(pgs, size);
1224 ret = rados_inconsistent_pg_list(self.cluster, pool,
1231 raise make_ex(ret, "error calling inconsistent_pg_list")
1232 return [pg for pg in decode_cstr(pgs[:ret]).split('\0') if pg]
1236 def list_pools(self):
1238 Gets a list of pool names.
1240 :returns: list - of pool names.
1242 self.require_state("connected")
1245 char *c_names = NULL
1249 c_names = <char *>realloc_chk(c_names, size)
1251 ret = rados_pool_list(self.cluster, c_names, size)
1256 return [name for name in decode_cstr(c_names[:ret]).split('\0')
1263 Get the fsid of the cluster as a hexadecimal string.
1265 :raises: :class:`Error`
1266 :returns: str - cluster fsid
1268 self.require_state("connected")
1270 char *ret_buf = NULL
1275 ret_buf = <char *>realloc_chk(ret_buf, buf_len)
1277 ret = rados_cluster_fsid(self.cluster, ret_buf, buf_len)
1278 if ret == -errno.ERANGE:
1279 buf_len = buf_len * 2
1281 raise make_ex(ret, "error getting cluster fsid")
1284 return decode_cstr(ret_buf)
1288 @requires(('ioctx_name', str_type))
1289 def open_ioctx(self, ioctx_name):
1291 Create an io context
1293 The io context allows you to perform operations within a particular
1296 :param ioctx_name: name of the pool
1297 :type ioctx_name: str
1299 :raises: :class:`TypeError`, :class:`Error`
1300 :returns: Ioctx - Rados Ioctx object
1302 self.require_state("connected")
1303 ioctx_name = cstr(ioctx_name, 'ioctx_name')
1306 char *_ioctx_name = ioctx_name
1308 ret = rados_ioctx_create(self.cluster, _ioctx_name, &ioctx)
1310 raise make_ex(ret, "error opening pool '%s'" % ioctx_name)
1311 io = Ioctx(ioctx_name)
1315 @requires(('pool_id', int))
1316 def open_ioctx2(self, pool_id):
1318 Create an io context
1320 The io context allows you to perform operations within a particular
1323 :param pool_id: ID of the pool
1326 :raises: :class:`TypeError`, :class:`Error`
1327 :returns: Ioctx - Rados Ioctx object
1329 self.require_state("connected")
1332 int64_t _pool_id = pool_id
1334 ret = rados_ioctx_create2(self.cluster, _pool_id, &ioctx)
1336 raise make_ex(ret, "error opening pool id '%s'" % pool_id)
1337 io = Ioctx(str(pool_id))
1341 def mon_command(self, cmd, inbuf, timeout=0, target=None):
1343 Send a command to the mon.
1345 mon_command[_target](cmd, inbuf, outbuf, outbuflen, outs, outslen)
1347 :param cmd: JSON formatted string.
1348 :param inbuf: optional string.
1349 :param timeout: This parameter is ignored.
1350 :param target: name of a specific mon. Optional
1351 :return: (int ret, string outbuf, string outs)
1356 >>> c = Rados(conffile='/etc/ceph/ceph.conf')
1358 >>> cmd = json.dumps({"prefix": "osd safe-to-destroy", "ids": ["2"], "format": "json"})
1359 >>> c.mon_command(cmd, b'')
1361 # NOTE(sileht): timeout is ignored because C API doesn't provide
1362 # timeout argument, but we keep it for backward compat with old python binding
1364 self.require_state("connected")
1365 cmd = cstr_list(cmd, 'c')
1367 if isinstance(target, int):
1368 # NOTE(sileht): looks weird but test_monmap_dump pass int
1369 target = str(target)
1371 target = cstr(target, 'target', opt=True)
1372 inbuf = cstr(inbuf, 'inbuf')
1375 char *_target = opt_str(target)
1376 char **_cmd = to_bytes_array(cmd)
1377 size_t _cmdlen = len(cmd)
1379 char *_inbuf = inbuf
1380 size_t _inbuf_len = len(inbuf)
1390 ret = rados_mon_command_target(self.cluster, _target,
1391 <const char **>_cmd, _cmdlen,
1392 <const char*>_inbuf, _inbuf_len,
1393 &_outbuf, &_outbuf_len,
1397 ret = rados_mon_command(self.cluster,
1398 <const char **>_cmd, _cmdlen,
1399 <const char*>_inbuf, _inbuf_len,
1400 &_outbuf, &_outbuf_len,
1403 my_outs = decode_cstr(_outs[:_outs_len])
1404 my_outbuf = _outbuf[:_outbuf_len]
1406 rados_buffer_free(_outs)
1408 rados_buffer_free(_outbuf)
1409 return (ret, my_outbuf, my_outs)
1413 def osd_command(self, osdid, cmd, inbuf, timeout=0):
1415 osd_command(osdid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
1417 :return: (int ret, string outbuf, string outs)
1419 # NOTE(sileht): timeout is ignored because C API doesn't provide
1420 # timeout argument, but we keep it for backward compat with old python binding
1421 self.require_state("connected")
1423 cmd = cstr_list(cmd, 'cmd')
1424 inbuf = cstr(inbuf, 'inbuf')
1428 char **_cmd = to_bytes_array(cmd)
1429 size_t _cmdlen = len(cmd)
1431 char *_inbuf = inbuf
1432 size_t _inbuf_len = len(inbuf)
1441 ret = rados_osd_command(self.cluster, _osdid,
1442 <const char **>_cmd, _cmdlen,
1443 <const char*>_inbuf, _inbuf_len,
1444 &_outbuf, &_outbuf_len,
1447 my_outs = decode_cstr(_outs[:_outs_len])
1448 my_outbuf = _outbuf[:_outbuf_len]
1450 rados_buffer_free(_outs)
1452 rados_buffer_free(_outbuf)
1453 return (ret, my_outbuf, my_outs)
1457 def mgr_command(self, cmd, inbuf, timeout=0, target=None):
1459 :return: (int ret, string outbuf, string outs)
1461 # NOTE(sileht): timeout is ignored because C API doesn't provide
1462 # timeout argument, but we keep it for backward compat with old python binding
1463 self.require_state("connected")
1465 cmd = cstr_list(cmd, 'cmd')
1466 inbuf = cstr(inbuf, 'inbuf')
1467 target = cstr(target, 'target', opt=True)
1470 char *_target = opt_str(target)
1472 char **_cmd = to_bytes_array(cmd)
1473 size_t _cmdlen = len(cmd)
1475 char *_inbuf = inbuf
1476 size_t _inbuf_len = len(inbuf)
1484 if target is not None:
1486 ret = rados_mgr_command_target(self.cluster,
1487 <const char*>_target,
1488 <const char **>_cmd, _cmdlen,
1489 <const char*>_inbuf, _inbuf_len,
1490 &_outbuf, &_outbuf_len,
1494 ret = rados_mgr_command(self.cluster,
1495 <const char **>_cmd, _cmdlen,
1496 <const char*>_inbuf, _inbuf_len,
1497 &_outbuf, &_outbuf_len,
1500 my_outs = decode_cstr(_outs[:_outs_len])
1501 my_outbuf = _outbuf[:_outbuf_len]
1503 rados_buffer_free(_outs)
1505 rados_buffer_free(_outbuf)
1506 return (ret, my_outbuf, my_outs)
1510 def pg_command(self, pgid, cmd, inbuf, timeout=0):
1512 pg_command(pgid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
1514 :return: (int ret, string outbuf, string outs)
1516 # NOTE(sileht): timeout is ignored because C API doesn't provide
1517 # timeout argument, but we keep it for backward compat with old python binding
1518 self.require_state("connected")
1520 pgid = cstr(pgid, 'pgid')
1521 cmd = cstr_list(cmd, 'cmd')
1522 inbuf = cstr(inbuf, 'inbuf')
1526 char **_cmd = to_bytes_array(cmd)
1527 size_t _cmdlen = len(cmd)
1529 char *_inbuf = inbuf
1530 size_t _inbuf_len = len(inbuf)
1539 ret = rados_pg_command(self.cluster, _pgid,
1540 <const char **>_cmd, _cmdlen,
1541 <const char *>_inbuf, _inbuf_len,
1542 &_outbuf, &_outbuf_len,
1545 my_outs = decode_cstr(_outs[:_outs_len])
1546 my_outbuf = _outbuf[:_outbuf_len]
1548 rados_buffer_free(_outs)
1550 rados_buffer_free(_outbuf)
1551 return (ret, my_outbuf, my_outs)
1555 def wait_for_latest_osdmap(self):
1556 self.require_state("connected")
1558 ret = rados_wait_for_latest_osdmap(self.cluster)
1561 def blacklist_add(self, client_address, expire_seconds=0):
1563 Blacklist a client from the OSDs
1565 :param client_address: client address
1566 :type client_address: str
1567 :param expire_seconds: number of seconds to blacklist
1568 :type expire_seconds: int
1570 :raises: :class:`Error`
1572 self.require_state("connected")
1573 client_address = cstr(client_address, 'client_address')
1575 uint32_t _expire_seconds = expire_seconds
1576 char *_client_address = client_address
1579 ret = rados_blacklist_add(self.cluster, _client_address, _expire_seconds)
1581 raise make_ex(ret, "error blacklisting client '%s'" % client_address)
1583 def monitor_log(self, level, callback, arg):
1584 if level not in MONITOR_LEVELS:
1585 raise LogicError("invalid monitor level " + level)
1586 if callback is not None and not callable(callback):
1587 raise LogicError("callback must be a callable function or None")
1589 level = cstr(level, 'level')
1590 cdef char *_level = level
1592 if callback is None:
1594 r = rados_monitor_log(self.cluster, <const char*>_level, NULL, NULL)
1595 self.monitor_callback = None
1596 self.monitor_callback2 = None
1599 cb = (callback, arg)
1600 cdef PyObject* _arg = <PyObject*>cb
1602 r = rados_monitor_log(self.cluster, <const char*>_level,
1603 <rados_log_callback_t>&__monitor_callback, _arg)
1606 raise make_ex(r, 'error calling rados_monitor_log')
1607 # NOTE(sileht): Prevents the callback method from being garbage collected
1608 self.monitor_callback = cb
1609 self.monitor_callback2 = None
1611 def monitor_log2(self, level, callback, arg):
1612 if level not in MONITOR_LEVELS:
1613 raise LogicError("invalid monitor level " + level)
1614 if callback is not None and not callable(callback):
1615 raise LogicError("callback must be a callable function or None")
1617 level = cstr(level, 'level')
1618 cdef char *_level = level
1620 if callback is None:
1622 r = rados_monitor_log2(self.cluster, <const char*>_level, NULL, NULL)
1623 self.monitor_callback = None
1624 self.monitor_callback2 = None
1627 cb = (callback, arg)
1628 cdef PyObject* _arg = <PyObject*>cb
1630 r = rados_monitor_log2(self.cluster, <const char*>_level,
1631 <rados_log_callback2_t>&__monitor_callback2, _arg)
1634 raise make_ex(r, 'error calling rados_monitor_log')
1635 # NOTE(sileht): Prevents the callback method from being garbage collected
1636 self.monitor_callback = None
1637 self.monitor_callback2 = cb
1639 @requires(('service', str_type), ('daemon', str_type), ('metadata', dict))
1640 def service_daemon_register(self, service, daemon, metadata):
1642 :param str service: service name (e.g. "rgw")
1643 :param str daemon: daemon name (e.g. "gwfoo")
1644 :param dict metadata: static metadata about the register daemon
1645 (e.g., the version of Ceph, the kernel version.)
1647 service = cstr(service, 'service')
1648 daemon = cstr(daemon, 'daemon')
1649 metadata_dict = flatten_dict(metadata, 'metadata')
1651 char *_service = service
1652 char *_daemon = daemon
1653 char *_metadata = metadata_dict
1656 ret = rados_service_register(self.cluster, _service, _daemon, _metadata)
1658 raise make_ex(ret, "error calling service_register()")
1660 @requires(('metadata', dict))
1661 def service_daemon_update(self, status):
1662 status_dict = flatten_dict(status, 'status')
1664 char *_status = status_dict
1667 ret = rados_service_update_status(self.cluster, _status)
1669 raise make_ex(ret, "error calling service_daemon_update()")
1672 cdef class OmapIterator(object):
1675 cdef public Ioctx ioctx
1676 cdef rados_omap_iter_t ctx
1678 def __cinit__(self, Ioctx ioctx):
1686 Get the next key-value pair in the object
1687 :returns: next rados.OmapItem
1695 ret = rados_omap_get_next(self.ctx, &key_, &val_, &len_)
1698 raise make_ex(ret, "error iterating over the omap")
1700 raise StopIteration()
1701 key = decode_cstr(key_)
1707 def __dealloc__(self):
1709 rados_omap_get_end(self.ctx)
1712 cdef class ObjectIterator(object):
1713 """rados.Ioctx Object iterator"""
1715 cdef rados_list_ctx_t ctx
1717 cdef public object ioctx
1719 def __cinit__(self, Ioctx ioctx):
1723 ret = rados_nobjects_list_open(ioctx.io, &self.ctx)
1725 raise make_ex(ret, "error iterating over the objects in ioctx '%s'"
1733 Get the next object name and locator in the pool
1735 :raises: StopIteration
1736 :returns: next rados.Ioctx Object
1739 const char *key_ = NULL
1740 const char *locator_ = NULL
1741 const char *nspace_ = NULL
1744 ret = rados_nobjects_list_next(self.ctx, &key_, &locator_, &nspace_)
1747 raise StopIteration()
1749 key = decode_cstr(key_)
1750 locator = decode_cstr(locator_) if locator_ != NULL else None
1751 nspace = decode_cstr(nspace_) if nspace_ != NULL else None
1752 return Object(self.ioctx, key, locator, nspace)
1754 def __dealloc__(self):
1756 rados_nobjects_list_close(self.ctx)
1759 cdef class XattrIterator(object):
1760 """Extended attribute iterator"""
1762 cdef rados_xattrs_iter_t it
1765 cdef public Ioctx ioctx
1766 cdef public object oid
1768 def __cinit__(self, Ioctx ioctx, oid):
1770 self.oid = cstr(oid, 'oid')
1771 self._oid = self.oid
1774 ret = rados_getxattrs(ioctx.io, self._oid, &self.it)
1776 raise make_ex(ret, "Failed to get rados xattrs for object %r" % oid)
1783 Get the next xattr on the object
1785 :raises: StopIteration
1786 :returns: pair - of name and value of the next Xattr
1789 const char *name_ = NULL
1790 const char *val_ = NULL
1794 ret = rados_getxattrs_next(self.it, &name_, &val_, &len_)
1796 raise make_ex(ret, "error iterating over the extended attributes \
1797 in '%s'" % self.oid)
1799 raise StopIteration()
1800 name = decode_cstr(name_)
1804 def __dealloc__(self):
1806 rados_getxattrs_end(self.it)
1809 cdef class SnapIterator(object):
1810 """Snapshot iterator"""
1812 cdef public Ioctx ioctx
1814 cdef rados_snap_t *snaps
1818 def __cinit__(self, Ioctx ioctx):
1820 # We don't know how big a buffer we need until we've called the
1821 # function. So use the exponential doubling strategy.
1822 cdef int num_snaps = 10
1824 self.snaps = <rados_snap_t*>realloc_chk(self.snaps,
1826 sizeof(rados_snap_t))
1829 ret = rados_ioctx_snap_list(ioctx.io, self.snaps, num_snaps)
1833 elif ret != -errno.ERANGE:
1834 raise make_ex(ret, "error calling rados_snap_list for \
1835 ioctx '%s'" % self.ioctx.name)
1836 num_snaps = num_snaps * 2
1844 Get the next Snapshot
1846 :raises: :class:`Error`, StopIteration
1847 :returns: Snap - next snapshot
1849 if self.cur_snap >= self.max_snap:
1853 rados_snap_t snap_id = self.snaps[self.cur_snap]
1859 name = <char *>realloc_chk(name, name_len)
1861 ret = rados_ioctx_snap_get_name(self.ioctx.io, snap_id, name, name_len)
1864 elif ret != -errno.ERANGE:
1865 raise make_ex(ret, "rados_snap_get_name error")
1867 name_len = name_len * 2
1869 snap = Snap(self.ioctx, decode_cstr(name[:name_len]).rstrip('\0'), snap_id)
1870 self.cur_snap = self.cur_snap + 1
1876 cdef class Snap(object):
1877 """Snapshot object"""
1878 cdef public Ioctx ioctx
1879 cdef public object name
1881 # NOTE(sileht): old API was storing the ctypes object
1882 # instead of the value ....
1883 cdef public rados_snap_t snap_id
1885 def __cinit__(self, Ioctx ioctx, object name, rados_snap_t snap_id):
1888 self.snap_id = snap_id
1891 return "rados.Snap(ioctx=%s,name=%s,snap_id=%d)" \
1892 % (str(self.ioctx), self.name, self.snap_id)
1894 def get_timestamp(self):
1896 Find when a snapshot in the current pool occurred
1898 :raises: :class:`Error`
1899 :returns: datetime - the data and time the snapshot was created
1901 cdef time_t snap_time
1904 ret = rados_ioctx_snap_get_stamp(self.ioctx.io, self.snap_id, &snap_time)
1906 raise make_ex(ret, "rados_ioctx_snap_get_stamp error")
1907 return datetime.fromtimestamp(snap_time)
1910 cdef class Completion(object):
1911 """completion object"""
1919 rados_callback_t complete_cb
1920 rados_callback_t safe_cb
1921 rados_completion_t rados_comp
1924 def __cinit__(self, Ioctx ioctx, object oncomplete, object onsafe):
1925 self.oncomplete = oncomplete
1926 self.onsafe = onsafe
1931 Is an asynchronous operation safe?
1933 This does not imply that the safe callback has finished.
1935 :returns: True if the operation is safe
1937 return self.is_complete()
1939 def is_complete(self):
1941 Has an asynchronous operation completed?
1943 This does not imply that the safe callback has finished.
1945 :returns: True if the operation is completed
1948 ret = rados_aio_is_complete(self.rados_comp)
1951 def wait_for_safe(self):
1953 Wait for an asynchronous operation to be marked safe
1955 wait_for_safe() is an alias of wait_for_complete() since Luminous
1957 self.wait_for_complete()
1959 def wait_for_complete(self):
1961 Wait for an asynchronous operation to complete
1963 This does not imply that the complete callback has finished.
1966 rados_aio_wait_for_complete(self.rados_comp)
1968 def wait_for_safe_and_cb(self):
1970 Wait for an asynchronous operation to be marked safe and for
1971 the safe callback to have returned
1973 return self.wait_for_complete_and_cb()
1975 def wait_for_complete_and_cb(self):
1977 Wait for an asynchronous operation to complete and for the
1978 complete callback to have returned
1980 :returns: whether the operation is completed
1983 ret = rados_aio_wait_for_complete_and_cb(self.rados_comp)
1986 def get_return_value(self):
1988 Get the return value of an asychronous operation
1990 The return value is set when the operation is complete or safe,
1991 whichever comes first.
1993 :returns: int - return value of the operation
1996 ret = rados_aio_get_return_value(self.rados_comp)
1999 def __dealloc__(self):
2001 Release a completion
2003 Call this when you no longer need the completion. It may not be
2004 freed immediately if the operation is not acked and committed.
2006 ref.Py_XDECREF(self.buf)
2008 if self.rados_comp != NULL:
2010 rados_aio_release(self.rados_comp)
2011 self.rados_comp = NULL
2013 def _complete(self):
2014 self.oncomplete(self)
2020 with self.ioctx.lock:
2022 self.ioctx.complete_completions.remove(self)
2024 self.ioctx.safe_completions.remove(self)
2027 class OpCtx(object):
2028 def __enter__(self):
2029 return self.create()
2031 def __exit__(self, type, msg, traceback):
2035 cdef class WriteOp(object):
2036 cdef rados_write_op_t write_op
2040 self.write_op = rados_create_write_op()
2045 rados_release_write_op(self.write_op)
2047 @requires(('exclusive', opt(int)))
2048 def new(self, exclusive=None):
2054 int _exclusive = exclusive
2057 rados_write_op_create(self.write_op, _exclusive, NULL)
2065 rados_write_op_remove(self.write_op)
2067 @requires(('flags', int))
2068 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
2070 Set flags for the last operation added to this write_op.
2071 :para flags: flags to apply to the last operation
2079 rados_write_op_set_flags(self.write_op, _flags)
2081 @requires(('xattr_name', str_type), ('xattr_value', bytes))
2082 def set_xattr(self, xattr_name, xattr_value):
2084 Set an extended attribute on an object.
2085 :param xattr_name: name of the xattr
2086 :type xattr_name: str
2087 :param xattr_value: buffer to set xattr to
2088 :type xattr_value: bytes
2090 xattr_name = cstr(xattr_name, 'xattr_name')
2092 char *_xattr_name = xattr_name
2093 char *_xattr_value = xattr_value
2094 size_t _xattr_value_len = len(xattr_value)
2096 rados_write_op_setxattr(self.write_op, _xattr_name, _xattr_value, _xattr_value_len)
2098 @requires(('xattr_name', str_type))
2099 def rm_xattr(self, xattr_name):
2101 Removes an extended attribute on from an object.
2102 :param xattr_name: name of the xattr to remove
2103 :type xattr_name: str
2105 xattr_name = cstr(xattr_name, 'xattr_name')
2107 char *_xattr_name = xattr_name
2109 rados_write_op_rmxattr(self.write_op, _xattr_name)
2111 @requires(('to_write', bytes))
2112 def append(self, to_write):
2114 Append data to an object synchronously
2115 :param to_write: data to write
2116 :type to_write: bytes
2120 char *_to_write = to_write
2121 size_t length = len(to_write)
2124 rados_write_op_append(self.write_op, _to_write, length)
2126 @requires(('to_write', bytes))
2127 def write_full(self, to_write):
2129 Write whole object, atomically replacing it.
2130 :param to_write: data to write
2131 :type to_write: bytes
2135 char *_to_write = to_write
2136 size_t length = len(to_write)
2139 rados_write_op_write_full(self.write_op, _to_write, length)
2141 @requires(('to_write', bytes), ('offset', int))
2142 def write(self, to_write, offset=0):
2145 :param to_write: data to write
2146 :type to_write: bytes
2147 :param offset: byte offset in the object to begin writing at
2152 char *_to_write = to_write
2153 size_t length = len(to_write)
2154 uint64_t _offset = offset
2157 rados_write_op_write(self.write_op, _to_write, length, _offset)
2159 @requires(('version', int))
2160 def assert_version(self, version):
2162 Check if object's version is the expected one.
2163 :param version: expected version of the object
2167 uint64_t _version = version
2170 rados_write_op_assert_version(self.write_op, _version)
2172 @requires(('offset', int), ('length', int))
2173 def zero(self, offset, length):
2175 Zero part of an object.
2176 :param offset: byte offset in the object to begin writing at
2178 :param offset: number of zero to write
2183 size_t _length = length
2184 uint64_t _offset = offset
2187 rados_write_op_zero(self.write_op, _length, _offset)
2189 @requires(('offset', int))
2190 def truncate(self, offset):
2193 :param offset: byte offset in the object to begin truncating at
2198 uint64_t _offset = offset
2201 rados_write_op_truncate(self.write_op, _offset)
2203 @requires(('cls', str_type), ('method', str_type), ('data', bytes))
2204 def execute(self, cls, method, data):
2206 Execute an OSD class method on an object
2208 :param cls: name of the object class
2210 :param method: name of the method
2212 :param data: input data
2216 cls = cstr(cls, 'cls')
2217 method = cstr(method, 'method')
2220 char *_method = method
2222 size_t _data_len = len(data)
2225 rados_write_op_exec(self.write_op, _cls, _method, _data, _data_len, NULL)
2227 @requires(('to_write', bytes), ('write_len', int), ('offset', int))
2228 def writesame(self, to_write, write_len, offset=0):
2230 Write the same buffer multiple times
2231 :param to_write: data to write
2232 :type to_write: bytes
2233 :param write_len: total number of bytes to write
2235 :param offset: byte offset in the object to begin writing at
2239 char *_to_write = to_write
2240 size_t _data_len = len(to_write)
2241 size_t _write_len = write_len
2242 uint64_t _offset = offset
2244 rados_write_op_writesame(self.write_op, _to_write, _data_len, _write_len, _offset)
2246 class WriteOpCtx(WriteOp, OpCtx):
2247 """write operation context manager"""
2250 cdef class ReadOp(object):
2251 cdef rados_read_op_t read_op
2255 self.read_op = rados_create_read_op()
2260 rados_release_read_op(self.read_op)
2262 @requires(('flags', int))
2263 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
2265 Set flags for the last operation added to this read_op.
2266 :para flags: flags to apply to the last operation
2274 rados_read_op_set_flags(self.read_op, _flags)
2277 class ReadOpCtx(ReadOp, OpCtx):
2278 """read operation context manager"""
2281 cdef int __aio_complete_cb(rados_completion_t completion, void *args) with gil:
2283 Callback to oncomplete() for asynchronous operations
2285 cdef object cb = <object>args
2290 cdef class Ioctx(object):
2291 """rados.Ioctx object"""
2292 # NOTE(sileht): attributes declared in .pyd
2294 def __init__(self, name):
2298 self.locator_key = ""
2300 self.lock = threading.Lock()
2301 self.safe_completions = []
2302 self.complete_completions = []
2304 def __enter__(self):
2307 def __exit__(self, type_, value, traceback):
2311 def __dealloc__(self):
2314 def __track_completion(self, completion_obj):
2315 if completion_obj.oncomplete:
2317 self.complete_completions.append(completion_obj)
2318 if completion_obj.onsafe:
2320 self.safe_completions.append(completion_obj)
2322 def __get_completion(self, oncomplete, onsafe):
2324 Constructs a completion to use with asynchronous operations
2326 :param oncomplete: what to do when the write is safe and complete in memory
2328 :type oncomplete: completion
2329 :param onsafe: what to do when the write is safe and complete on storage
2331 :type onsafe: completion
2333 :raises: :class:`Error`
2334 :returns: completion object
2337 completion_obj = Completion(self, oncomplete, onsafe)
2340 rados_callback_t complete_cb = NULL
2341 rados_completion_t completion
2342 PyObject* p_completion_obj= <PyObject*>completion_obj
2345 complete_cb = <rados_callback_t>&__aio_complete_cb
2348 ret = rados_aio_create_completion2(p_completion_obj, complete_cb,
2351 raise make_ex(ret, "error getting a completion")
2353 completion_obj.rados_comp = completion
2354 return completion_obj
2356 @requires(('object_name', str_type), ('oncomplete', opt(Callable)))
2357 def aio_stat(self, object_name, oncomplete):
2359 Asynchronously get object stats (size/mtime)
2361 oncomplete will be called with the returned size and mtime
2362 as well as the completion:
2364 oncomplete(completion, size, mtime)
2366 :param object_name: the name of the object to get stats from
2367 :type object_name: str
2368 :param oncomplete: what to do when the stat is complete
2369 :type oncomplete: completion
2371 :raises: :class:`Error`
2372 :returns: completion object
2375 object_name = cstr(object_name, 'object_name')
2378 Completion completion
2379 char *_object_name = object_name
2383 def oncomplete_(completion_v):
2384 cdef Completion _completion_v = completion_v
2385 return_value = _completion_v.get_return_value()
2386 if return_value >= 0:
2387 return oncomplete(_completion_v, psize, time.localtime(pmtime))
2389 return oncomplete(_completion_v, None, None)
2391 completion = self.__get_completion(oncomplete_, None)
2392 self.__track_completion(completion)
2394 ret = rados_aio_stat(self.io, _object_name, completion.rados_comp,
2398 completion._cleanup()
2399 raise make_ex(ret, "error stating %s" % object_name)
2402 @requires(('object_name', str_type), ('to_write', bytes), ('offset', int),
2403 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2404 def aio_write(self, object_name, to_write, offset=0,
2405 oncomplete=None, onsafe=None):
2407 Write data to an object asynchronously
2409 Queues the write and returns.
2411 :param object_name: name of the object
2412 :type object_name: str
2413 :param to_write: data to write
2414 :type to_write: bytes
2415 :param offset: byte offset in the object to begin writing at
2417 :param oncomplete: what to do when the write is safe and complete in memory
2419 :type oncomplete: completion
2420 :param onsafe: what to do when the write is safe and complete on storage
2422 :type onsafe: completion
2424 :raises: :class:`Error`
2425 :returns: completion object
2428 object_name = cstr(object_name, 'object_name')
2431 Completion completion
2432 char* _object_name = object_name
2433 char* _to_write = to_write
2434 size_t size = len(to_write)
2435 uint64_t _offset = offset
2437 completion = self.__get_completion(oncomplete, onsafe)
2438 self.__track_completion(completion)
2440 ret = rados_aio_write(self.io, _object_name, completion.rados_comp,
2441 _to_write, size, _offset)
2443 completion._cleanup()
2444 raise make_ex(ret, "error writing object %s" % object_name)
2447 @requires(('object_name', str_type), ('to_write', bytes), ('oncomplete', opt(Callable)),
2448 ('onsafe', opt(Callable)))
2449 def aio_write_full(self, object_name, to_write,
2450 oncomplete=None, onsafe=None):
2452 Asynchronously write an entire object
2454 The object is filled with the provided data. If the object exists,
2455 it is atomically truncated and then written.
2456 Queues the write and returns.
2458 :param object_name: name of the object
2459 :type object_name: str
2460 :param to_write: data to write
2462 :param oncomplete: what to do when the write is safe and complete in memory
2464 :type oncomplete: completion
2465 :param onsafe: what to do when the write is safe and complete on storage
2467 :type onsafe: completion
2469 :raises: :class:`Error`
2470 :returns: completion object
2473 object_name = cstr(object_name, 'object_name')
2476 Completion completion
2477 char* _object_name = object_name
2478 char* _to_write = to_write
2479 size_t size = len(to_write)
2481 completion = self.__get_completion(oncomplete, onsafe)
2482 self.__track_completion(completion)
2484 ret = rados_aio_write_full(self.io, _object_name,
2485 completion.rados_comp,
2488 completion._cleanup()
2489 raise make_ex(ret, "error writing object %s" % object_name)
2492 @requires(('object_name', str_type), ('to_write', bytes), ('write_len', int),
2493 ('offset', int), ('oncomplete', opt(Callable)))
2494 def aio_writesame(self, object_name, to_write, write_len, offset=0,
2497 Asynchronously write the same buffer multiple times
2499 :param object_name: name of the object
2500 :type object_name: str
2501 :param to_write: data to write
2502 :type to_write: bytes
2503 :param write_len: total number of bytes to write
2504 :type write_len: int
2505 :param offset: byte offset in the object to begin writing at
2507 :param oncomplete: what to do when the writesame is safe and
2508 complete in memory on all replicas
2509 :type oncomplete: completion
2510 :raises: :class:`Error`
2511 :returns: completion object
2514 object_name = cstr(object_name, 'object_name')
2517 Completion completion
2518 char* _object_name = object_name
2519 char* _to_write = to_write
2520 size_t _data_len = len(to_write)
2521 size_t _write_len = write_len
2522 uint64_t _offset = offset
2524 completion = self.__get_completion(oncomplete, None)
2525 self.__track_completion(completion)
2527 ret = rados_aio_writesame(self.io, _object_name, completion.rados_comp,
2528 _to_write, _data_len, _write_len, _offset)
2531 completion._cleanup()
2532 raise make_ex(ret, "error writing object %s" % object_name)
2535 @requires(('object_name', str_type), ('to_append', bytes), ('oncomplete', opt(Callable)),
2536 ('onsafe', opt(Callable)))
2537 def aio_append(self, object_name, to_append, oncomplete=None, onsafe=None):
2539 Asynchronously append data to an object
2541 Queues the write and returns.
2543 :param object_name: name of the object
2544 :type object_name: str
2545 :param to_append: data to append
2546 :type to_append: str
2547 :param offset: byte offset in the object to begin writing at
2549 :param oncomplete: what to do when the write is safe and complete in memory
2551 :type oncomplete: completion
2552 :param onsafe: what to do when the write is safe and complete on storage
2554 :type onsafe: completion
2556 :raises: :class:`Error`
2557 :returns: completion object
2559 object_name = cstr(object_name, 'object_name')
2562 Completion completion
2563 char* _object_name = object_name
2564 char* _to_append = to_append
2565 size_t size = len(to_append)
2567 completion = self.__get_completion(oncomplete, onsafe)
2568 self.__track_completion(completion)
2570 ret = rados_aio_append(self.io, _object_name,
2571 completion.rados_comp,
2574 completion._cleanup()
2575 raise make_ex(ret, "error appending object %s" % object_name)
2578 def aio_flush(self):
2580 Block until all pending writes in an io context are safe
2582 :raises: :class:`Error`
2585 ret = rados_aio_flush(self.io)
2587 raise make_ex(ret, "error flushing")
2589 @requires(('object_name', str_type), ('length', int), ('offset', int),
2590 ('oncomplete', opt(Callable)))
2591 def aio_read(self, object_name, length, offset, oncomplete):
2593 Asynchronously read data from an object
2595 oncomplete will be called with the returned read value as
2596 well as the completion:
2598 oncomplete(completion, data_read)
2600 :param object_name: name of the object to read from
2601 :type object_name: str
2602 :param length: the number of bytes to read
2604 :param offset: byte offset in the object to begin reading from
2606 :param oncomplete: what to do when the read is complete
2607 :type oncomplete: completion
2609 :raises: :class:`Error`
2610 :returns: completion object
2613 object_name = cstr(object_name, 'object_name')
2616 Completion completion
2617 char* _object_name = object_name
2618 uint64_t _offset = offset
2621 size_t _length = length
2623 def oncomplete_(completion_v):
2624 cdef Completion _completion_v = completion_v
2625 return_value = _completion_v.get_return_value()
2626 if return_value > 0 and return_value != length:
2627 _PyBytes_Resize(&_completion_v.buf, return_value)
2628 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2630 completion = self.__get_completion(oncomplete_, None)
2631 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2632 ret_buf = PyBytes_AsString(completion.buf)
2633 self.__track_completion(completion)
2635 ret = rados_aio_read(self.io, _object_name, completion.rados_comp,
2636 ret_buf, _length, _offset)
2638 completion._cleanup()
2639 raise make_ex(ret, "error reading %s" % object_name)
2642 @requires(('object_name', str_type), ('cls', str_type), ('method', str_type),
2643 ('data', bytes), ('length', int),
2644 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2645 def aio_execute(self, object_name, cls, method, data,
2646 length=8192, oncomplete=None, onsafe=None):
2648 Asynchronously execute an OSD class method on an object.
2650 oncomplete and onsafe will be called with the data returned from
2651 the plugin as well as the completion:
2653 oncomplete(completion, data)
2654 onsafe(completion, data)
2656 :param object_name: name of the object
2657 :type object_name: str
2658 :param cls: name of the object class
2660 :param method: name of the method
2662 :param data: input data
2664 :param length: size of output buffer in bytes (default=8192)
2666 :param oncomplete: what to do when the execution is complete
2667 :type oncomplete: completion
2668 :param onsafe: what to do when the execution is safe and complete
2669 :type onsafe: completion
2671 :raises: :class:`Error`
2672 :returns: completion object
2675 object_name = cstr(object_name, 'object_name')
2676 cls = cstr(cls, 'cls')
2677 method = cstr(method, 'method')
2679 Completion completion
2680 char *_object_name = object_name
2682 char *_method = method
2684 size_t _data_len = len(data)
2687 size_t _length = length
2689 def oncomplete_(completion_v):
2690 cdef Completion _completion_v = completion_v
2691 return_value = _completion_v.get_return_value()
2692 if return_value > 0 and return_value != length:
2693 _PyBytes_Resize(&_completion_v.buf, return_value)
2694 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2696 def onsafe_(completion_v):
2697 cdef Completion _completion_v = completion_v
2698 return_value = _completion_v.get_return_value()
2699 return onsafe(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2701 completion = self.__get_completion(oncomplete_ if oncomplete else None, onsafe_ if onsafe else None)
2702 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2703 ret_buf = PyBytes_AsString(completion.buf)
2704 self.__track_completion(completion)
2706 ret = rados_aio_exec(self.io, _object_name, completion.rados_comp,
2707 _cls, _method, _data, _data_len, ret_buf, _length)
2709 completion._cleanup()
2710 raise make_ex(ret, "error executing %s::%s on %s" % (cls, method, object_name))
2713 @requires(('object_name', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2714 def aio_remove(self, object_name, oncomplete=None, onsafe=None):
2716 Asynchronously remove an object
2718 :param object_name: name of the object to remove
2719 :type object_name: str
2720 :param oncomplete: what to do when the remove is safe and complete in memory
2722 :type oncomplete: completion
2723 :param onsafe: what to do when the remove is safe and complete on storage
2725 :type onsafe: completion
2727 :raises: :class:`Error`
2728 :returns: completion object
2730 object_name = cstr(object_name, 'object_name')
2733 Completion completion
2734 char* _object_name = object_name
2736 completion = self.__get_completion(oncomplete, onsafe)
2737 self.__track_completion(completion)
2739 ret = rados_aio_remove(self.io, _object_name,
2740 completion.rados_comp)
2742 completion._cleanup()
2743 raise make_ex(ret, "error removing %s" % object_name)
2746 def require_ioctx_open(self):
2748 Checks if the rados.Ioctx object state is 'open'
2750 :raises: IoctxStateError
2752 if self.state != "open":
2753 raise IoctxStateError("The pool is %s" % self.state)
2755 @requires(('loc_key', str_type))
2756 def set_locator_key(self, loc_key):
2758 Set the key for mapping objects to pgs within an io context.
2760 The key is used instead of the object name to determine which
2761 placement groups an object is put in. This affects all subsequent
2762 operations of the io context - until a different locator key is
2763 set, all objects in this io context will be placed in the same pg.
2765 :param loc_key: the key to use as the object locator, or NULL to discard
2766 any previously set key
2769 :raises: :class:`TypeError`
2771 self.require_ioctx_open()
2772 cloc_key = cstr(loc_key, 'loc_key')
2773 cdef char *_loc_key = cloc_key
2775 rados_ioctx_locator_set_key(self.io, _loc_key)
2776 self.locator_key = loc_key
2778 def get_locator_key(self):
2780 Get the locator_key of context
2782 :returns: locator_key
2784 return self.locator_key
2786 @requires(('snap_id', long))
2787 def set_read(self, snap_id):
2789 Set the snapshot for reading objects.
2791 To stop to read from snapshot, use set_read(LIBRADOS_SNAP_HEAD)
2793 :param snap_id: the snapshot Id
2796 :raises: :class:`TypeError`
2798 self.require_ioctx_open()
2799 cdef rados_snap_t _snap_id = snap_id
2801 rados_ioctx_snap_set_read(self.io, _snap_id)
2803 @requires(('nspace', str_type))
2804 def set_namespace(self, nspace):
2806 Set the namespace for objects within an io context.
2808 The namespace in addition to the object name fully identifies
2809 an object. This affects all subsequent operations of the io context
2810 - until a different namespace is set, all objects in this io context
2811 will be placed in the same namespace.
2813 :param nspace: the namespace to use, or None/"" for the default namespace
2816 :raises: :class:`TypeError`
2818 self.require_ioctx_open()
2821 cnspace = cstr(nspace, 'nspace')
2822 cdef char *_nspace = cnspace
2824 rados_ioctx_set_namespace(self.io, _nspace)
2825 self.nspace = nspace
2827 def get_namespace(self):
2829 Get the namespace of context
2837 Close a rados.Ioctx object.
2839 This just tells librados that you no longer need to use the io context.
2840 It may not be freed immediately if there are pending asynchronous
2841 requests on it, but you should not use an io context again after
2842 calling this function on it.
2844 if self.state == "open":
2845 self.require_ioctx_open()
2847 rados_ioctx_destroy(self.io)
2848 self.state = "closed"
2851 @requires(('key', str_type), ('data', bytes))
2852 def write(self, key, data, offset=0):
2854 Write data to an object synchronously
2856 :param key: name of the object
2858 :param data: data to write
2860 :param offset: byte offset in the object to begin writing at
2863 :raises: :class:`TypeError`
2864 :raises: :class:`LogicError`
2865 :returns: int - 0 on success
2867 self.require_ioctx_open()
2869 key = cstr(key, 'key')
2873 size_t length = len(data)
2874 uint64_t _offset = offset
2877 ret = rados_write(self.io, _key, _data, length, _offset)
2881 raise make_ex(ret, "Ioctx.write(%s): failed to write %s"
2884 raise LogicError("Ioctx.write(%s): rados_write \
2885 returned %d, but should return zero on success." % (self.name, ret))
2887 @requires(('key', str_type), ('data', bytes))
2888 def write_full(self, key, data):
2890 Write an entire object synchronously.
2892 The object is filled with the provided data. If the object exists,
2893 it is atomically truncated and then written.
2895 :param key: name of the object
2897 :param data: data to write
2900 :raises: :class:`TypeError`
2901 :raises: :class:`Error`
2902 :returns: int - 0 on success
2904 self.require_ioctx_open()
2905 key = cstr(key, 'key')
2909 size_t length = len(data)
2912 ret = rados_write_full(self.io, _key, _data, length)
2916 raise make_ex(ret, "Ioctx.write_full(%s): failed to write %s"
2919 raise LogicError("Ioctx.write_full(%s): rados_write_full \
2920 returned %d, but should return zero on success." % (self.name, ret))
2922 @requires(('key', str_type), ('data', bytes), ('write_len', int), ('offset', int))
2923 def writesame(self, key, data, write_len, offset=0):
2925 Write the same buffer multiple times
2926 :param key: name of the object
2928 :param data: data to write
2930 :param write_len: total number of bytes to write
2931 :type write_len: int
2932 :param offset: byte offset in the object to begin writing at
2935 :raises: :class:`TypeError`
2936 :raises: :class:`LogicError`
2938 self.require_ioctx_open()
2940 key = cstr(key, 'key')
2944 size_t _data_len = len(data)
2945 size_t _write_len = write_len
2946 uint64_t _offset = offset
2949 ret = rados_writesame(self.io, _key, _data, _data_len, _write_len, _offset)
2951 raise make_ex(ret, "Ioctx.writesame(%s): failed to write %s"
2955 @requires(('key', str_type), ('data', bytes))
2956 def append(self, key, data):
2958 Append data to an object synchronously
2960 :param key: name of the object
2962 :param data: data to write
2965 :raises: :class:`TypeError`
2966 :raises: :class:`LogicError`
2967 :returns: int - 0 on success
2969 self.require_ioctx_open()
2970 key = cstr(key, 'key')
2974 size_t length = len(data)
2977 ret = rados_append(self.io, _key, _data, length)
2981 raise make_ex(ret, "Ioctx.append(%s): failed to append %s"
2984 raise LogicError("Ioctx.append(%s): rados_append \
2985 returned %d, but should return zero on success." % (self.name, ret))
2987 @requires(('key', str_type))
2988 def read(self, key, length=8192, offset=0):
2990 Read data from an object synchronously
2992 :param key: name of the object
2994 :param length: the number of bytes to read (default=8192)
2996 :param offset: byte offset in the object to begin reading at
2999 :raises: :class:`TypeError`
3000 :raises: :class:`Error`
3001 :returns: str - data read from object
3003 self.require_ioctx_open()
3004 key = cstr(key, 'key')
3008 uint64_t _offset = offset
3009 size_t _length = length
3010 PyObject* ret_s = NULL
3012 ret_s = PyBytes_FromStringAndSize(NULL, length)
3014 ret_buf = PyBytes_AsString(ret_s)
3016 ret = rados_read(self.io, _key, ret_buf, _length, _offset)
3018 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
3021 _PyBytes_Resize(&ret_s, ret)
3023 return <object>ret_s
3025 # We DECREF unconditionally: the cast to object above will have
3026 # INCREFed if necessary. This also takes care of exceptions,
3027 # including if _PyString_Resize fails (that will free the string
3028 # itself and set ret_s to NULL, hence XDECREF).
3029 ref.Py_XDECREF(ret_s)
3031 @requires(('key', str_type), ('cls', str_type), ('method', str_type), ('data', bytes))
3032 def execute(self, key, cls, method, data, length=8192):
3034 Execute an OSD class method on an object.
3036 :param key: name of the object
3038 :param cls: name of the object class
3040 :param method: name of the method
3042 :param data: input data
3044 :param length: size of output buffer in bytes (default=8192)
3047 :raises: :class:`TypeError`
3048 :raises: :class:`Error`
3049 :returns: (ret, method output)
3051 self.require_ioctx_open()
3053 key = cstr(key, 'key')
3054 cls = cstr(cls, 'cls')
3055 method = cstr(method, 'method')
3059 char *_method = method
3061 size_t _data_len = len(data)
3064 size_t _length = length
3065 PyObject* ret_s = NULL
3067 ret_s = PyBytes_FromStringAndSize(NULL, length)
3069 ret_buf = PyBytes_AsString(ret_s)
3071 ret = rados_exec(self.io, _key, _cls, _method, _data,
3072 _data_len, ret_buf, _length)
3074 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
3077 _PyBytes_Resize(&ret_s, ret)
3079 return ret, <object>ret_s
3081 # We DECREF unconditionally: the cast to object above will have
3082 # INCREFed if necessary. This also takes care of exceptions,
3083 # including if _PyString_Resize fails (that will free the string
3084 # itself and set ret_s to NULL, hence XDECREF).
3085 ref.Py_XDECREF(ret_s)
3087 def get_stats(self):
3089 Get pool usage statistics
3091 :returns: dict - contains the following keys:
3093 - ``num_bytes`` (int) - size of pool in bytes
3095 - ``num_kb`` (int) - size of pool in kbytes
3097 - ``num_objects`` (int) - number of objects in the pool
3099 - ``num_object_clones`` (int) - number of object clones
3101 - ``num_object_copies`` (int) - number of object copies
3103 - ``num_objects_missing_on_primary`` (int) - number of objets
3106 - ``num_objects_unfound`` (int) - number of unfound objects
3108 - ``num_objects_degraded`` (int) - number of degraded objects
3110 - ``num_rd`` (int) - bytes read
3112 - ``num_rd_kb`` (int) - kbytes read
3114 - ``num_wr`` (int) - bytes written
3116 - ``num_wr_kb`` (int) - kbytes written
3118 self.require_ioctx_open()
3119 cdef rados_pool_stat_t stats
3121 ret = rados_ioctx_pool_stat(self.io, &stats)
3123 raise make_ex(ret, "Ioctx.get_stats(%s): get_stats failed" % self.name)
3124 return {'num_bytes': stats.num_bytes,
3125 'num_kb': stats.num_kb,
3126 'num_objects': stats.num_objects,
3127 'num_object_clones': stats.num_object_clones,
3128 'num_object_copies': stats.num_object_copies,
3129 "num_objects_missing_on_primary": stats.num_objects_missing_on_primary,
3130 "num_objects_unfound": stats.num_objects_unfound,
3131 "num_objects_degraded": stats.num_objects_degraded,
3132 "num_rd": stats.num_rd,
3133 "num_rd_kb": stats.num_rd_kb,
3134 "num_wr": stats.num_wr,
3135 "num_wr_kb": stats.num_wr_kb}
3137 @requires(('key', str_type))
3138 def remove_object(self, key):
3142 This does not delete any snapshots of the object.
3144 :param key: the name of the object to delete
3147 :raises: :class:`TypeError`
3148 :raises: :class:`Error`
3149 :returns: bool - True on success
3151 self.require_ioctx_open()
3152 key = cstr(key, 'key')
3157 ret = rados_remove(self.io, _key)
3159 raise make_ex(ret, "Failed to remove '%s'" % key)
3162 @requires(('key', str_type))
3163 def trunc(self, key, size):
3167 If this enlarges the object, the new area is logically filled with
3168 zeroes. If this shrinks the object, the excess data is removed.
3170 :param key: the name of the object to resize
3172 :param size: the new size of the object in bytes
3175 :raises: :class:`TypeError`
3176 :raises: :class:`Error`
3177 :returns: int - 0 on success, otherwise raises error
3180 self.require_ioctx_open()
3181 key = cstr(key, 'key')
3184 uint64_t _size = size
3187 ret = rados_trunc(self.io, _key, _size)
3189 raise make_ex(ret, "Ioctx.trunc(%s): failed to truncate %s" % (self.name, key))
3192 @requires(('key', str_type))
3193 def stat(self, key):
3195 Get object stats (size/mtime)
3197 :param key: the name of the object to get stats from
3200 :raises: :class:`TypeError`
3201 :raises: :class:`Error`
3202 :returns: (size,timestamp)
3204 self.require_ioctx_open()
3206 key = cstr(key, 'key')
3213 ret = rados_stat(self.io, _key, &psize, &pmtime)
3215 raise make_ex(ret, "Failed to stat %r" % key)
3216 return psize, time.localtime(pmtime)
3218 @requires(('key', str_type), ('xattr_name', str_type))
3219 def get_xattr(self, key, xattr_name):
3221 Get the value of an extended attribute on an object.
3223 :param key: the name of the object to get xattr from
3225 :param xattr_name: which extended attribute to read
3226 :type xattr_name: str
3228 :raises: :class:`TypeError`
3229 :raises: :class:`Error`
3230 :returns: str - value of the xattr
3232 self.require_ioctx_open()
3234 key = cstr(key, 'key')
3235 xattr_name = cstr(xattr_name, 'xattr_name')
3238 char *_xattr_name = xattr_name
3239 size_t ret_length = 4096
3240 char *ret_buf = NULL
3243 while ret_length < 4096 * 1024 * 1024:
3244 ret_buf = <char *>realloc_chk(ret_buf, ret_length)
3246 ret = rados_getxattr(self.io, _key, _xattr_name, ret_buf, ret_length)
3247 if ret == -errno.ERANGE:
3250 raise make_ex(ret, "Failed to get xattr %r" % xattr_name)
3253 return ret_buf[:ret]
3257 @requires(('oid', str_type))
3258 def get_xattrs(self, oid):
3260 Start iterating over xattrs on an object.
3262 :param oid: the name of the object to get xattrs from
3265 :raises: :class:`TypeError`
3266 :raises: :class:`Error`
3267 :returns: XattrIterator
3269 self.require_ioctx_open()
3270 return XattrIterator(self, oid)
3272 @requires(('key', str_type), ('xattr_name', str_type), ('xattr_value', bytes))
3273 def set_xattr(self, key, xattr_name, xattr_value):
3275 Set an extended attribute on an object.
3277 :param key: the name of the object to set xattr to
3279 :param xattr_name: which extended attribute to set
3280 :type xattr_name: str
3281 :param xattr_value: the value of the extended attribute
3282 :type xattr_value: bytes
3284 :raises: :class:`TypeError`
3285 :raises: :class:`Error`
3286 :returns: bool - True on success, otherwise raise an error
3288 self.require_ioctx_open()
3290 key = cstr(key, 'key')
3291 xattr_name = cstr(xattr_name, 'xattr_name')
3294 char *_xattr_name = xattr_name
3295 char *_xattr_value = xattr_value
3296 size_t _xattr_value_len = len(xattr_value)
3299 ret = rados_setxattr(self.io, _key, _xattr_name,
3300 _xattr_value, _xattr_value_len)
3302 raise make_ex(ret, "Failed to set xattr %r" % xattr_name)
3305 @requires(('key', str_type), ('xattr_name', str_type))
3306 def rm_xattr(self, key, xattr_name):
3308 Removes an extended attribute on from an object.
3310 :param key: the name of the object to remove xattr from
3312 :param xattr_name: which extended attribute to remove
3313 :type xattr_name: str
3315 :raises: :class:`TypeError`
3316 :raises: :class:`Error`
3317 :returns: bool - True on success, otherwise raise an error
3319 self.require_ioctx_open()
3321 key = cstr(key, 'key')
3322 xattr_name = cstr(xattr_name, 'xattr_name')
3325 char *_xattr_name = xattr_name
3328 ret = rados_rmxattr(self.io, _key, _xattr_name)
3330 raise make_ex(ret, "Failed to delete key %r xattr %r" %
3334 @requires(('obj', str_type), ('msg', str_type), ('timeout_ms', int))
3335 def notify(self, obj, msg='', timeout_ms=5000):
3337 Send a rados notification to an object.
3339 :param obj: the name of the object to notify
3341 :param msg: optional message to send in the notification
3343 :param timeout_ms: notify timeout (in ms)
3344 :type timeout_ms: int
3346 :raises: :class:`TypeError`
3347 :raises: :class:`Error`
3348 :returns: bool - True on success, otherwise raise an error
3350 self.require_ioctx_open()
3353 obj = cstr(obj, 'obj')
3354 msg = cstr(msg, 'msg')
3358 int _msglen = msglen
3359 uint64_t _timeout_ms = timeout_ms
3362 ret = rados_notify2(self.io, _obj, _msg, _msglen, _timeout_ms,
3365 raise make_ex(ret, "Failed to notify %r" % (obj))
3368 def list_objects(self):
3370 Get ObjectIterator on rados.Ioctx object.
3372 :returns: ObjectIterator
3374 self.require_ioctx_open()
3375 return ObjectIterator(self)
3377 def list_snaps(self):
3379 Get SnapIterator on rados.Ioctx object.
3381 :returns: SnapIterator
3383 self.require_ioctx_open()
3384 return SnapIterator(self)
3386 def get_pool_id(self):
3390 :returns: int - pool id
3393 ret = rados_ioctx_get_id(self.io)
3396 def get_pool_name(self):
3400 :returns: str - pool name
3408 name = <char *>realloc_chk(name, name_len)
3410 ret = rados_ioctx_get_pool_name(self.io, name, name_len)
3413 elif ret != -errno.ERANGE:
3414 raise make_ex(ret, "get pool name error")
3416 name_len = name_len * 2
3418 return decode_cstr(name)
3423 @requires(('snap_name', str_type))
3424 def create_snap(self, snap_name):
3426 Create a pool-wide snapshot
3428 :param snap_name: the name of the snapshot
3429 :type snap_name: str
3431 :raises: :class:`TypeError`
3432 :raises: :class:`Error`
3434 self.require_ioctx_open()
3435 snap_name = cstr(snap_name, 'snap_name')
3436 cdef char *_snap_name = snap_name
3439 ret = rados_ioctx_snap_create(self.io, _snap_name)
3441 raise make_ex(ret, "Failed to create snap %s" % snap_name)
3443 @requires(('snap_name', str_type))
3444 def remove_snap(self, snap_name):
3446 Removes a pool-wide snapshot
3448 :param snap_name: the name of the snapshot
3449 :type snap_name: str
3451 :raises: :class:`TypeError`
3452 :raises: :class:`Error`
3454 self.require_ioctx_open()
3455 snap_name = cstr(snap_name, 'snap_name')
3456 cdef char *_snap_name = snap_name
3459 ret = rados_ioctx_snap_remove(self.io, _snap_name)
3461 raise make_ex(ret, "Failed to remove snap %s" % snap_name)
3463 @requires(('snap_name', str_type))
3464 def lookup_snap(self, snap_name):
3466 Get the id of a pool snapshot
3468 :param snap_name: the name of the snapshot to lookop
3469 :type snap_name: str
3471 :raises: :class:`TypeError`
3472 :raises: :class:`Error`
3473 :returns: Snap - on success
3475 self.require_ioctx_open()
3476 csnap_name = cstr(snap_name, 'snap_name')
3478 char *_snap_name = csnap_name
3479 rados_snap_t snap_id
3482 ret = rados_ioctx_snap_lookup(self.io, _snap_name, &snap_id)
3484 raise make_ex(ret, "Failed to lookup snap %s" % snap_name)
3485 return Snap(self, snap_name, int(snap_id))
3487 @requires(('oid', str_type), ('snap_name', str_type))
3488 def snap_rollback(self, oid, snap_name):
3490 Rollback an object to a snapshot
3492 :param oid: the name of the object
3494 :param snap_name: the name of the snapshot
3495 :type snap_name: str
3497 :raises: :class:`TypeError`
3498 :raises: :class:`Error`
3500 self.require_ioctx_open()
3501 oid = cstr(oid, 'oid')
3502 snap_name = cstr(snap_name, 'snap_name')
3504 char *_snap_name = snap_name
3508 ret = rados_ioctx_snap_rollback(self.io, _oid, _snap_name)
3510 raise make_ex(ret, "Failed to rollback %s" % oid)
3512 def create_self_managed_snap(self):
3514 Creates a self-managed snapshot
3516 :returns: snap id on success
3518 :raises: :class:`Error`
3520 self.require_ioctx_open()
3522 rados_snap_t _snap_id
3524 ret = rados_ioctx_selfmanaged_snap_create(self.io, &_snap_id)
3526 raise make_ex(ret, "Failed to create self-managed snapshot")
3527 return int(_snap_id)
3529 @requires(('snap_id', int))
3530 def remove_self_managed_snap(self, snap_id):
3532 Removes a self-managed snapshot
3534 :param snap_id: the name of the snapshot
3537 :raises: :class:`TypeError`
3538 :raises: :class:`Error`
3540 self.require_ioctx_open()
3542 rados_snap_t _snap_id = snap_id
3544 ret = rados_ioctx_selfmanaged_snap_remove(self.io, _snap_id)
3546 raise make_ex(ret, "Failed to remove self-managed snapshot")
3548 def set_self_managed_snap_write(self, snaps):
3550 Updates the write context to the specified self-managed
3553 :param snaps: all associated self-managed snapshot ids
3556 :raises: :class:`TypeError`
3557 :raises: :class:`Error`
3559 self.require_ioctx_open()
3563 sorted_snaps = sorted([int(x) for x in snaps], reverse=True)
3564 snap_seq = sorted_snaps[0]
3567 rados_snap_t _snap_seq = snap_seq
3568 rados_snap_t *_snaps = NULL
3569 int _num_snaps = len(sorted_snaps)
3571 _snaps = <rados_snap_t *>malloc(_num_snaps * sizeof(rados_snap_t))
3572 for i in range(len(sorted_snaps)):
3573 _snaps[i] = sorted_snaps[i]
3575 ret = rados_ioctx_selfmanaged_snap_set_write_ctx(self.io,
3580 raise make_ex(ret, "Failed to update snapshot write context")
3584 @requires(('oid', str_type), ('snap_id', int))
3585 def rollback_self_managed_snap(self, oid, snap_id):
3587 Rolls an specific object back to a self-managed snapshot revision
3589 :param oid: the name of the object
3591 :param snap_id: the name of the snapshot
3594 :raises: :class:`TypeError`
3595 :raises: :class:`Error`
3597 self.require_ioctx_open()
3598 oid = cstr(oid, 'oid')
3601 rados_snap_t _snap_id = snap_id
3603 ret = rados_ioctx_selfmanaged_snap_rollback(self.io, _oid, _snap_id)
3605 raise make_ex(ret, "Failed to rollback %s" % oid)
3607 def get_last_version(self):
3609 Return the version of the last object read or written to.
3611 This exposes the internal version number of the last object read or
3612 written via this io context
3614 :returns: version of the last object used
3616 self.require_ioctx_open()
3618 ret = rados_get_last_version(self.io)
3621 def create_write_op(self):
3623 create write operation object.
3624 need call release_write_op after use
3626 return WriteOp().create()
3628 def create_read_op(self):
3630 create read operation object.
3631 need call release_read_op after use
3633 return ReadOp().create()
3635 def release_write_op(self, write_op):
3637 release memory alloc by create_write_op
3641 def release_read_op(self, read_op):
3643 release memory alloc by create_read_op
3644 :para read_op: read_op object
3649 @requires(('write_op', WriteOp), ('keys', tuple), ('values', tuple))
3650 def set_omap(self, write_op, keys, values):
3652 set keys values to write_op
3653 :para write_op: write_operation object
3654 :type write_op: WriteOp
3655 :para keys: a tuple of keys
3657 :para values: a tuple of values
3661 if len(keys) != len(values):
3662 raise Error("Rados(): keys and values must have the same number of items")
3664 keys = cstr_list(keys, 'keys')
3665 values = cstr_list(values, 'values')
3666 lens = [len(v) for v in values]
3668 WriteOp _write_op = write_op
3669 size_t key_num = len(keys)
3670 char **_keys = to_bytes_array(keys)
3671 char **_values = to_bytes_array(values)
3672 size_t *_lens = to_csize_t_array(lens)
3676 rados_write_op_omap_set(_write_op.write_op,
3677 <const char**>_keys,
3678 <const char**>_values,
3679 <const size_t*>_lens, key_num)
3685 @requires(('write_op', WriteOp), ('oid', str_type), ('mtime', opt(int)), ('flags', opt(int)))
3686 def operate_write_op(self, write_op, oid, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3688 execute the real write operation
3689 :para write_op: write operation object
3690 :type write_op: WriteOp
3691 :para oid: object name
3693 :para mtime: the time to set the mtime to, 0 for the current time
3695 :para flags: flags to apply to the entire operation
3699 oid = cstr(oid, 'oid')
3701 WriteOp _write_op = write_op
3703 time_t _mtime = mtime
3707 ret = rados_write_op_operate(_write_op.write_op, self.io, _oid, &_mtime, _flags)
3709 raise make_ex(ret, "Failed to operate write op for oid %s" % oid)
3711 @requires(('write_op', WriteOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('mtime', opt(int)), ('flags', opt(int)))
3712 def operate_aio_write_op(self, write_op, oid, oncomplete=None, onsafe=None, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3714 execute the real write operation asynchronously
3715 :para write_op: write operation object
3716 :type write_op: WriteOp
3717 :para oid: object name
3719 :param oncomplete: what to do when the remove is safe and complete in memory
3721 :type oncomplete: completion
3722 :param onsafe: what to do when the remove is safe and complete on storage
3724 :type onsafe: completion
3725 :para mtime: the time to set the mtime to, 0 for the current time
3727 :para flags: flags to apply to the entire operation
3730 :raises: :class:`Error`
3731 :returns: completion object
3734 oid = cstr(oid, 'oid')
3736 WriteOp _write_op = write_op
3738 Completion completion
3739 time_t _mtime = mtime
3742 completion = self.__get_completion(oncomplete, onsafe)
3743 self.__track_completion(completion)
3746 ret = rados_aio_write_op_operate(_write_op.write_op, self.io, completion.rados_comp, _oid,
3749 completion._cleanup()
3750 raise make_ex(ret, "Failed to operate aio write op for oid %s" % oid)
3753 @requires(('read_op', ReadOp), ('oid', str_type), ('flag', opt(int)))
3754 def operate_read_op(self, read_op, oid, flag=LIBRADOS_OPERATION_NOFLAG):
3756 execute the real read operation
3757 :para read_op: read operation object
3758 :type read_op: ReadOp
3759 :para oid: object name
3761 :para flag: flags to apply to the entire operation
3764 oid = cstr(oid, 'oid')
3766 ReadOp _read_op = read_op
3771 ret = rados_read_op_operate(_read_op.read_op, self.io, _oid, _flag)
3773 raise make_ex(ret, "Failed to operate read op for oid %s" % oid)
3775 @requires(('read_op', ReadOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('flag', opt(int)))
3776 def operate_aio_read_op(self, read_op, oid, oncomplete=None, onsafe=None, flag=LIBRADOS_OPERATION_NOFLAG):
3778 execute the real read operation
3779 :para read_op: read operation object
3780 :type read_op: ReadOp
3781 :para oid: object name
3783 :param oncomplete: what to do when the remove is safe and complete in memory
3785 :type oncomplete: completion
3786 :param onsafe: what to do when the remove is safe and complete on storage
3788 :type onsafe: completion
3789 :para flag: flags to apply to the entire operation
3792 oid = cstr(oid, 'oid')
3794 ReadOp _read_op = read_op
3796 Completion completion
3799 completion = self.__get_completion(oncomplete, onsafe)
3800 self.__track_completion(completion)
3803 ret = rados_aio_read_op_operate(_read_op.read_op, self.io, completion.rados_comp, _oid, _flag)
3805 completion._cleanup()
3806 raise make_ex(ret, "Failed to operate aio read op for oid %s" % oid)
3809 @requires(('read_op', ReadOp), ('start_after', str_type), ('filter_prefix', str_type), ('max_return', int))
3810 def get_omap_vals(self, read_op, start_after, filter_prefix, max_return):
3813 :para read_op: read operation object
3814 :type read_op: ReadOp
3815 :para start_after: list keys starting after start_after
3816 :type start_after: str
3817 :para filter_prefix: list only keys beginning with filter_prefix
3818 :type filter_prefix: str
3819 :para max_return: list no more than max_return key/value pairs
3820 :type max_return: int
3821 :returns: an iterator over the requested omap values, return value from this action
3824 start_after = cstr(start_after, 'start_after') if start_after else None
3825 filter_prefix = cstr(filter_prefix, 'filter_prefix') if filter_prefix else None
3827 char *_start_after = opt_str(start_after)
3828 char *_filter_prefix = opt_str(filter_prefix)
3829 ReadOp _read_op = read_op
3830 rados_omap_iter_t iter_addr = NULL
3831 int _max_return = max_return
3834 rados_read_op_omap_get_vals2(_read_op.read_op, _start_after, _filter_prefix,
3835 _max_return, &iter_addr, NULL, NULL)
3836 it = OmapIterator(self)
3838 return it, 0 # 0 is meaningless; there for backward-compat
3840 @requires(('read_op', ReadOp), ('start_after', str_type), ('max_return', int))
3841 def get_omap_keys(self, read_op, start_after, max_return):
3844 :para read_op: read operation object
3845 :type read_op: ReadOp
3846 :para start_after: list keys starting after start_after
3847 :type start_after: str
3848 :para max_return: list no more than max_return key/value pairs
3849 :type max_return: int
3850 :returns: an iterator over the requested omap values, return value from this action
3852 start_after = cstr(start_after, 'start_after') if start_after else None
3854 char *_start_after = opt_str(start_after)
3855 ReadOp _read_op = read_op
3856 rados_omap_iter_t iter_addr = NULL
3857 int _max_return = max_return
3860 rados_read_op_omap_get_keys2(_read_op.read_op, _start_after,
3861 _max_return, &iter_addr, NULL, NULL)
3862 it = OmapIterator(self)
3864 return it, 0 # 0 is meaningless; there for backward-compat
3866 @requires(('read_op', ReadOp), ('keys', tuple))
3867 def get_omap_vals_by_keys(self, read_op, keys):
3869 get the omap values by keys
3870 :para read_op: read operation object
3871 :type read_op: ReadOp
3872 :para keys: input key tuple
3874 :returns: an iterator over the requested omap values, return value from this action
3876 keys = cstr_list(keys, 'keys')
3878 ReadOp _read_op = read_op
3879 rados_omap_iter_t iter_addr
3880 char **_keys = to_bytes_array(keys)
3881 size_t key_num = len(keys)
3885 rados_read_op_omap_get_vals_by_keys(_read_op.read_op,
3886 <const char**>_keys,
3887 key_num, &iter_addr, NULL)
3888 it = OmapIterator(self)
3890 return it, 0 # 0 is meaningless; there for backward-compat
3894 @requires(('write_op', WriteOp), ('keys', tuple))
3895 def remove_omap_keys(self, write_op, keys):
3897 remove omap keys specifiled
3898 :para write_op: write operation object
3899 :type write_op: WriteOp
3900 :para keys: input key tuple
3904 keys = cstr_list(keys, 'keys')
3906 WriteOp _write_op = write_op
3907 size_t key_num = len(keys)
3908 char **_keys = to_bytes_array(keys)
3912 rados_write_op_omap_rm_keys(_write_op.write_op, <const char**>_keys, key_num)
3916 @requires(('write_op', WriteOp))
3917 def clear_omap(self, write_op):
3919 Remove all key/value pairs from an object
3920 :para write_op: write operation object
3921 :type write_op: WriteOp
3925 WriteOp _write_op = write_op
3928 rados_write_op_omap_clear(_write_op.write_op)
3930 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('desc', str_type),
3931 ('duration', opt(int)), ('flags', int))
3932 def lock_exclusive(self, key, name, cookie, desc="", duration=None, flags=0):
3935 Take an exclusive lock on an object
3937 :param key: name of the object
3939 :param name: name of the lock
3941 :param cookie: cookie of the lock
3943 :param desc: description of the lock
3945 :param duration: duration of the lock in seconds
3950 :raises: :class:`TypeError`
3951 :raises: :class:`Error`
3953 self.require_ioctx_open()
3955 key = cstr(key, 'key')
3956 name = cstr(name, 'name')
3957 cookie = cstr(cookie, 'cookie')
3958 desc = cstr(desc, 'desc')
3963 char* _cookie = cookie
3965 uint8_t _flags = flags
3968 if duration is None:
3970 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3973 _duration.tv_sec = duration
3975 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3979 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
3981 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('tag', str_type),
3982 ('desc', str_type), ('duration', opt(int)), ('flags', int))
3983 def lock_shared(self, key, name, cookie, tag, desc="", duration=None, flags=0):
3986 Take a shared lock on an object
3988 :param key: name of the object
3990 :param name: name of the lock
3992 :param cookie: cookie of the lock
3994 :param tag: tag of the lock
3996 :param desc: description of the lock
3998 :param duration: duration of the lock in seconds
4003 :raises: :class:`TypeError`
4004 :raises: :class:`Error`
4006 self.require_ioctx_open()
4008 key = cstr(key, 'key')
4009 tag = cstr(tag, 'tag')
4010 name = cstr(name, 'name')
4011 cookie = cstr(cookie, 'cookie')
4012 desc = cstr(desc, 'desc')
4018 char* _cookie = cookie
4020 uint8_t _flags = flags
4023 if duration is None:
4025 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
4028 _duration.tv_sec = duration
4030 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
4033 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
4035 @requires(('key', str_type), ('name', str_type), ('cookie', str_type))
4036 def unlock(self, key, name, cookie):
4039 Release a shared or exclusive lock on an object
4041 :param key: name of the object
4043 :param name: name of the lock
4045 :param cookie: cookie of the lock
4048 :raises: :class:`TypeError`
4049 :raises: :class:`Error`
4051 self.require_ioctx_open()
4053 key = cstr(key, 'key')
4054 name = cstr(name, 'name')
4055 cookie = cstr(cookie, 'cookie')
4060 char* _cookie = cookie
4063 ret = rados_unlock(self.io, _key, _name, _cookie)
4065 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
4067 def set_osdmap_full_try(self):
4069 Set global osdmap_full_try label to true
4072 rados_set_osdmap_full_try(self.io)
4074 def unset_osdmap_full_try(self):
4079 rados_unset_osdmap_full_try(self.io)
4081 def application_enable(self, app_name, force=False):
4083 Enable an application on an OSD pool
4085 :param app_name: application name
4087 :param force: False if only a single app should exist per pool
4088 :type expire_seconds: boool
4090 :raises: :class:`Error`
4092 app_name = cstr(app_name, 'app_name')
4094 char *_app_name = app_name
4095 int _force = (1 if force else 0)
4098 ret = rados_application_enable(self.io, _app_name, _force)
4100 raise make_ex(ret, "error enabling application")
4102 def application_list(self):
4104 Returns a list of enabled applications
4106 :returns: list of app name string
4114 apps = <char *>realloc_chk(apps, length)
4116 ret = rados_application_list(self.io, apps, &length)
4118 return [decode_cstr(app) for app in
4119 apps[:length].split(b'\0') if app]
4120 elif ret == -errno.ENOENT:
4122 elif ret == -errno.ERANGE:
4125 raise make_ex(ret, "error listing applications")
4129 def application_metadata_get(self, app_name, key):
4131 Gets application metadata on an OSD pool for the given key
4133 :param app_name: application name
4135 :param key: metadata key
4137 :returns: str - metadata value
4139 :raises: :class:`Error`
4142 app_name = cstr(app_name, 'app_name')
4143 key = cstr(key, 'key')
4145 char *_app_name = app_name
4152 value = <char *>realloc_chk(value, size)
4154 ret = rados_application_metadata_get(self.io, _app_name,
4156 if ret != -errno.ERANGE:
4158 if ret == -errno.ENOENT:
4159 raise KeyError('no metadata %s for application %s' % (key, _app_name))
4161 raise make_ex(ret, 'error getting metadata %s for application %s' %
4163 return decode_cstr(value)
4167 def application_metadata_set(self, app_name, key, value):
4169 Sets application metadata on an OSD pool
4171 :param app_name: application name
4173 :param key: metadata key
4175 :param value: metadata value
4178 :raises: :class:`Error`
4180 app_name = cstr(app_name, 'app_name')
4181 key = cstr(key, 'key')
4182 value = cstr(value, 'value')
4184 char *_app_name = app_name
4186 char *_value = value
4189 ret = rados_application_metadata_set(self.io, _app_name, _key,
4192 raise make_ex(ret, "error setting application metadata")
4194 def application_metadata_remove(self, app_name, key):
4196 Remove application metadata from an OSD pool
4198 :param app_name: application name
4200 :param key: metadata key
4203 :raises: :class:`Error`
4205 app_name = cstr(app_name, 'app_name')
4206 key = cstr(key, 'key')
4208 char *_app_name = app_name
4212 ret = rados_application_metadata_remove(self.io, _app_name, _key)
4214 raise make_ex(ret, "error removing application metadata")
4216 def application_metadata_list(self, app_name):
4218 Returns a list of enabled applications
4220 :param app_name: application name
4222 :returns: list of key/value tuples
4224 app_name = cstr(app_name, 'app_name')
4226 char *_app_name = app_name
4227 size_t key_length = 128
4228 size_t val_length = 128
4234 c_keys = <char *>realloc_chk(c_keys, key_length)
4235 c_vals = <char *>realloc_chk(c_vals, val_length)
4237 ret = rados_application_metadata_list(self.io, _app_name,
4238 c_keys, &key_length,
4239 c_vals, &val_length)
4241 keys = [decode_cstr(key) for key in
4242 c_keys[:key_length].split(b'\0')]
4243 vals = [decode_cstr(val) for val in
4244 c_vals[:val_length].split(b'\0')]
4245 return list(zip(keys, vals))[:-1]
4246 elif ret == -errno.ERANGE:
4249 raise make_ex(ret, "error listing application metadata")
4254 def alignment(self):
4256 Returns pool alignment
4259 Number of alignment bytes required by the current pool, or None if
4260 alignment is not required.
4267 ret = rados_ioctx_pool_requires_alignment2(self.io, &requires)
4269 raise make_ex(ret, "error checking alignment")
4274 ret = rados_ioctx_pool_required_alignment2(self.io, &_alignment)
4276 raise make_ex(ret, "error querying alignment")
4277 alignment = _alignment
4281 def set_object_locator(func):
4282 def retfunc(self, *args, **kwargs):
4283 if self.locator_key is not None:
4284 old_locator = self.ioctx.get_locator_key()
4285 self.ioctx.set_locator_key(self.locator_key)
4286 retval = func(self, *args, **kwargs)
4287 self.ioctx.set_locator_key(old_locator)
4290 return func(self, *args, **kwargs)
4294 def set_object_namespace(func):
4295 def retfunc(self, *args, **kwargs):
4296 if self.nspace is None:
4297 raise LogicError("Namespace not set properly in context")
4298 old_nspace = self.ioctx.get_namespace()
4299 self.ioctx.set_namespace(self.nspace)
4300 retval = func(self, *args, **kwargs)
4301 self.ioctx.set_namespace(old_nspace)
4306 class Object(object):
4307 """Rados object wrapper, makes the object look like a file"""
4308 def __init__(self, ioctx, key, locator_key=None, nspace=None):
4312 self.state = "exists"
4313 self.locator_key = locator_key
4314 self.nspace = "" if nspace is None else nspace
4317 return "rados.Object(ioctx=%s,key=%s,nspace=%s,locator=%s)" % \
4318 (str(self.ioctx), self.key, "--default--"
4319 if self.nspace is "" else self.nspace, self.locator_key)
4321 def require_object_exists(self):
4322 if self.state != "exists":
4323 raise ObjectStateError("The object is %s" % self.state)
4326 @set_object_namespace
4327 def read(self, length=1024 * 1024):
4328 self.require_object_exists()
4329 ret = self.ioctx.read(self.key, length, self.offset)
4330 self.offset += len(ret)
4334 @set_object_namespace
4335 def write(self, string_to_write):
4336 self.require_object_exists()
4337 ret = self.ioctx.write(self.key, string_to_write, self.offset)
4339 self.offset += len(string_to_write)
4343 @set_object_namespace
4345 self.require_object_exists()
4346 self.ioctx.remove_object(self.key)
4347 self.state = "removed"
4350 @set_object_namespace
4352 self.require_object_exists()
4353 return self.ioctx.stat(self.key)
4355 def seek(self, position):
4356 self.require_object_exists()
4357 self.offset = position
4360 @set_object_namespace
4361 def get_xattr(self, xattr_name):
4362 self.require_object_exists()
4363 return self.ioctx.get_xattr(self.key, xattr_name)
4366 @set_object_namespace
4367 def get_xattrs(self):
4368 self.require_object_exists()
4369 return self.ioctx.get_xattrs(self.key)
4372 @set_object_namespace
4373 def set_xattr(self, xattr_name, xattr_value):
4374 self.require_object_exists()
4375 return self.ioctx.set_xattr(self.key, xattr_name, xattr_value)
4378 @set_object_namespace
4379 def rm_xattr(self, xattr_name):
4380 self.require_object_exists()
4381 return self.ioctx.rm_xattr(self.key, xattr_name)
4392 class MonitorLog(object):
4393 # NOTE(sileht): Keep this class for backward compat
4394 # method moved to Rados.monitor_log()
4396 For watching cluster log messages. Instantiate an object and keep
4397 it around while callback is periodically called. Construct with
4398 'level' to monitor 'level' messages (one of MONITOR_LEVELS).
4399 arg will be passed to the callback.
4401 callback will be called with:
4402 arg (given to __init__)
4403 line (the full line, including timestamp, who, level, msg)
4404 who (which entity issued the log message)
4405 timestamp_sec (sec of a struct timespec)
4406 timestamp_nsec (sec of a struct timespec)
4407 seq (sequence number)
4408 level (string representing the level of the log message)
4409 msg (the message itself)
4410 callback's return value is ignored
4412 def __init__(self, cluster, level, callback, arg):
4414 self.callback = callback
4416 self.cluster = cluster
4417 self.cluster.monitor_log(level, callback, arg)