]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/rados/rados.pyx
d/control: depend on python3-yaml for ceph-mgr
[ceph.git] / ceph / src / pybind / rados / rados.pyx
CommitLineData
7c673cae
FG
1# cython: embedsignature=True
2"""
3This module is a thin wrapper around librados.
4
5Error 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`
8and :class:`IOError`, in addition to those documented for the
9method.
10"""
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>
15
16from cpython cimport PyObject, ref
17from cpython.pycapsule cimport *
18from libc cimport errno
19from libc.stdint cimport *
20from libc.stdlib cimport malloc, realloc, free
21
22import sys
23import threading
24import time
25
11fdf7f2
TL
26try:
27 from collections.abc import Callable
28except ImportError:
29 from collections import Callable
7c673cae
FG
30from datetime import datetime
31from functools import partial, wraps
32from itertools import chain
33
34# Are we running Python 2.x
35if sys.version_info[0] < 3:
36 str_type = basestring
37else:
38 str_type = str
39
40
41cdef 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()
50
51
52cdef extern from "time.h":
53 ctypedef long int time_t
54 ctypedef long int suseconds_t
55
56
57cdef extern from "sys/time.h":
58 cdef struct timeval:
59 time_t tv_sec
60 suseconds_t tv_usec
61
62
63cdef extern from "rados/rados_types.h" nogil:
64 cdef char* _LIBRADOS_ALL_NSPACES "LIBRADOS_ALL_NSPACES"
65
66
67cdef extern from "rados/librados.h" nogil:
68 enum:
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"
76
77
78 enum:
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"
88
89 cdef uint64_t _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
90
7c673cae
FG
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)
224ce89b 101 ctypedef void (*rados_log_callback2_t)(void *arg, const char *line, const char *channel, const char *who, const char *name,
31f18b77 102 uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg)
7c673cae
FG
103
104
105 cdef struct rados_cluster_stat_t:
106 uint64_t kb
107 uint64_t kb_used
108 uint64_t kb_avail
109 uint64_t num_objects
110
111 cdef struct rados_pool_stat_t:
112 uint64_t num_bytes
113 uint64_t num_kb
114 uint64_t num_objects
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
120 uint64_t num_rd
121 uint64_t num_rd_kb
122 uint64_t num_wr
123 uint64_t num_wr_kb
124
125 void rados_buffer_free(char *buf)
126
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)
11fdf7f2 133 uint64_t rados_get_instance_id(rados_t cluster)
7c673cae
FG
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)
139
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)
7c673cae 144 int rados_pool_create_with_crush_rule(rados_t cluster, const char *pool_name, uint8_t crush_rule_num)
9f95a23c
TL
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)
7c673cae
FG
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)
151
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)
9f95a23c 155 int rados_getaddrs(rados_t cluster, char** addrs)
c07f9fc5
FG
156 int rados_application_enable(rados_ioctx_t io, const char *app_name,
157 int force)
11fdf7f2
TL
158 void rados_set_osdmap_full_try(rados_ioctx_t io)
159 void rados_unset_osdmap_full_try(rados_ioctx_t io)
c07f9fc5
FG
160 int rados_application_list(rados_ioctx_t io, char *values,
161 size_t *values_len)
162 int rados_application_metadata_get(rados_ioctx_t io, const char *app_name,
163 const char *key, char *value,
164 size_t *value_len)
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,
172 size_t *value_len)
7c673cae
FG
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)
9f95a23c
TL
182 int rados_mgr_command_target(rados_t cluster,
183 const char *name,
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)
7c673cae
FG
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)
31f18b77 201 int rados_monitor_log2(rados_t cluster, const char *level, rados_log_callback2_t cb, void *arg)
7c673cae
FG
202
203 int rados_wait_for_latest_osdmap(rados_t cluster)
204
11fdf7f2
TL
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)
207
7c673cae 208 int rados_ioctx_create(rados_t cluster, const char *pool_name, rados_ioctx_t *ioctx)
11fdf7f2 209 int rados_ioctx_create2(rados_t cluster, int64_t pool_id, rados_ioctx_t *ioctx)
7c673cae 210 void rados_ioctx_destroy(rados_ioctx_t io)
7c673cae
FG
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)
213
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)
9f95a23c 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)
7c673cae
FG
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)
229
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)
233
11fdf7f2
TL
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)
236
7c673cae
FG
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)
9f95a23c
TL
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)
7c673cae 247
28e407b8
AA
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,
251 rados_snap_t snapid)
252 int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io,
253 rados_snap_t snap_seq,
254 rados_snap_t *snap,
255 int num_snaps)
256 int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io, const char *oid,
257 rados_snap_t snapid)
258
7c673cae
FG
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)
266
267 rados_write_op_t rados_create_write_op()
268 void rados_release_write_op(rados_write_op_t write_op)
269
270 rados_read_op_t rados_create_read_op()
271 void rados_release_read_op(rados_read_op_t read_op)
272
9f95a23c 273 int rados_aio_create_completion2(void * cb_arg, rados_callback_t cb_complete, rados_completion_t * pc)
7c673cae
FG
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)
9f95a23c 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)
7c673cae
FG
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)
283
284 int rados_aio_get_return_value(rados_completion_t c)
285 int rados_aio_wait_for_complete_and_cb(rados_completion_t c)
7c673cae 286 int rados_aio_wait_for_complete(rados_completion_t c)
7c673cae 287 int rados_aio_is_complete(rados_completion_t c)
7c673cae
FG
288
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)
293
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)
9f95a23c
TL
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)
7c673cae
FG
302
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)
91327a77 306 void rados_write_op_assert_version(rados_write_op_t write_op, uint64_t ver)
7c673cae
FG
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)
9f95a23c
TL
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)
d2e6a577
FG
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)
7c673cae
FG
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)
11fdf7f2 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)
7c673cae
FG
322
323
324LIBRADOS_OP_FLAG_EXCL = _LIBRADOS_OP_FLAG_EXCL
325LIBRADOS_OP_FLAG_FAILOK = _LIBRADOS_OP_FLAG_FAILOK
326LIBRADOS_OP_FLAG_FADVISE_RANDOM = _LIBRADOS_OP_FLAG_FADVISE_RANDOM
327LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL = _LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
328LIBRADOS_OP_FLAG_FADVISE_WILLNEED = _LIBRADOS_OP_FLAG_FADVISE_WILLNEED
329LIBRADOS_OP_FLAG_FADVISE_DONTNEED = _LIBRADOS_OP_FLAG_FADVISE_DONTNEED
330LIBRADOS_OP_FLAG_FADVISE_NOCACHE = _LIBRADOS_OP_FLAG_FADVISE_NOCACHE
331
332LIBRADOS_SNAP_HEAD = _LIBRADOS_SNAP_HEAD
333
334LIBRADOS_OPERATION_NOFLAG = _LIBRADOS_OPERATION_NOFLAG
335LIBRADOS_OPERATION_BALANCE_READS = _LIBRADOS_OPERATION_BALANCE_READS
336LIBRADOS_OPERATION_LOCALIZE_READS = _LIBRADOS_OPERATION_LOCALIZE_READS
337LIBRADOS_OPERATION_ORDER_READS_WRITES = _LIBRADOS_OPERATION_ORDER_READS_WRITES
338LIBRADOS_OPERATION_IGNORE_CACHE = _LIBRADOS_OPERATION_IGNORE_CACHE
339LIBRADOS_OPERATION_SKIPRWLOCKS = _LIBRADOS_OPERATION_SKIPRWLOCKS
340LIBRADOS_OPERATION_IGNORE_OVERLAY = _LIBRADOS_OPERATION_IGNORE_OVERLAY
341
342LIBRADOS_ALL_NSPACES = _LIBRADOS_ALL_NSPACES.decode('utf-8')
343
344LIBRADOS_CREATE_EXCLUSIVE = _LIBRADOS_CREATE_EXCLUSIVE
345LIBRADOS_CREATE_IDEMPOTENT = _LIBRADOS_CREATE_IDEMPOTENT
346
347ANONYMOUS_AUID = 0xffffffffffffffff
348ADMIN_AUID = 0
349
350
351class Error(Exception):
352 """ `Error` class, derived from `Exception` """
224ce89b 353 def __init__(self, message, errno=None):
1adf2230 354 super(Exception, self).__init__(message)
7c673cae 355 self.errno = errno
7c673cae
FG
356
357 def __str__(self):
1adf2230 358 msg = super(Exception, self).__str__()
224ce89b
WB
359 if self.errno is None:
360 return msg
361 return '[errno {0}] {1}'.format(self.errno, msg)
7c673cae 362
224ce89b
WB
363 def __reduce__(self):
364 return (self.__class__, (self.message, self.errno))
7c673cae 365
1adf2230 366class InvalidArgumentError(Error):
9f95a23c
TL
367 def __init__(self, message, errno=None):
368 super(InvalidArgumentError, self).__init__(
369 "RADOS invalid argument (%s)" % message, errno)
370
1adf2230
AA
371
372class OSError(Error):
373 """ `OSError` class, derived from `Error` """
374 pass
375
7c673cae
FG
376class InterruptedOrTimeoutError(OSError):
377 """ `InterruptedOrTimeoutError` class, derived from `OSError` """
9f95a23c
TL
378 def __init__(self, message, errno=None):
379 super(InterruptedOrTimeoutError, self).__init__(
380 "RADOS interrupted or timeout (%s)" % message, errno)
7c673cae
FG
381
382
383class PermissionError(OSError):
384 """ `PermissionError` class, derived from `OSError` """
9f95a23c
TL
385 def __init__(self, message, errno=None):
386 super(PermissionError, self).__init__(
387 "RADOS permission error (%s)" % message, errno)
7c673cae
FG
388
389
390class PermissionDeniedError(OSError):
391 """ deal with EACCES related. """
9f95a23c
TL
392 def __init__(self, message, errno=None):
393 super(PermissionDeniedError, self).__init__(
394 "RADOS permission denied (%s)" % message, errno)
7c673cae
FG
395
396
397class ObjectNotFound(OSError):
398 """ `ObjectNotFound` class, derived from `OSError` """
9f95a23c
TL
399 def __init__(self, message, errno=None):
400 super(ObjectNotFound, self).__init__(
401 "RADOS object not found (%s)" % message, errno)
7c673cae
FG
402
403
404class NoData(OSError):
405 """ `NoData` class, derived from `OSError` """
9f95a23c
TL
406 def __init__(self, message, errno=None):
407 super(NoData, self).__init__(
408 "RADOS no data (%s)" % message, errno)
7c673cae
FG
409
410
411class ObjectExists(OSError):
412 """ `ObjectExists` class, derived from `OSError` """
9f95a23c
TL
413 def __init__(self, message, errno=None):
414 super(ObjectExists, self).__init__(
415 "RADOS object exists (%s)" % message, errno)
7c673cae
FG
416
417
418class ObjectBusy(OSError):
419 """ `ObjectBusy` class, derived from `IOError` """
9f95a23c
TL
420 def __init__(self, message, errno=None):
421 super(ObjectBusy, self).__init__(
422 "RADOS object busy (%s)" % message, errno)
7c673cae
FG
423
424
425class IOError(OSError):
426 """ `ObjectBusy` class, derived from `OSError` """
9f95a23c
TL
427 def __init__(self, message, errno=None):
428 super(IOError, self).__init__(
429 "RADOS I/O error (%s)" % message, errno)
7c673cae
FG
430
431
432class NoSpace(OSError):
433 """ `NoSpace` class, derived from `OSError` """
9f95a23c
TL
434 def __init__(self, message, errno=None):
435 super(NoSpace, self).__init__(
436 "RADOS no space (%s)" % message, errno)
7c673cae
FG
437
438
439class RadosStateError(Error):
440 """ `RadosStateError` class, derived from `Error` """
9f95a23c
TL
441 def __init__(self, message, errno=None):
442 super(RadosStateError, self).__init__(
443 "RADOS rados state (%s)" % message, errno)
7c673cae
FG
444
445
446class IoctxStateError(Error):
447 """ `IoctxStateError` class, derived from `Error` """
9f95a23c
TL
448 def __init__(self, message, errno=None):
449 super(IoctxStateError, self).__init__(
450 "RADOS Ioctx state error (%s)" % message, errno)
7c673cae
FG
451
452
453class ObjectStateError(Error):
454 """ `ObjectStateError` class, derived from `Error` """
9f95a23c
TL
455 def __init__(self, message, errno=None):
456 super(ObjectStateError, self).__init__(
457 "RADOS object state error (%s)" % message, errno)
7c673cae
FG
458
459
460class LogicError(Error):
461 """ `` class, derived from `Error` """
9f95a23c
TL
462 def __init__(self, message, errno=None):
463 super(LogicError, self).__init__(
464 "RADOS logic error (%s)" % message, errno)
7c673cae
FG
465
466
467class TimedOut(OSError):
468 """ `TimedOut` class, derived from `OSError` """
9f95a23c
TL
469 def __init__(self, message, errno=None):
470 super(TimedOut, self).__init__(
471 "RADOS timed out (%s)" % message, errno)
472
473
474class 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)
479
480
481class 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)
7c673cae
FG
486
487
488IF UNAME_SYSNAME == "FreeBSD":
489 cdef errno_to_exception = {
490 errno.EPERM : PermissionError,
491 errno.ENOENT : ObjectNotFound,
492 errno.EIO : IOError,
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,
9f95a23c
TL
500 errno.EINPROGRESS : InProgress,
501 errno.EISCONN : IsConnected,
7c673cae
FG
502 errno.EINVAL : InvalidArgumentError,
503 }
504ELSE:
505 cdef errno_to_exception = {
506 errno.EPERM : PermissionError,
507 errno.ENOENT : ObjectNotFound,
508 errno.EIO : IOError,
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,
9f95a23c
TL
516 errno.EINPROGRESS : InProgress,
517 errno.EISCONN : IsConnected,
7c673cae
FG
518 errno.EINVAL : InvalidArgumentError,
519 }
520
521
522cdef make_ex(ret, msg):
523 """
524 Translate a librados return code into an exception.
525
526 :param ret: the return code
527 :type ret: int
528 :param msg: the error message to use
529 :type msg: str
530 :returns: a subclass of :class:`Error`
531 """
532 ret = abs(ret)
533 if ret in errno_to_exception:
224ce89b 534 return errno_to_exception[ret](msg, errno=ret)
7c673cae 535 else:
224ce89b 536 return OSError(msg, errno=ret)
7c673cae
FG
537
538
539# helper to specify an optional argument, where in addition to `cls`, `None`
540# is also acceptable
541def opt(cls):
542 return (cls, None)
543
544
545# validate argument types of an instance method
546# kwargs is an un-ordered dict, so use args instead
547def requires(*types):
548 def is_type_of(v, t):
549 if t is None:
550 return v is None
551 else:
552 return isinstance(v, t)
553
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):
557 return
558 type_names = ' or '.join('None' if t is None else t.__name__
559 for t in arg_type)
560 raise TypeError('%s must be %s' % (arg_name, type_names))
561 else:
562 if is_type_of(val, arg_type):
563 return
564 assert(arg_type is not None)
565 raise TypeError('%s must be %s' % (arg_name, arg_type.__name__))
566
567 def wrapper(f):
568 # FIXME(sileht): this stop with
569 # AttributeError: 'method_descriptor' object has no attribute '__module__'
570 # @wraps(f)
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
575 if name in kwargs)
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)
579 return validate_func
580 return wrapper
581
582
583def cstr(val, name, encoding="utf-8", opt=False):
584 """
585 Create a byte string from a Python string
586
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
591 :rtype: bytes
592 :raises: :class:`InvalidArgument`
593 """
594 if opt and val is None:
595 return None
596 if isinstance(val, bytes):
597 return val
598 elif isinstance(val, unicode):
599 return val.encode(encoding)
600 else:
601 raise TypeError('%s must be a string' % name)
602
603
604def cstr_list(list_str, name, encoding="utf-8"):
605 return [cstr(s, name) for s in list_str]
606
607
608def decode_cstr(val, encoding="utf-8"):
609 """
610 Decode a byte string into a Python string.
611
612 :param bytes val: byte string
613 :rtype: unicode or None
614 """
615 if val is None:
616 return None
617
618 return val.decode(encoding)
619
620
9f95a23c
TL
621def flatten_dict(d, name):
622 items = chain.from_iterable(d.items())
623 return cstr(''.join(i + '\0' for i in items), name)
624
625
7c673cae
FG
626cdef char* opt_str(s) except? NULL:
627 if s is None:
628 return NULL
629 return s
630
631
632cdef void* realloc_chk(void* ptr, size_t size) except NULL:
633 cdef void *ret = realloc(ptr, size)
634 if ret == NULL:
635 raise MemoryError("realloc failed")
636 return ret
637
638
639cdef size_t * to_csize_t_array(list_int):
640 cdef size_t *ret = <size_t *>malloc(len(list_int) * sizeof(size_t))
641 if ret == NULL:
642 raise MemoryError("malloc failed")
643 for i in xrange(len(list_int)):
644 ret[i] = <size_t>list_int[i]
645 return ret
646
647
648cdef char ** to_bytes_array(list_bytes):
649 cdef char **ret = <char **>malloc(len(list_bytes) * sizeof(char *))
650 if ret == NULL:
651 raise MemoryError("malloc failed")
652 for i in xrange(len(list_bytes)):
653 ret[i] = <char *>list_bytes[i]
654 return ret
655
656
657
658cdef 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)
663 return 0
664
224ce89b
WB
665cdef int __monitor_callback2(void *arg, const char *line, const char *channel,
666 const char *who,
31f18b77
FG
667 const char *name,
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
224ce89b 671 cb_info[0](cb_info[1], line, channel, name, who, sec, nsec, seq, level, msg)
31f18b77
FG
672 return 0
673
7c673cae
FG
674
675class Version(object):
676 """ Version information """
677 def __init__(self, major, minor, extra):
678 self.major = major
679 self.minor = minor
680 self.extra = extra
681
682 def __str__(self):
683 return "%d.%d.%d" % (self.major, self.minor, self.extra)
684
685
686cdef class Rados(object):
687 """This class wraps librados functions"""
688 # NOTE(sileht): attributes declared in .pyd
689
690 def __init__(self, *args, **kwargs):
691 PyEval_InitThreads()
692 self.__setup(*args, **kwargs)
693
694 @requires(('rados_id', opt(str_type)), ('name', opt(str_type)), ('clustername', opt(str_type)),
695 ('conffile', opt(str_type)))
696 def __setup(self, rados_id=None, name=None, clustername=None,
697 conf_defaults=None, conffile=None, conf=None, flags=0,
698 context=None):
699 self.monitor_callback = None
31f18b77 700 self.monitor_callback2 = None
7c673cae
FG
701 self.parsed_args = []
702 self.conf_defaults = conf_defaults
703 self.conffile = conffile
704 self.rados_id = rados_id
705
706 if rados_id and name:
707 raise Error("Rados(): can't supply both rados_id and name")
708 elif rados_id:
709 name = 'client.' + rados_id
710 elif name is None:
711 name = 'client.admin'
712 if clustername is None:
713 clustername = ''
714
715 name = cstr(name, 'name')
716 clustername = cstr(clustername, 'clustername')
717 cdef:
718 char *_name = name
719 char *_clustername = clustername
720 int _flags = flags
721 int ret
722
723 if context:
724 # Unpack void* (aka rados_config_t) from capsule
725 rados_config = <rados_config_t> PyCapsule_GetPointer(context, NULL)
726 with nogil:
727 ret = rados_create_with_context(&self.cluster, rados_config)
728 else:
729 with nogil:
730 ret = rados_create2(&self.cluster, _clustername, _name, _flags)
731 if ret != 0:
732 raise Error("rados_initialize failed with error code: %d" % ret)
733
734 self.state = "configuring"
735 # order is important: conf_defaults, then conffile, then conf
736 if conf_defaults:
737 for key, value in conf_defaults.items():
738 self.conf_set(key, value)
739 if conffile is not None:
740 # read the default conf file when '' is given
741 if conffile == '':
742 conffile = None
743 self.conf_read_file(conffile)
744 if conf:
745 for key, value in conf.items():
746 self.conf_set(key, value)
747
9f95a23c
TL
748 def get_addrs(self):
749 """
750 Get associated client addresses with this RADOS session.
751 """
752 self.require_state("configuring", "connected")
753
754 cdef:
755 char* addrs = NULL
756
757 try:
758
759 with nogil:
760 ret = rados_getaddrs(self.cluster, &addrs)
761 if ret:
762 raise make_ex(ret, "error calling getaddrs")
763
764 return decode_cstr(addrs)
765 finally:
766 free(addrs)
767
7c673cae
FG
768 def require_state(self, *args):
769 """
770 Checks if the Rados object is in a special state
771
11fdf7f2 772 :raises: :class:`RadosStateError`
7c673cae
FG
773 """
774 if self.state in args:
775 return
776 raise RadosStateError("You cannot perform that operation on a \
777Rados object in state %s." % self.state)
778
779 def shutdown(self):
780 """
781 Disconnects from the cluster. Call this explicitly when a
782 Rados.connect()ed object is no longer used.
783 """
784 if self.state != "shutdown":
785 with nogil:
786 rados_shutdown(self.cluster)
787 self.state = "shutdown"
788
789 def __enter__(self):
790 self.connect()
791 return self
792
793 def __exit__(self, type_, value, traceback):
794 self.shutdown()
795 return False
796
797 def version(self):
798 """
799 Get the version number of the ``librados`` C library.
800
801 :returns: a tuple of ``(major, minor, extra)`` components of the
802 librados version
803 """
804 cdef int major = 0
805 cdef int minor = 0
806 cdef int extra = 0
807 with nogil:
808 rados_version(&major, &minor, &extra)
809 return Version(major, minor, extra)
810
811 @requires(('path', opt(str_type)))
812 def conf_read_file(self, path=None):
813 """
814 Configure the cluster handle using a Ceph config file.
815
816 :param path: path to the config file
817 :type path: str
818 """
819 self.require_state("configuring", "connected")
820 path = cstr(path, 'path', opt=True)
821 cdef:
822 char *_path = opt_str(path)
823 with nogil:
824 ret = rados_conf_read_file(self.cluster, _path)
825 if ret != 0:
826 raise make_ex(ret, "error calling conf_read_file")
827
828 def conf_parse_argv(self, args):
829 """
830 Parse known arguments from args, and remove; returned
831 args contain only those unknown to ceph
832 """
833 self.require_state("configuring", "connected")
834 if not args:
835 return
836
837 cargs = cstr_list(args, 'args')
838 cdef:
839 int _argc = len(args)
840 char **_argv = to_bytes_array(cargs)
841 char **_remargv = NULL
842
843 try:
844 _remargv = <char **>malloc(_argc * sizeof(char *))
845 with nogil:
846 ret = rados_conf_parse_argv_remainder(self.cluster, _argc,
847 <const char**>_argv,
848 <const char**>_remargv)
849 if ret:
850 raise make_ex(ret, "error calling conf_parse_argv_remainder")
851
852 # _remargv was allocated with fixed argc; collapse return
853 # list to eliminate any missing args
854 retargs = [decode_cstr(a) for a in _remargv[:_argc]
855 if a != NULL]
856 self.parsed_args = args
857 return retargs
858 finally:
859 free(_argv)
860 free(_remargv)
861
862 def conf_parse_env(self, var='CEPH_ARGS'):
863 """
864 Parse known arguments from an environment variable, normally
865 CEPH_ARGS.
866 """
867 self.require_state("configuring", "connected")
868 if not var:
869 return
870
871 var = cstr(var, 'var')
872 cdef:
873 char *_var = var
874 with nogil:
875 ret = rados_conf_parse_env(self.cluster, _var)
876 if ret != 0:
877 raise make_ex(ret, "error calling conf_parse_env")
878
879 @requires(('option', str_type))
880 def conf_get(self, option):
881 """
882 Get the value of a configuration option
883
884 :param option: which option to read
885 :type option: str
886
887 :returns: str - value of the option or None
888 :raises: :class:`TypeError`
889 """
890 self.require_state("configuring", "connected")
891 option = cstr(option, 'option')
892 cdef:
893 char *_option = option
894 size_t length = 20
895 char *ret_buf = NULL
896
897 try:
898 while True:
899 ret_buf = <char *>realloc_chk(ret_buf, length)
900 with nogil:
901 ret = rados_conf_get(self.cluster, _option, ret_buf, length)
902 if ret == 0:
903 return decode_cstr(ret_buf)
904 elif ret == -errno.ENAMETOOLONG:
905 length = length * 2
906 elif ret == -errno.ENOENT:
907 return None
908 else:
909 raise make_ex(ret, "error calling conf_get")
910 finally:
911 free(ret_buf)
912
913 @requires(('option', str_type), ('val', str_type))
914 def conf_set(self, option, val):
915 """
916 Set the value of a configuration option
917
918 :param option: which option to set
919 :type option: str
920 :param option: value of the option
921 :type option: str
922
923 :raises: :class:`TypeError`, :class:`ObjectNotFound`
924 """
925 self.require_state("configuring", "connected")
926 option = cstr(option, 'option')
927 val = cstr(val, 'val')
928 cdef:
929 char *_option = option
930 char *_val = val
931
932 with nogil:
933 ret = rados_conf_set(self.cluster, _option, _val)
934 if ret != 0:
935 raise make_ex(ret, "error calling conf_set")
936
937 def ping_monitor(self, mon_id):
938 """
939 Ping a monitor to assess liveness
940
941 May be used as a simply way to assess liveness, or to obtain
942 information about the monitor in a simple way even in the
943 absence of quorum.
944
945 :param mon_id: the ID portion of the monitor's name (i.e., mon.<ID>)
946 :type mon_id: str
947 :returns: the string reply from the monitor
948 """
949
950 self.require_state("configuring", "connected")
951
952 mon_id = cstr(mon_id, 'mon_id')
953 cdef:
954 char *_mon_id = mon_id
31f18b77 955 size_t outstrlen = 0
7c673cae
FG
956 char *outstr
957
958 with nogil:
959 ret = rados_ping_monitor(self.cluster, _mon_id, &outstr, &outstrlen)
960
961 if ret != 0:
962 raise make_ex(ret, "error calling ping_monitor")
963
964 if outstrlen:
965 my_outstr = outstr[:outstrlen]
966 rados_buffer_free(outstr)
967 return decode_cstr(my_outstr)
968
969 def connect(self, timeout=0):
970 """
971 Connect to the cluster. Use shutdown() to release resources.
972 """
973 self.require_state("configuring")
974 # NOTE(sileht): timeout was supported by old python API,
975 # but this is not something available in C API, so ignore
976 # for now and remove it later
977 with nogil:
978 ret = rados_connect(self.cluster)
979 if ret != 0:
980 raise make_ex(ret, "error connecting to the cluster")
981 self.state = "connected"
982
11fdf7f2
TL
983 def get_instance_id(self):
984 """
985 Get a global id for current instance
986 """
987 self.require_state("connected")
988 with nogil:
989 ret = rados_get_instance_id(self.cluster)
990 return ret;
991
7c673cae
FG
992 def get_cluster_stats(self):
993 """
994 Read usage info about the cluster
995
996 This tells you total space, space used, space available, and number
997 of objects. These are not updated immediately when data is written,
998 they are eventually consistent.
999
1000 :returns: dict - contains the following keys:
1001
1002 - ``kb`` (int) - total space
1003
1004 - ``kb_used`` (int) - space used
1005
1006 - ``kb_avail`` (int) - free space available
1007
1008 - ``num_objects`` (int) - number of objects
1009
1010 """
1011 cdef:
1012 rados_cluster_stat_t stats
1013
1014 with nogil:
1015 ret = rados_cluster_stat(self.cluster, &stats)
1016
1017 if ret < 0:
1018 raise make_ex(
1019 ret, "Rados.get_cluster_stats(%s): get_stats failed" % self.rados_id)
1020 return {'kb': stats.kb,
1021 'kb_used': stats.kb_used,
1022 'kb_avail': stats.kb_avail,
1023 'num_objects': stats.num_objects}
1024
1025 @requires(('pool_name', str_type))
1026 def pool_exists(self, pool_name):
1027 """
1028 Checks if a given pool exists.
1029
1030 :param pool_name: name of the pool to check
1031 :type pool_name: str
1032
1033 :raises: :class:`TypeError`, :class:`Error`
1034 :returns: bool - whether the pool exists, false otherwise.
1035 """
1036 self.require_state("connected")
1037
1038 pool_name = cstr(pool_name, 'pool_name')
1039 cdef:
1040 char *_pool_name = pool_name
1041
1042 with nogil:
1043 ret = rados_pool_lookup(self.cluster, _pool_name)
1044 if ret >= 0:
1045 return True
1046 elif ret == -errno.ENOENT:
1047 return False
1048 else:
1049 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
1050
1051 @requires(('pool_name', str_type))
1052 def pool_lookup(self, pool_name):
1053 """
1054 Returns a pool's ID based on its name.
1055
1056 :param pool_name: name of the pool to look up
1057 :type pool_name: str
1058
1059 :raises: :class:`TypeError`, :class:`Error`
1060 :returns: int - pool ID, or None if it doesn't exist
1061 """
1062 self.require_state("connected")
1063 pool_name = cstr(pool_name, 'pool_name')
1064 cdef:
1065 char *_pool_name = pool_name
1066
1067 with nogil:
1068 ret = rados_pool_lookup(self.cluster, _pool_name)
1069 if ret >= 0:
1070 return int(ret)
1071 elif ret == -errno.ENOENT:
1072 return None
1073 else:
1074 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
1075
1076 @requires(('pool_id', int))
1077 def pool_reverse_lookup(self, pool_id):
1078 """
1079 Returns a pool's name based on its ID.
1080
1081 :param pool_id: ID of the pool to look up
1082 :type pool_id: int
1083
1084 :raises: :class:`TypeError`, :class:`Error`
1085 :returns: string - pool name, or None if it doesn't exist
1086 """
1087 self.require_state("connected")
1088 cdef:
1089 int64_t _pool_id = pool_id
1090 size_t size = 512
1091 char *name = NULL
1092
1093 try:
1094 while True:
1095 name = <char *>realloc_chk(name, size)
1096 with nogil:
1097 ret = rados_pool_reverse_lookup(self.cluster, _pool_id, name, size)
1098 if ret >= 0:
1099 break
1100 elif ret != -errno.ERANGE and size <= 4096:
1101 size *= 2
1102 elif ret == -errno.ENOENT:
1103 return None
1104 elif ret < 0:
1105 raise make_ex(ret, "error reverse looking up pool '%s'" % pool_id)
1106
1107 return decode_cstr(name)
1108
1109 finally:
1110 free(name)
1111
9f95a23c
TL
1112 @requires(('pool_name', str_type), ('crush_rule', opt(int)), ('auid', opt(int)))
1113 def create_pool(self, pool_name, crush_rule=None, auid=None):
7c673cae
FG
1114 """
1115 Create a pool:
9f95a23c 1116 - with default settings: if crush_rule=None and auid=None
11fdf7f2 1117 - with a specific CRUSH rule: crush_rule given
9f95a23c
TL
1118 - with a specific auid: auid given
1119 - with a specific CRUSH rule and auid: crush_rule and auid given
1120
7c673cae
FG
1121 :param pool_name: name of the pool to create
1122 :type pool_name: str
7c673cae
FG
1123 :param crush_rule: rule to use for placement in the new pool
1124 :type crush_rule: int
9f95a23c
TL
1125 :param auid: id of the owner of the new pool
1126 :type auid: int
7c673cae
FG
1127
1128 :raises: :class:`TypeError`, :class:`Error`
1129 """
1130 self.require_state("connected")
1131
1132 pool_name = cstr(pool_name, 'pool_name')
1133 cdef:
1134 char *_pool_name = pool_name
1135 uint8_t _crush_rule
9f95a23c 1136 uint64_t _auid
7c673cae 1137
9f95a23c 1138 if crush_rule is None and auid is None:
7c673cae
FG
1139 with nogil:
1140 ret = rados_pool_create(self.cluster, _pool_name)
9f95a23c 1141 elif crush_rule is not None and auid is None:
7c673cae
FG
1142 _crush_rule = crush_rule
1143 with nogil:
11fdf7f2 1144 ret = rados_pool_create_with_crush_rule(self.cluster, _pool_name, _crush_rule)
9f95a23c
TL
1145 elif crush_rule is None and auid is not None:
1146 _auid = auid
1147 with nogil:
1148 ret = rados_pool_create_with_auid(self.cluster, _pool_name, _auid)
1149 else:
1150 _crush_rule = crush_rule
1151 _auid = auid
1152 with nogil:
1153 ret = rados_pool_create_with_all(self.cluster, _pool_name, _auid, _crush_rule)
7c673cae
FG
1154 if ret < 0:
1155 raise make_ex(ret, "error creating pool '%s'" % pool_name)
1156
1157 @requires(('pool_id', int))
1158 def get_pool_base_tier(self, pool_id):
1159 """
1160 Get base pool
1161
1162 :returns: base pool, or pool_id if tiering is not configured for the pool
1163 """
1164 self.require_state("connected")
1165 cdef:
1166 int64_t base_tier = 0
1167 int64_t _pool_id = pool_id
1168
1169 with nogil:
1170 ret = rados_pool_get_base_tier(self.cluster, _pool_id, &base_tier)
1171 if ret < 0:
1172 raise make_ex(ret, "get_pool_base_tier(%d)" % pool_id)
1173 return int(base_tier)
1174
1175 @requires(('pool_name', str_type))
1176 def delete_pool(self, pool_name):
1177 """
1178 Delete a pool and all data inside it.
1179
1180 The pool is removed from the cluster immediately,
1181 but the actual data is deleted in the background.
1182
1183 :param pool_name: name of the pool to delete
1184 :type pool_name: str
1185
1186 :raises: :class:`TypeError`, :class:`Error`
1187 """
1188 self.require_state("connected")
1189
1190 pool_name = cstr(pool_name, 'pool_name')
1191 cdef:
1192 char *_pool_name = pool_name
1193
1194 with nogil:
1195 ret = rados_pool_delete(self.cluster, _pool_name)
1196 if ret < 0:
1197 raise make_ex(ret, "error deleting pool '%s'" % pool_name)
1198
1199 @requires(('pool_id', int))
1200 def get_inconsistent_pgs(self, pool_id):
1201 """
1202 List inconsistent placement groups in the given pool
1203
1204 :param pool_id: ID of the pool in which PGs are listed
1205 :type pool_id: int
1206 :returns: list - inconsistent placement groups
1207 """
1208 self.require_state("connected")
1209 cdef:
1210 int64_t pool = pool_id
1211 size_t size = 512
1212 char *pgs = NULL
1213
1214 try:
1215 while True:
1216 pgs = <char *>realloc_chk(pgs, size);
1217 with nogil:
1218 ret = rados_inconsistent_pg_list(self.cluster, pool,
1219 pgs, size)
1220 if ret > <int>size:
1221 size *= 2
1222 elif ret >= 0:
1223 break
1224 else:
1225 raise make_ex(ret, "error calling inconsistent_pg_list")
1226 return [pg for pg in decode_cstr(pgs[:ret]).split('\0') if pg]
1227 finally:
1228 free(pgs)
1229
1230 def list_pools(self):
1231 """
1232 Gets a list of pool names.
1233
1234 :returns: list - of pool names.
1235 """
1236 self.require_state("connected")
1237 cdef:
1238 size_t size = 512
1239 char *c_names = NULL
1240
1241 try:
1242 while True:
1243 c_names = <char *>realloc_chk(c_names, size)
1244 with nogil:
1245 ret = rados_pool_list(self.cluster, c_names, size)
1246 if ret > <int>size:
1247 size *= 2
1248 elif ret >= 0:
1249 break
1250 return [name for name in decode_cstr(c_names[:ret]).split('\0')
1251 if name]
1252 finally:
1253 free(c_names)
1254
1255 def get_fsid(self):
1256 """
1257 Get the fsid of the cluster as a hexadecimal string.
1258
1259 :raises: :class:`Error`
1260 :returns: str - cluster fsid
1261 """
1262 self.require_state("connected")
1263 cdef:
81eedcae
TL
1264 char *ret_buf = NULL
1265 size_t buf_len = 64
7c673cae 1266
7c673cae 1267 try:
81eedcae
TL
1268 while True:
1269 ret_buf = <char *>realloc_chk(ret_buf, buf_len)
1270 with nogil:
1271 ret = rados_cluster_fsid(self.cluster, ret_buf, buf_len)
1272 if ret == -errno.ERANGE:
1273 buf_len = buf_len * 2
1274 elif ret < 0:
1275 raise make_ex(ret, "error getting cluster fsid")
1276 else:
1277 break
1278 return decode_cstr(ret_buf)
7c673cae 1279 finally:
81eedcae 1280 free(ret_buf)
7c673cae
FG
1281
1282 @requires(('ioctx_name', str_type))
1283 def open_ioctx(self, ioctx_name):
1284 """
1285 Create an io context
1286
1287 The io context allows you to perform operations within a particular
1288 pool.
1289
1290 :param ioctx_name: name of the pool
1291 :type ioctx_name: str
1292
1293 :raises: :class:`TypeError`, :class:`Error`
1294 :returns: Ioctx - Rados Ioctx object
1295 """
1296 self.require_state("connected")
1297 ioctx_name = cstr(ioctx_name, 'ioctx_name')
1298 cdef:
1299 rados_ioctx_t ioctx
1300 char *_ioctx_name = ioctx_name
1301 with nogil:
1302 ret = rados_ioctx_create(self.cluster, _ioctx_name, &ioctx)
1303 if ret < 0:
1304 raise make_ex(ret, "error opening pool '%s'" % ioctx_name)
1305 io = Ioctx(ioctx_name)
1306 io.io = ioctx
1307 return io
1308
11fdf7f2
TL
1309 @requires(('pool_id', int))
1310 def open_ioctx2(self, pool_id):
1311 """
1312 Create an io context
1313
1314 The io context allows you to perform operations within a particular
1315 pool.
1316
1317 :param pool_id: ID of the pool
1318 :type pool_id: int
1319
1320 :raises: :class:`TypeError`, :class:`Error`
1321 :returns: Ioctx - Rados Ioctx object
1322 """
1323 self.require_state("connected")
1324 cdef:
1325 rados_ioctx_t ioctx
1326 int64_t _pool_id = pool_id
1327 with nogil:
1328 ret = rados_ioctx_create2(self.cluster, _pool_id, &ioctx)
1329 if ret < 0:
1330 raise make_ex(ret, "error opening pool id '%s'" % pool_id)
1331 io = Ioctx(str(pool_id))
1332 io.io = ioctx
1333 return io
1334
7c673cae
FG
1335 def mon_command(self, cmd, inbuf, timeout=0, target=None):
1336 """
9f95a23c
TL
1337 Send a command to the mon.
1338
7c673cae 1339 mon_command[_target](cmd, inbuf, outbuf, outbuflen, outs, outslen)
9f95a23c
TL
1340
1341 :param cmd: JSON formatted string.
1342 :param inbuf: optional string.
1343 :param timeout: This parameter is ignored.
1344 :param target: name of a specific mon. Optional
1345 :return: (int ret, string outbuf, string outs)
1346
1347 Example:
1348
1349 >>> import json
1350 >>> c = Rados(conffile='/etc/ceph/ceph.conf')
1351 >>> c.connect()
1352 >>> cmd = json.dumps({"prefix": "osd safe-to-destroy", "ids": ["2"], "format": "json"})
1353 >>> c.mon_command(cmd, b'')
7c673cae
FG
1354 """
1355 # NOTE(sileht): timeout is ignored because C API doesn't provide
1356 # timeout argument, but we keep it for backward compat with old python binding
1357
1358 self.require_state("connected")
1359 cmd = cstr_list(cmd, 'c')
1360
1361 if isinstance(target, int):
1362 # NOTE(sileht): looks weird but test_monmap_dump pass int
1363 target = str(target)
1364
1365 target = cstr(target, 'target', opt=True)
1366 inbuf = cstr(inbuf, 'inbuf')
1367
1368 cdef:
1369 char *_target = opt_str(target)
1370 char **_cmd = to_bytes_array(cmd)
1371 size_t _cmdlen = len(cmd)
1372
1373 char *_inbuf = inbuf
1374 size_t _inbuf_len = len(inbuf)
1375
1376 char *_outbuf
1377 size_t _outbuf_len
1378 char *_outs
1379 size_t _outs_len
1380
1381 try:
1382 if target:
1383 with nogil:
1384 ret = rados_mon_command_target(self.cluster, _target,
1385 <const char **>_cmd, _cmdlen,
1386 <const char*>_inbuf, _inbuf_len,
1387 &_outbuf, &_outbuf_len,
1388 &_outs, &_outs_len)
1389 else:
1390 with nogil:
1391 ret = rados_mon_command(self.cluster,
1392 <const char **>_cmd, _cmdlen,
1393 <const char*>_inbuf, _inbuf_len,
1394 &_outbuf, &_outbuf_len,
1395 &_outs, &_outs_len)
1396
1397 my_outs = decode_cstr(_outs[:_outs_len])
1398 my_outbuf = _outbuf[:_outbuf_len]
1399 if _outs_len:
1400 rados_buffer_free(_outs)
1401 if _outbuf_len:
1402 rados_buffer_free(_outbuf)
1403 return (ret, my_outbuf, my_outs)
1404 finally:
1405 free(_cmd)
1406
1407 def osd_command(self, osdid, cmd, inbuf, timeout=0):
1408 """
1409 osd_command(osdid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
9f95a23c
TL
1410
1411 :return: (int ret, string outbuf, string outs)
7c673cae
FG
1412 """
1413 # NOTE(sileht): timeout is ignored because C API doesn't provide
1414 # timeout argument, but we keep it for backward compat with old python binding
1415 self.require_state("connected")
1416
1417 cmd = cstr_list(cmd, 'cmd')
1418 inbuf = cstr(inbuf, 'inbuf')
1419
1420 cdef:
1421 int _osdid = osdid
1422 char **_cmd = to_bytes_array(cmd)
1423 size_t _cmdlen = len(cmd)
1424
1425 char *_inbuf = inbuf
1426 size_t _inbuf_len = len(inbuf)
1427
1428 char *_outbuf
1429 size_t _outbuf_len
1430 char *_outs
1431 size_t _outs_len
1432
1433 try:
1434 with nogil:
1435 ret = rados_osd_command(self.cluster, _osdid,
1436 <const char **>_cmd, _cmdlen,
1437 <const char*>_inbuf, _inbuf_len,
1438 &_outbuf, &_outbuf_len,
1439 &_outs, &_outs_len)
1440
1441 my_outs = decode_cstr(_outs[:_outs_len])
1442 my_outbuf = _outbuf[:_outbuf_len]
1443 if _outs_len:
1444 rados_buffer_free(_outs)
1445 if _outbuf_len:
1446 rados_buffer_free(_outbuf)
1447 return (ret, my_outbuf, my_outs)
1448 finally:
1449 free(_cmd)
1450
9f95a23c 1451 def mgr_command(self, cmd, inbuf, timeout=0, target=None):
7c673cae 1452 """
9f95a23c 1453 :return: (int ret, string outbuf, string outs)
7c673cae
FG
1454 """
1455 # NOTE(sileht): timeout is ignored because C API doesn't provide
1456 # timeout argument, but we keep it for backward compat with old python binding
1457 self.require_state("connected")
1458
1459 cmd = cstr_list(cmd, 'cmd')
1460 inbuf = cstr(inbuf, 'inbuf')
9f95a23c 1461 target = cstr(target, 'target', opt=True)
7c673cae
FG
1462
1463 cdef:
9f95a23c
TL
1464 char *_target = opt_str(target)
1465
7c673cae
FG
1466 char **_cmd = to_bytes_array(cmd)
1467 size_t _cmdlen = len(cmd)
1468
1469 char *_inbuf = inbuf
1470 size_t _inbuf_len = len(inbuf)
1471
1472 char *_outbuf
1473 size_t _outbuf_len
1474 char *_outs
1475 size_t _outs_len
1476
1477 try:
9f95a23c
TL
1478 if target is not None:
1479 with nogil:
1480 ret = rados_mgr_command_target(self.cluster,
1481 <const char*>_target,
1482 <const char **>_cmd, _cmdlen,
1483 <const char*>_inbuf, _inbuf_len,
1484 &_outbuf, &_outbuf_len,
1485 &_outs, &_outs_len)
1486 else:
1487 with nogil:
1488 ret = rados_mgr_command(self.cluster,
1489 <const char **>_cmd, _cmdlen,
1490 <const char*>_inbuf, _inbuf_len,
1491 &_outbuf, &_outbuf_len,
1492 &_outs, &_outs_len)
7c673cae
FG
1493
1494 my_outs = decode_cstr(_outs[:_outs_len])
1495 my_outbuf = _outbuf[:_outbuf_len]
1496 if _outs_len:
1497 rados_buffer_free(_outs)
1498 if _outbuf_len:
1499 rados_buffer_free(_outbuf)
1500 return (ret, my_outbuf, my_outs)
1501 finally:
1502 free(_cmd)
1503
1504 def pg_command(self, pgid, cmd, inbuf, timeout=0):
1505 """
1506 pg_command(pgid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
9f95a23c
TL
1507
1508 :return: (int ret, string outbuf, string outs)
7c673cae
FG
1509 """
1510 # NOTE(sileht): timeout is ignored because C API doesn't provide
1511 # timeout argument, but we keep it for backward compat with old python binding
1512 self.require_state("connected")
1513
1514 pgid = cstr(pgid, 'pgid')
1515 cmd = cstr_list(cmd, 'cmd')
1516 inbuf = cstr(inbuf, 'inbuf')
1517
1518 cdef:
1519 char *_pgid = pgid
1520 char **_cmd = to_bytes_array(cmd)
1521 size_t _cmdlen = len(cmd)
1522
1523 char *_inbuf = inbuf
1524 size_t _inbuf_len = len(inbuf)
1525
1526 char *_outbuf
1527 size_t _outbuf_len
1528 char *_outs
1529 size_t _outs_len
1530
1531 try:
1532 with nogil:
1533 ret = rados_pg_command(self.cluster, _pgid,
1534 <const char **>_cmd, _cmdlen,
1535 <const char *>_inbuf, _inbuf_len,
1536 &_outbuf, &_outbuf_len,
1537 &_outs, &_outs_len)
1538
1539 my_outs = decode_cstr(_outs[:_outs_len])
1540 my_outbuf = _outbuf[:_outbuf_len]
1541 if _outs_len:
1542 rados_buffer_free(_outs)
1543 if _outbuf_len:
1544 rados_buffer_free(_outbuf)
1545 return (ret, my_outbuf, my_outs)
1546 finally:
1547 free(_cmd)
1548
1549 def wait_for_latest_osdmap(self):
1550 self.require_state("connected")
1551 with nogil:
1552 ret = rados_wait_for_latest_osdmap(self.cluster)
1553 return ret
1554
1555 def blacklist_add(self, client_address, expire_seconds=0):
1556 """
1557 Blacklist a client from the OSDs
1558
1559 :param client_address: client address
1560 :type client_address: str
1561 :param expire_seconds: number of seconds to blacklist
1562 :type expire_seconds: int
1563
1564 :raises: :class:`Error`
1565 """
1566 self.require_state("connected")
1567 client_address = cstr(client_address, 'client_address')
1568 cdef:
1569 uint32_t _expire_seconds = expire_seconds
1570 char *_client_address = client_address
1571
1572 with nogil:
1573 ret = rados_blacklist_add(self.cluster, _client_address, _expire_seconds)
1574 if ret < 0:
1575 raise make_ex(ret, "error blacklisting client '%s'" % client_address)
1576
1577 def monitor_log(self, level, callback, arg):
1578 if level not in MONITOR_LEVELS:
1579 raise LogicError("invalid monitor level " + level)
1580 if callback is not None and not callable(callback):
1581 raise LogicError("callback must be a callable function or None")
1582
1583 level = cstr(level, 'level')
1584 cdef char *_level = level
1585
1586 if callback is None:
1587 with nogil:
1588 r = rados_monitor_log(self.cluster, <const char*>_level, NULL, NULL)
1589 self.monitor_callback = None
31f18b77 1590 self.monitor_callback2 = None
7c673cae
FG
1591 return
1592
1593 cb = (callback, arg)
1594 cdef PyObject* _arg = <PyObject*>cb
1595 with nogil:
1596 r = rados_monitor_log(self.cluster, <const char*>_level,
1597 <rados_log_callback_t>&__monitor_callback, _arg)
1598
1599 if r:
1600 raise make_ex(r, 'error calling rados_monitor_log')
1601 # NOTE(sileht): Prevents the callback method from being garbage collected
1602 self.monitor_callback = cb
31f18b77
FG
1603 self.monitor_callback2 = None
1604
1605 def monitor_log2(self, level, callback, arg):
1606 if level not in MONITOR_LEVELS:
1607 raise LogicError("invalid monitor level " + level)
1608 if callback is not None and not callable(callback):
1609 raise LogicError("callback must be a callable function or None")
1610
1611 level = cstr(level, 'level')
1612 cdef char *_level = level
1613
1614 if callback is None:
1615 with nogil:
1616 r = rados_monitor_log2(self.cluster, <const char*>_level, NULL, NULL)
1617 self.monitor_callback = None
1618 self.monitor_callback2 = None
1619 return
1620
1621 cb = (callback, arg)
1622 cdef PyObject* _arg = <PyObject*>cb
1623 with nogil:
1624 r = rados_monitor_log2(self.cluster, <const char*>_level,
1625 <rados_log_callback2_t>&__monitor_callback2, _arg)
1626
1627 if r:
1628 raise make_ex(r, 'error calling rados_monitor_log')
1629 # NOTE(sileht): Prevents the callback method from being garbage collected
1630 self.monitor_callback = None
1631 self.monitor_callback2 = cb
7c673cae 1632
11fdf7f2
TL
1633 @requires(('service', str_type), ('daemon', str_type), ('metadata', dict))
1634 def service_daemon_register(self, service, daemon, metadata):
1635 """
1636 :param str service: service name (e.g. "rgw")
1637 :param str daemon: daemon name (e.g. "gwfoo")
1638 :param dict metadata: static metadata about the register daemon
1639 (e.g., the version of Ceph, the kernel version.)
1640 """
1641 service = cstr(service, 'service')
1642 daemon = cstr(daemon, 'daemon')
9f95a23c 1643 metadata_dict = flatten_dict(metadata, 'metadata')
11fdf7f2
TL
1644 cdef:
1645 char *_service = service
1646 char *_daemon = daemon
1647 char *_metadata = metadata_dict
1648
1649 with nogil:
1650 ret = rados_service_register(self.cluster, _service, _daemon, _metadata)
1651 if ret != 0:
1652 raise make_ex(ret, "error calling service_register()")
1653
1654 @requires(('metadata', dict))
1655 def service_daemon_update(self, status):
9f95a23c 1656 status_dict = flatten_dict(status, 'status')
11fdf7f2
TL
1657 cdef:
1658 char *_status = status_dict
1659
1660 with nogil:
1661 ret = rados_service_update_status(self.cluster, _status)
1662 if ret != 0:
1663 raise make_ex(ret, "error calling service_daemon_update()")
1664
7c673cae
FG
1665
1666cdef class OmapIterator(object):
1667 """Omap iterator"""
1668
1669 cdef public Ioctx ioctx
1670 cdef rados_omap_iter_t ctx
1671
1672 def __cinit__(self, Ioctx ioctx):
1673 self.ioctx = ioctx
1674
1675 def __iter__(self):
1676 return self
1677
1678 def __next__(self):
1679 """
1680 Get the next key-value pair in the object
1681 :returns: next rados.OmapItem
1682 """
1683 cdef:
1684 char *key_ = NULL
1685 char *val_ = NULL
1686 size_t len_
1687
1688 with nogil:
1689 ret = rados_omap_get_next(self.ctx, &key_, &val_, &len_)
1690
1691 if ret != 0:
1692 raise make_ex(ret, "error iterating over the omap")
1693 if key_ == NULL:
1694 raise StopIteration()
1695 key = decode_cstr(key_)
1696 val = None
1697 if val_ != NULL:
1698 val = val_[:len_]
1699 return (key, val)
1700
1701 def __dealloc__(self):
1702 with nogil:
1703 rados_omap_get_end(self.ctx)
1704
1705
1706cdef class ObjectIterator(object):
1707 """rados.Ioctx Object iterator"""
1708
1709 cdef rados_list_ctx_t ctx
1710
1711 cdef public object ioctx
1712
1713 def __cinit__(self, Ioctx ioctx):
1714 self.ioctx = ioctx
1715
1716 with nogil:
1717 ret = rados_nobjects_list_open(ioctx.io, &self.ctx)
1718 if ret < 0:
1719 raise make_ex(ret, "error iterating over the objects in ioctx '%s'"
1720 % self.ioctx.name)
1721
1722 def __iter__(self):
1723 return self
1724
1725 def __next__(self):
1726 """
1727 Get the next object name and locator in the pool
1728
1729 :raises: StopIteration
1730 :returns: next rados.Ioctx Object
1731 """
1732 cdef:
1733 const char *key_ = NULL
1734 const char *locator_ = NULL
1735 const char *nspace_ = NULL
1736
1737 with nogil:
1738 ret = rados_nobjects_list_next(self.ctx, &key_, &locator_, &nspace_)
1739
1740 if ret < 0:
1741 raise StopIteration()
1742
1743 key = decode_cstr(key_)
1744 locator = decode_cstr(locator_) if locator_ != NULL else None
1745 nspace = decode_cstr(nspace_) if nspace_ != NULL else None
1746 return Object(self.ioctx, key, locator, nspace)
1747
1748 def __dealloc__(self):
1749 with nogil:
1750 rados_nobjects_list_close(self.ctx)
1751
1752
1753cdef class XattrIterator(object):
1754 """Extended attribute iterator"""
1755
1756 cdef rados_xattrs_iter_t it
1757 cdef char* _oid
1758
1759 cdef public Ioctx ioctx
1760 cdef public object oid
1761
1762 def __cinit__(self, Ioctx ioctx, oid):
1763 self.ioctx = ioctx
1764 self.oid = cstr(oid, 'oid')
1765 self._oid = self.oid
1766
1767 with nogil:
1768 ret = rados_getxattrs(ioctx.io, self._oid, &self.it)
1769 if ret != 0:
1770 raise make_ex(ret, "Failed to get rados xattrs for object %r" % oid)
1771
1772 def __iter__(self):
1773 return self
1774
1775 def __next__(self):
1776 """
1777 Get the next xattr on the object
1778
1779 :raises: StopIteration
1780 :returns: pair - of name and value of the next Xattr
1781 """
1782 cdef:
1783 const char *name_ = NULL
1784 const char *val_ = NULL
1785 size_t len_ = 0
1786
1787 with nogil:
1788 ret = rados_getxattrs_next(self.it, &name_, &val_, &len_)
1789 if ret != 0:
1790 raise make_ex(ret, "error iterating over the extended attributes \
1791in '%s'" % self.oid)
1792 if name_ == NULL:
1793 raise StopIteration()
1794 name = decode_cstr(name_)
1795 val = val_[:len_]
1796 return (name, val)
1797
1798 def __dealloc__(self):
1799 with nogil:
1800 rados_getxattrs_end(self.it)
1801
1802
1803cdef class SnapIterator(object):
1804 """Snapshot iterator"""
1805
1806 cdef public Ioctx ioctx
1807
1808 cdef rados_snap_t *snaps
1809 cdef int max_snap
1810 cdef int cur_snap
1811
1812 def __cinit__(self, Ioctx ioctx):
1813 self.ioctx = ioctx
1814 # We don't know how big a buffer we need until we've called the
1815 # function. So use the exponential doubling strategy.
1816 cdef int num_snaps = 10
1817 while True:
1818 self.snaps = <rados_snap_t*>realloc_chk(self.snaps,
1819 num_snaps *
1820 sizeof(rados_snap_t))
1821
1822 with nogil:
1823 ret = rados_ioctx_snap_list(ioctx.io, self.snaps, num_snaps)
1824 if ret >= 0:
1825 self.max_snap = ret
1826 break
1827 elif ret != -errno.ERANGE:
1828 raise make_ex(ret, "error calling rados_snap_list for \
1829ioctx '%s'" % self.ioctx.name)
1830 num_snaps = num_snaps * 2
1831 self.cur_snap = 0
1832
1833 def __iter__(self):
1834 return self
1835
1836 def __next__(self):
1837 """
1838 Get the next Snapshot
1839
1840 :raises: :class:`Error`, StopIteration
1841 :returns: Snap - next snapshot
1842 """
1843 if self.cur_snap >= self.max_snap:
1844 raise StopIteration
1845
1846 cdef:
1847 rados_snap_t snap_id = self.snaps[self.cur_snap]
1848 int name_len = 10
1849 char *name = NULL
1850
1851 try:
1852 while True:
1853 name = <char *>realloc_chk(name, name_len)
1854 with nogil:
1855 ret = rados_ioctx_snap_get_name(self.ioctx.io, snap_id, name, name_len)
1856 if ret == 0:
1857 break
1858 elif ret != -errno.ERANGE:
1859 raise make_ex(ret, "rados_snap_get_name error")
1860 else:
1861 name_len = name_len * 2
1862
1863 snap = Snap(self.ioctx, decode_cstr(name[:name_len]).rstrip('\0'), snap_id)
1864 self.cur_snap = self.cur_snap + 1
1865 return snap
1866 finally:
1867 free(name)
1868
1869
1870cdef class Snap(object):
1871 """Snapshot object"""
1872 cdef public Ioctx ioctx
1873 cdef public object name
1874
1875 # NOTE(sileht): old API was storing the ctypes object
1876 # instead of the value ....
1877 cdef public rados_snap_t snap_id
1878
1879 def __cinit__(self, Ioctx ioctx, object name, rados_snap_t snap_id):
1880 self.ioctx = ioctx
1881 self.name = name
1882 self.snap_id = snap_id
1883
1884 def __str__(self):
1885 return "rados.Snap(ioctx=%s,name=%s,snap_id=%d)" \
1886 % (str(self.ioctx), self.name, self.snap_id)
1887
1888 def get_timestamp(self):
1889 """
1890 Find when a snapshot in the current pool occurred
1891
1892 :raises: :class:`Error`
1893 :returns: datetime - the data and time the snapshot was created
1894 """
1895 cdef time_t snap_time
1896
1897 with nogil:
1898 ret = rados_ioctx_snap_get_stamp(self.ioctx.io, self.snap_id, &snap_time)
1899 if ret != 0:
1900 raise make_ex(ret, "rados_ioctx_snap_get_stamp error")
1901 return datetime.fromtimestamp(snap_time)
1902
1903
1904cdef class Completion(object):
1905 """completion object"""
1906
1907 cdef public:
1908 Ioctx ioctx
1909 object oncomplete
1910 object onsafe
1911
1912 cdef:
1913 rados_callback_t complete_cb
1914 rados_callback_t safe_cb
1915 rados_completion_t rados_comp
1916 PyObject* buf
1917
1918 def __cinit__(self, Ioctx ioctx, object oncomplete, object onsafe):
1919 self.oncomplete = oncomplete
1920 self.onsafe = onsafe
1921 self.ioctx = ioctx
1922
1923 def is_safe(self):
1924 """
1925 Is an asynchronous operation safe?
1926
1927 This does not imply that the safe callback has finished.
1928
1929 :returns: True if the operation is safe
1930 """
9f95a23c 1931 return self.is_complete()
7c673cae
FG
1932
1933 def is_complete(self):
1934 """
1935 Has an asynchronous operation completed?
1936
1937 This does not imply that the safe callback has finished.
1938
1939 :returns: True if the operation is completed
1940 """
1941 with nogil:
1942 ret = rados_aio_is_complete(self.rados_comp)
1943 return ret == 1
1944
1945 def wait_for_safe(self):
1946 """
1947 Wait for an asynchronous operation to be marked safe
1948
9f95a23c 1949 wait_for_safe() is an alias of wait_for_complete() since Luminous
7c673cae 1950 """
9f95a23c 1951 self.wait_for_complete()
7c673cae
FG
1952
1953 def wait_for_complete(self):
1954 """
1955 Wait for an asynchronous operation to complete
1956
1957 This does not imply that the complete callback has finished.
1958 """
1959 with nogil:
1960 rados_aio_wait_for_complete(self.rados_comp)
1961
1962 def wait_for_safe_and_cb(self):
1963 """
1964 Wait for an asynchronous operation to be marked safe and for
1965 the safe callback to have returned
1966 """
9f95a23c 1967 return self.wait_for_complete_and_cb()
7c673cae
FG
1968
1969 def wait_for_complete_and_cb(self):
1970 """
1971 Wait for an asynchronous operation to complete and for the
1972 complete callback to have returned
1973
1974 :returns: whether the operation is completed
1975 """
1976 with nogil:
1977 ret = rados_aio_wait_for_complete_and_cb(self.rados_comp)
1978 return ret
1979
1980 def get_return_value(self):
1981 """
1982 Get the return value of an asychronous operation
1983
1984 The return value is set when the operation is complete or safe,
1985 whichever comes first.
1986
1987 :returns: int - return value of the operation
1988 """
1989 with nogil:
1990 ret = rados_aio_get_return_value(self.rados_comp)
1991 return ret
1992
1993 def __dealloc__(self):
1994 """
1995 Release a completion
1996
1997 Call this when you no longer need the completion. It may not be
1998 freed immediately if the operation is not acked and committed.
1999 """
2000 ref.Py_XDECREF(self.buf)
2001 self.buf = NULL
2002 if self.rados_comp != NULL:
2003 with nogil:
2004 rados_aio_release(self.rados_comp)
2005 self.rados_comp = NULL
2006
2007 def _complete(self):
2008 self.oncomplete(self)
9f95a23c
TL
2009 if self.onsafe:
2010 self.onsafe(self)
2011 self._cleanup()
7c673cae
FG
2012
2013 def _cleanup(self):
2014 with self.ioctx.lock:
2015 if self.oncomplete:
2016 self.ioctx.complete_completions.remove(self)
2017 if self.onsafe:
2018 self.ioctx.safe_completions.remove(self)
2019
2020
2021class OpCtx(object):
2022 def __enter__(self):
2023 return self.create()
2024
2025 def __exit__(self, type, msg, traceback):
2026 self.release()
2027
2028
2029cdef class WriteOp(object):
2030 cdef rados_write_op_t write_op
2031
2032 def create(self):
2033 with nogil:
2034 self.write_op = rados_create_write_op()
2035 return self
2036
2037 def release(self):
2038 with nogil:
2039 rados_release_write_op(self.write_op)
2040
2041 @requires(('exclusive', opt(int)))
2042 def new(self, exclusive=None):
2043 """
2044 Create the object.
2045 """
2046
2047 cdef:
2048 int _exclusive = exclusive
2049
2050 with nogil:
2051 rados_write_op_create(self.write_op, _exclusive, NULL)
2052
2053
2054 def remove(self):
2055 """
2056 Remove object.
2057 """
2058 with nogil:
2059 rados_write_op_remove(self.write_op)
2060
2061 @requires(('flags', int))
2062 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
2063 """
2064 Set flags for the last operation added to this write_op.
2065 :para flags: flags to apply to the last operation
2066 :type flags: int
2067 """
2068
2069 cdef:
2070 int _flags = flags
2071
2072 with nogil:
2073 rados_write_op_set_flags(self.write_op, _flags)
2074
9f95a23c
TL
2075 @requires(('xattr_name', str_type), ('xattr_value', bytes))
2076 def set_xattr(self, xattr_name, xattr_value):
2077 """
2078 Set an extended attribute on an object.
2079 :param xattr_name: name of the xattr
2080 :type xattr_name: str
2081 :param xattr_value: buffer to set xattr to
2082 :type xattr_value: bytes
2083 """
2084 xattr_name = cstr(xattr_name, 'xattr_name')
2085 cdef:
2086 char *_xattr_name = xattr_name
2087 char *_xattr_value = xattr_value
2088 size_t _xattr_value_len = len(xattr_value)
2089 with nogil:
2090 rados_write_op_setxattr(self.write_op, _xattr_name, _xattr_value, _xattr_value_len)
2091
2092 @requires(('xattr_name', str_type))
2093 def rm_xattr(self, xattr_name):
2094 """
2095 Removes an extended attribute on from an object.
2096 :param xattr_name: name of the xattr to remove
2097 :type xattr_name: str
2098 """
2099 xattr_name = cstr(xattr_name, 'xattr_name')
2100 cdef:
2101 char *_xattr_name = xattr_name
2102 with nogil:
2103 rados_write_op_rmxattr(self.write_op, _xattr_name)
2104
7c673cae
FG
2105 @requires(('to_write', bytes))
2106 def append(self, to_write):
2107 """
2108 Append data to an object synchronously
2109 :param to_write: data to write
2110 :type to_write: bytes
2111 """
2112
2113 cdef:
2114 char *_to_write = to_write
2115 size_t length = len(to_write)
2116
2117 with nogil:
2118 rados_write_op_append(self.write_op, _to_write, length)
2119
2120 @requires(('to_write', bytes))
2121 def write_full(self, to_write):
2122 """
2123 Write whole object, atomically replacing it.
2124 :param to_write: data to write
2125 :type to_write: bytes
2126 """
2127
2128 cdef:
2129 char *_to_write = to_write
2130 size_t length = len(to_write)
2131
2132 with nogil:
2133 rados_write_op_write_full(self.write_op, _to_write, length)
2134
2135 @requires(('to_write', bytes), ('offset', int))
2136 def write(self, to_write, offset=0):
2137 """
2138 Write to offset.
2139 :param to_write: data to write
2140 :type to_write: bytes
2141 :param offset: byte offset in the object to begin writing at
2142 :type offset: int
2143 """
2144
2145 cdef:
2146 char *_to_write = to_write
2147 size_t length = len(to_write)
2148 uint64_t _offset = offset
2149
2150 with nogil:
2151 rados_write_op_write(self.write_op, _to_write, length, _offset)
2152
91327a77
AA
2153 @requires(('version', int))
2154 def assert_version(self, version):
2155 """
2156 Check if object's version is the expected one.
2157 :param version: expected version of the object
2158 :param type: int
2159 """
2160 cdef:
2161 uint64_t _version = version
2162
2163 with nogil:
2164 rados_write_op_assert_version(self.write_op, _version)
2165
7c673cae
FG
2166 @requires(('offset', int), ('length', int))
2167 def zero(self, offset, length):
2168 """
2169 Zero part of an object.
2170 :param offset: byte offset in the object to begin writing at
2171 :type offset: int
2172 :param offset: number of zero to write
2173 :type offset: int
2174 """
2175
2176 cdef:
2177 size_t _length = length
2178 uint64_t _offset = offset
2179
2180 with nogil:
2181 rados_write_op_zero(self.write_op, _length, _offset)
2182
2183 @requires(('offset', int))
2184 def truncate(self, offset):
2185 """
2186 Truncate an object.
2187 :param offset: byte offset in the object to begin truncating at
2188 :type offset: int
2189 """
2190
2191 cdef:
2192 uint64_t _offset = offset
2193
2194 with nogil:
2195 rados_write_op_truncate(self.write_op, _offset)
2196
9f95a23c
TL
2197 @requires(('cls', str_type), ('method', str_type), ('data', bytes))
2198 def execute(self, cls, method, data):
2199 """
2200 Execute an OSD class method on an object
2201
2202 :param cls: name of the object class
2203 :type cls: str
2204 :param method: name of the method
2205 :type method: str
2206 :param data: input data
2207 :type data: bytes
2208 """
2209
2210 cls = cstr(cls, 'cls')
2211 method = cstr(method, 'method')
2212 cdef:
2213 char *_cls = cls
2214 char *_method = method
2215 char *_data = data
2216 size_t _data_len = len(data)
2217
2218 with nogil:
2219 rados_write_op_exec(self.write_op, _cls, _method, _data, _data_len, NULL)
2220
2221 @requires(('to_write', bytes), ('write_len', int), ('offset', int))
2222 def writesame(self, to_write, write_len, offset=0):
2223 """
2224 Write the same buffer multiple times
2225 :param to_write: data to write
2226 :type to_write: bytes
2227 :param write_len: total number of bytes to write
2228 :type len: int
2229 :param offset: byte offset in the object to begin writing at
2230 :type offset: int
2231 """
2232 cdef:
2233 char *_to_write = to_write
2234 size_t _data_len = len(to_write)
2235 size_t _write_len = write_len
2236 uint64_t _offset = offset
2237 with nogil:
2238 rados_write_op_writesame(self.write_op, _to_write, _data_len, _write_len, _offset)
7c673cae
FG
2239
2240class WriteOpCtx(WriteOp, OpCtx):
2241 """write operation context manager"""
2242
2243
2244cdef class ReadOp(object):
2245 cdef rados_read_op_t read_op
2246
2247 def create(self):
2248 with nogil:
2249 self.read_op = rados_create_read_op()
2250 return self
2251
2252 def release(self):
2253 with nogil:
2254 rados_release_read_op(self.read_op)
2255
2256 @requires(('flags', int))
2257 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
2258 """
2259 Set flags for the last operation added to this read_op.
2260 :para flags: flags to apply to the last operation
2261 :type flags: int
2262 """
2263
2264 cdef:
2265 int _flags = flags
2266
2267 with nogil:
2268 rados_read_op_set_flags(self.read_op, _flags)
2269
2270
2271class ReadOpCtx(ReadOp, OpCtx):
2272 """read operation context manager"""
2273
2274
7c673cae
FG
2275cdef int __aio_complete_cb(rados_completion_t completion, void *args) with gil:
2276 """
2277 Callback to oncomplete() for asynchronous operations
2278 """
2279 cdef object cb = <object>args
2280 cb._complete()
2281 return 0
2282
2283
2284cdef class Ioctx(object):
2285 """rados.Ioctx object"""
2286 # NOTE(sileht): attributes declared in .pyd
2287
2288 def __init__(self, name):
2289 self.name = name
2290 self.state = "open"
2291
2292 self.locator_key = ""
2293 self.nspace = ""
2294 self.lock = threading.Lock()
2295 self.safe_completions = []
2296 self.complete_completions = []
2297
2298 def __enter__(self):
2299 return self
2300
2301 def __exit__(self, type_, value, traceback):
2302 self.close()
2303 return False
2304
2305 def __dealloc__(self):
2306 self.close()
2307
2308 def __track_completion(self, completion_obj):
2309 if completion_obj.oncomplete:
2310 with self.lock:
2311 self.complete_completions.append(completion_obj)
2312 if completion_obj.onsafe:
2313 with self.lock:
2314 self.safe_completions.append(completion_obj)
2315
2316 def __get_completion(self, oncomplete, onsafe):
2317 """
2318 Constructs a completion to use with asynchronous operations
2319
2320 :param oncomplete: what to do when the write is safe and complete in memory
2321 on all replicas
2322 :type oncomplete: completion
2323 :param onsafe: what to do when the write is safe and complete on storage
2324 on all replicas
2325 :type onsafe: completion
2326
2327 :raises: :class:`Error`
2328 :returns: completion object
2329 """
2330
2331 completion_obj = Completion(self, oncomplete, onsafe)
2332
2333 cdef:
2334 rados_callback_t complete_cb = NULL
7c673cae
FG
2335 rados_completion_t completion
2336 PyObject* p_completion_obj= <PyObject*>completion_obj
2337
2338 if oncomplete:
2339 complete_cb = <rados_callback_t>&__aio_complete_cb
7c673cae
FG
2340
2341 with nogil:
9f95a23c 2342 ret = rados_aio_create_completion2(p_completion_obj, complete_cb,
7c673cae
FG
2343 &completion)
2344 if ret < 0:
2345 raise make_ex(ret, "error getting a completion")
2346
2347 completion_obj.rados_comp = completion
2348 return completion_obj
2349
2350 @requires(('object_name', str_type), ('oncomplete', opt(Callable)))
2351 def aio_stat(self, object_name, oncomplete):
2352 """
2353 Asynchronously get object stats (size/mtime)
2354
2355 oncomplete will be called with the returned size and mtime
2356 as well as the completion:
2357
2358 oncomplete(completion, size, mtime)
2359
2360 :param object_name: the name of the object to get stats from
2361 :type object_name: str
2362 :param oncomplete: what to do when the stat is complete
2363 :type oncomplete: completion
2364
2365 :raises: :class:`Error`
2366 :returns: completion object
2367 """
2368
2369 object_name = cstr(object_name, 'object_name')
2370
2371 cdef:
2372 Completion completion
2373 char *_object_name = object_name
2374 uint64_t psize
2375 time_t pmtime
2376
2377 def oncomplete_(completion_v):
2378 cdef Completion _completion_v = completion_v
2379 return_value = _completion_v.get_return_value()
2380 if return_value >= 0:
2381 return oncomplete(_completion_v, psize, time.localtime(pmtime))
2382 else:
2383 return oncomplete(_completion_v, None, None)
2384
2385 completion = self.__get_completion(oncomplete_, None)
2386 self.__track_completion(completion)
2387 with nogil:
2388 ret = rados_aio_stat(self.io, _object_name, completion.rados_comp,
2389 &psize, &pmtime)
2390
2391 if ret < 0:
2392 completion._cleanup()
2393 raise make_ex(ret, "error stating %s" % object_name)
2394 return completion
2395
2396 @requires(('object_name', str_type), ('to_write', bytes), ('offset', int),
2397 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2398 def aio_write(self, object_name, to_write, offset=0,
2399 oncomplete=None, onsafe=None):
2400 """
2401 Write data to an object asynchronously
2402
2403 Queues the write and returns.
2404
2405 :param object_name: name of the object
2406 :type object_name: str
2407 :param to_write: data to write
2408 :type to_write: bytes
2409 :param offset: byte offset in the object to begin writing at
2410 :type offset: int
2411 :param oncomplete: what to do when the write is safe and complete in memory
2412 on all replicas
2413 :type oncomplete: completion
2414 :param onsafe: what to do when the write is safe and complete on storage
2415 on all replicas
2416 :type onsafe: completion
2417
2418 :raises: :class:`Error`
2419 :returns: completion object
2420 """
2421
2422 object_name = cstr(object_name, 'object_name')
2423
2424 cdef:
2425 Completion completion
2426 char* _object_name = object_name
2427 char* _to_write = to_write
2428 size_t size = len(to_write)
2429 uint64_t _offset = offset
2430
2431 completion = self.__get_completion(oncomplete, onsafe)
2432 self.__track_completion(completion)
2433 with nogil:
2434 ret = rados_aio_write(self.io, _object_name, completion.rados_comp,
2435 _to_write, size, _offset)
2436 if ret < 0:
2437 completion._cleanup()
2438 raise make_ex(ret, "error writing object %s" % object_name)
2439 return completion
2440
2441 @requires(('object_name', str_type), ('to_write', bytes), ('oncomplete', opt(Callable)),
2442 ('onsafe', opt(Callable)))
2443 def aio_write_full(self, object_name, to_write,
2444 oncomplete=None, onsafe=None):
2445 """
11fdf7f2 2446 Asynchronously write an entire object
7c673cae
FG
2447
2448 The object is filled with the provided data. If the object exists,
2449 it is atomically truncated and then written.
2450 Queues the write and returns.
2451
2452 :param object_name: name of the object
2453 :type object_name: str
2454 :param to_write: data to write
2455 :type to_write: str
2456 :param oncomplete: what to do when the write is safe and complete in memory
2457 on all replicas
2458 :type oncomplete: completion
2459 :param onsafe: what to do when the write is safe and complete on storage
2460 on all replicas
2461 :type onsafe: completion
2462
2463 :raises: :class:`Error`
2464 :returns: completion object
2465 """
2466
2467 object_name = cstr(object_name, 'object_name')
2468
2469 cdef:
2470 Completion completion
2471 char* _object_name = object_name
2472 char* _to_write = to_write
2473 size_t size = len(to_write)
2474
2475 completion = self.__get_completion(oncomplete, onsafe)
2476 self.__track_completion(completion)
2477 with nogil:
2478 ret = rados_aio_write_full(self.io, _object_name,
2479 completion.rados_comp,
2480 _to_write, size)
2481 if ret < 0:
2482 completion._cleanup()
2483 raise make_ex(ret, "error writing object %s" % object_name)
2484 return completion
2485
9f95a23c
TL
2486 @requires(('object_name', str_type), ('to_write', bytes), ('write_len', int),
2487 ('offset', int), ('oncomplete', opt(Callable)))
2488 def aio_writesame(self, object_name, to_write, write_len, offset=0,
2489 oncomplete=None):
2490 """
2491 Asynchronously write the same buffer multiple times
2492
2493 :param object_name: name of the object
2494 :type object_name: str
2495 :param to_write: data to write
2496 :type to_write: bytes
2497 :param write_len: total number of bytes to write
2498 :type write_len: int
2499 :param offset: byte offset in the object to begin writing at
2500 :type offset: int
2501 :param oncomplete: what to do when the writesame is safe and
2502 complete in memory on all replicas
2503 :type oncomplete: completion
2504 :raises: :class:`Error`
2505 :returns: completion object
2506 """
2507
2508 object_name = cstr(object_name, 'object_name')
2509
2510 cdef:
2511 Completion completion
2512 char* _object_name = object_name
2513 char* _to_write = to_write
2514 size_t _data_len = len(to_write)
2515 size_t _write_len = write_len
2516 uint64_t _offset = offset
2517
2518 completion = self.__get_completion(oncomplete, None)
2519 self.__track_completion(completion)
2520 with nogil:
2521 ret = rados_aio_writesame(self.io, _object_name, completion.rados_comp,
2522 _to_write, _data_len, _write_len, _offset)
2523
2524 if ret < 0:
2525 completion._cleanup()
2526 raise make_ex(ret, "error writing object %s" % object_name)
2527 return completion
2528
7c673cae
FG
2529 @requires(('object_name', str_type), ('to_append', bytes), ('oncomplete', opt(Callable)),
2530 ('onsafe', opt(Callable)))
2531 def aio_append(self, object_name, to_append, oncomplete=None, onsafe=None):
2532 """
11fdf7f2 2533 Asynchronously append data to an object
7c673cae
FG
2534
2535 Queues the write and returns.
2536
2537 :param object_name: name of the object
2538 :type object_name: str
2539 :param to_append: data to append
2540 :type to_append: str
2541 :param offset: byte offset in the object to begin writing at
2542 :type offset: int
2543 :param oncomplete: what to do when the write is safe and complete in memory
2544 on all replicas
2545 :type oncomplete: completion
2546 :param onsafe: what to do when the write is safe and complete on storage
2547 on all replicas
2548 :type onsafe: completion
2549
2550 :raises: :class:`Error`
2551 :returns: completion object
2552 """
2553 object_name = cstr(object_name, 'object_name')
2554
2555 cdef:
2556 Completion completion
2557 char* _object_name = object_name
2558 char* _to_append = to_append
2559 size_t size = len(to_append)
2560
2561 completion = self.__get_completion(oncomplete, onsafe)
2562 self.__track_completion(completion)
2563 with nogil:
2564 ret = rados_aio_append(self.io, _object_name,
2565 completion.rados_comp,
2566 _to_append, size)
2567 if ret < 0:
2568 completion._cleanup()
2569 raise make_ex(ret, "error appending object %s" % object_name)
2570 return completion
2571
2572 def aio_flush(self):
2573 """
2574 Block until all pending writes in an io context are safe
2575
2576 :raises: :class:`Error`
2577 """
2578 with nogil:
2579 ret = rados_aio_flush(self.io)
2580 if ret < 0:
2581 raise make_ex(ret, "error flushing")
2582
2583 @requires(('object_name', str_type), ('length', int), ('offset', int),
2584 ('oncomplete', opt(Callable)))
2585 def aio_read(self, object_name, length, offset, oncomplete):
2586 """
11fdf7f2 2587 Asynchronously read data from an object
7c673cae
FG
2588
2589 oncomplete will be called with the returned read value as
2590 well as the completion:
2591
2592 oncomplete(completion, data_read)
2593
2594 :param object_name: name of the object to read from
2595 :type object_name: str
2596 :param length: the number of bytes to read
2597 :type length: int
2598 :param offset: byte offset in the object to begin reading from
2599 :type offset: int
2600 :param oncomplete: what to do when the read is complete
2601 :type oncomplete: completion
2602
2603 :raises: :class:`Error`
2604 :returns: completion object
2605 """
2606
2607 object_name = cstr(object_name, 'object_name')
2608
2609 cdef:
2610 Completion completion
2611 char* _object_name = object_name
2612 uint64_t _offset = offset
2613
2614 char *ref_buf
2615 size_t _length = length
2616
2617 def oncomplete_(completion_v):
2618 cdef Completion _completion_v = completion_v
2619 return_value = _completion_v.get_return_value()
2620 if return_value > 0 and return_value != length:
2621 _PyBytes_Resize(&_completion_v.buf, return_value)
2622 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2623
2624 completion = self.__get_completion(oncomplete_, None)
2625 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2626 ret_buf = PyBytes_AsString(completion.buf)
2627 self.__track_completion(completion)
2628 with nogil:
2629 ret = rados_aio_read(self.io, _object_name, completion.rados_comp,
2630 ret_buf, _length, _offset)
2631 if ret < 0:
2632 completion._cleanup()
2633 raise make_ex(ret, "error reading %s" % object_name)
2634 return completion
2635
2636 @requires(('object_name', str_type), ('cls', str_type), ('method', str_type),
2637 ('data', bytes), ('length', int),
2638 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2639 def aio_execute(self, object_name, cls, method, data,
2640 length=8192, oncomplete=None, onsafe=None):
2641 """
2642 Asynchronously execute an OSD class method on an object.
2643
2644 oncomplete and onsafe will be called with the data returned from
2645 the plugin as well as the completion:
2646
2647 oncomplete(completion, data)
2648 onsafe(completion, data)
2649
2650 :param object_name: name of the object
2651 :type object_name: str
2652 :param cls: name of the object class
2653 :type cls: str
2654 :param method: name of the method
2655 :type method: str
2656 :param data: input data
2657 :type data: bytes
2658 :param length: size of output buffer in bytes (default=8192)
2659 :type length: int
2660 :param oncomplete: what to do when the execution is complete
2661 :type oncomplete: completion
2662 :param onsafe: what to do when the execution is safe and complete
2663 :type onsafe: completion
2664
2665 :raises: :class:`Error`
2666 :returns: completion object
2667 """
2668
2669 object_name = cstr(object_name, 'object_name')
2670 cls = cstr(cls, 'cls')
2671 method = cstr(method, 'method')
2672 cdef:
2673 Completion completion
2674 char *_object_name = object_name
2675 char *_cls = cls
2676 char *_method = method
2677 char *_data = data
2678 size_t _data_len = len(data)
2679
2680 char *ref_buf
2681 size_t _length = length
2682
2683 def oncomplete_(completion_v):
2684 cdef Completion _completion_v = completion_v
2685 return_value = _completion_v.get_return_value()
2686 if return_value > 0 and return_value != length:
2687 _PyBytes_Resize(&_completion_v.buf, return_value)
2688 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2689
2690 def onsafe_(completion_v):
2691 cdef Completion _completion_v = completion_v
2692 return_value = _completion_v.get_return_value()
2693 return onsafe(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2694
2695 completion = self.__get_completion(oncomplete_ if oncomplete else None, onsafe_ if onsafe else None)
2696 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2697 ret_buf = PyBytes_AsString(completion.buf)
2698 self.__track_completion(completion)
2699 with nogil:
2700 ret = rados_aio_exec(self.io, _object_name, completion.rados_comp,
2701 _cls, _method, _data, _data_len, ret_buf, _length)
2702 if ret < 0:
2703 completion._cleanup()
2704 raise make_ex(ret, "error executing %s::%s on %s" % (cls, method, object_name))
2705 return completion
2706
2707 @requires(('object_name', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2708 def aio_remove(self, object_name, oncomplete=None, onsafe=None):
2709 """
11fdf7f2 2710 Asynchronously remove an object
7c673cae
FG
2711
2712 :param object_name: name of the object to remove
2713 :type object_name: str
2714 :param oncomplete: what to do when the remove is safe and complete in memory
2715 on all replicas
2716 :type oncomplete: completion
2717 :param onsafe: what to do when the remove is safe and complete on storage
2718 on all replicas
2719 :type onsafe: completion
2720
2721 :raises: :class:`Error`
2722 :returns: completion object
2723 """
2724 object_name = cstr(object_name, 'object_name')
2725
2726 cdef:
2727 Completion completion
2728 char* _object_name = object_name
2729
2730 completion = self.__get_completion(oncomplete, onsafe)
2731 self.__track_completion(completion)
2732 with nogil:
2733 ret = rados_aio_remove(self.io, _object_name,
2734 completion.rados_comp)
2735 if ret < 0:
2736 completion._cleanup()
2737 raise make_ex(ret, "error removing %s" % object_name)
2738 return completion
2739
2740 def require_ioctx_open(self):
2741 """
2742 Checks if the rados.Ioctx object state is 'open'
2743
2744 :raises: IoctxStateError
2745 """
2746 if self.state != "open":
2747 raise IoctxStateError("The pool is %s" % self.state)
2748
7c673cae
FG
2749 @requires(('loc_key', str_type))
2750 def set_locator_key(self, loc_key):
2751 """
2752 Set the key for mapping objects to pgs within an io context.
2753
2754 The key is used instead of the object name to determine which
2755 placement groups an object is put in. This affects all subsequent
2756 operations of the io context - until a different locator key is
2757 set, all objects in this io context will be placed in the same pg.
2758
2759 :param loc_key: the key to use as the object locator, or NULL to discard
2760 any previously set key
2761 :type loc_key: str
2762
2763 :raises: :class:`TypeError`
2764 """
2765 self.require_ioctx_open()
2766 cloc_key = cstr(loc_key, 'loc_key')
2767 cdef char *_loc_key = cloc_key
2768 with nogil:
2769 rados_ioctx_locator_set_key(self.io, _loc_key)
2770 self.locator_key = loc_key
2771
2772 def get_locator_key(self):
2773 """
2774 Get the locator_key of context
2775
2776 :returns: locator_key
2777 """
2778 return self.locator_key
2779
2780 @requires(('snap_id', long))
2781 def set_read(self, snap_id):
2782 """
2783 Set the snapshot for reading objects.
2784
2785 To stop to read from snapshot, use set_read(LIBRADOS_SNAP_HEAD)
2786
2787 :param snap_id: the snapshot Id
2788 :type snap_id: int
2789
2790 :raises: :class:`TypeError`
2791 """
2792 self.require_ioctx_open()
2793 cdef rados_snap_t _snap_id = snap_id
2794 with nogil:
2795 rados_ioctx_snap_set_read(self.io, _snap_id)
2796
2797 @requires(('nspace', str_type))
2798 def set_namespace(self, nspace):
2799 """
2800 Set the namespace for objects within an io context.
2801
2802 The namespace in addition to the object name fully identifies
2803 an object. This affects all subsequent operations of the io context
2804 - until a different namespace is set, all objects in this io context
2805 will be placed in the same namespace.
2806
2807 :param nspace: the namespace to use, or None/"" for the default namespace
2808 :type nspace: str
2809
2810 :raises: :class:`TypeError`
2811 """
2812 self.require_ioctx_open()
2813 if nspace is None:
2814 nspace = ""
2815 cnspace = cstr(nspace, 'nspace')
2816 cdef char *_nspace = cnspace
2817 with nogil:
2818 rados_ioctx_set_namespace(self.io, _nspace)
2819 self.nspace = nspace
2820
2821 def get_namespace(self):
2822 """
2823 Get the namespace of context
2824
2825 :returns: namespace
2826 """
2827 return self.nspace
2828
2829 def close(self):
2830 """
2831 Close a rados.Ioctx object.
2832
2833 This just tells librados that you no longer need to use the io context.
2834 It may not be freed immediately if there are pending asynchronous
2835 requests on it, but you should not use an io context again after
2836 calling this function on it.
2837 """
2838 if self.state == "open":
2839 self.require_ioctx_open()
2840 with nogil:
2841 rados_ioctx_destroy(self.io)
2842 self.state = "closed"
2843
2844
2845 @requires(('key', str_type), ('data', bytes))
2846 def write(self, key, data, offset=0):
2847 """
2848 Write data to an object synchronously
2849
2850 :param key: name of the object
2851 :type key: str
2852 :param data: data to write
2853 :type data: bytes
2854 :param offset: byte offset in the object to begin writing at
2855 :type offset: int
2856
2857 :raises: :class:`TypeError`
2858 :raises: :class:`LogicError`
2859 :returns: int - 0 on success
2860 """
2861 self.require_ioctx_open()
2862
2863 key = cstr(key, 'key')
2864 cdef:
2865 char *_key = key
2866 char *_data = data
2867 size_t length = len(data)
2868 uint64_t _offset = offset
2869
2870 with nogil:
2871 ret = rados_write(self.io, _key, _data, length, _offset)
2872 if ret == 0:
2873 return ret
2874 elif ret < 0:
2875 raise make_ex(ret, "Ioctx.write(%s): failed to write %s"
2876 % (self.name, key))
2877 else:
2878 raise LogicError("Ioctx.write(%s): rados_write \
2879returned %d, but should return zero on success." % (self.name, ret))
2880
2881 @requires(('key', str_type), ('data', bytes))
2882 def write_full(self, key, data):
2883 """
2884 Write an entire object synchronously.
2885
2886 The object is filled with the provided data. If the object exists,
2887 it is atomically truncated and then written.
2888
2889 :param key: name of the object
2890 :type key: str
2891 :param data: data to write
2892 :type data: bytes
2893
2894 :raises: :class:`TypeError`
2895 :raises: :class:`Error`
2896 :returns: int - 0 on success
2897 """
2898 self.require_ioctx_open()
2899 key = cstr(key, 'key')
2900 cdef:
2901 char *_key = key
2902 char *_data = data
2903 size_t length = len(data)
2904
2905 with nogil:
2906 ret = rados_write_full(self.io, _key, _data, length)
2907 if ret == 0:
2908 return ret
2909 elif ret < 0:
2910 raise make_ex(ret, "Ioctx.write_full(%s): failed to write %s"
2911 % (self.name, key))
2912 else:
2913 raise LogicError("Ioctx.write_full(%s): rados_write_full \
2914returned %d, but should return zero on success." % (self.name, ret))
2915
9f95a23c
TL
2916 @requires(('key', str_type), ('data', bytes), ('write_len', int), ('offset', int))
2917 def writesame(self, key, data, write_len, offset=0):
2918 """
2919 Write the same buffer multiple times
2920 :param key: name of the object
2921 :type key: str
2922 :param data: data to write
2923 :type data: bytes
2924 :param write_len: total number of bytes to write
2925 :type write_len: int
2926 :param offset: byte offset in the object to begin writing at
2927 :type offset: int
2928
2929 :raises: :class:`TypeError`
2930 :raises: :class:`LogicError`
2931 """
2932 self.require_ioctx_open()
2933
2934 key = cstr(key, 'key')
2935 cdef:
2936 char *_key = key
2937 char *_data = data
2938 size_t _data_len = len(data)
2939 size_t _write_len = write_len
2940 uint64_t _offset = offset
2941
2942 with nogil:
2943 ret = rados_writesame(self.io, _key, _data, _data_len, _write_len, _offset)
2944 if ret < 0:
2945 raise make_ex(ret, "Ioctx.writesame(%s): failed to write %s"
2946 % (self.name, key))
2947 assert(ret == 0)
2948
7c673cae
FG
2949 @requires(('key', str_type), ('data', bytes))
2950 def append(self, key, data):
2951 """
2952 Append data to an object synchronously
2953
2954 :param key: name of the object
2955 :type key: str
2956 :param data: data to write
2957 :type data: bytes
2958
2959 :raises: :class:`TypeError`
2960 :raises: :class:`LogicError`
2961 :returns: int - 0 on success
2962 """
2963 self.require_ioctx_open()
2964 key = cstr(key, 'key')
2965 cdef:
2966 char *_key = key
2967 char *_data = data
2968 size_t length = len(data)
2969
2970 with nogil:
2971 ret = rados_append(self.io, _key, _data, length)
2972 if ret == 0:
2973 return ret
2974 elif ret < 0:
2975 raise make_ex(ret, "Ioctx.append(%s): failed to append %s"
2976 % (self.name, key))
2977 else:
2978 raise LogicError("Ioctx.append(%s): rados_append \
2979returned %d, but should return zero on success." % (self.name, ret))
2980
2981 @requires(('key', str_type))
2982 def read(self, key, length=8192, offset=0):
2983 """
2984 Read data from an object synchronously
2985
2986 :param key: name of the object
2987 :type key: str
2988 :param length: the number of bytes to read (default=8192)
2989 :type length: int
2990 :param offset: byte offset in the object to begin reading at
2991 :type offset: int
2992
2993 :raises: :class:`TypeError`
2994 :raises: :class:`Error`
2995 :returns: str - data read from object
2996 """
2997 self.require_ioctx_open()
2998 key = cstr(key, 'key')
2999 cdef:
3000 char *_key = key
3001 char *ret_buf
3002 uint64_t _offset = offset
3003 size_t _length = length
3004 PyObject* ret_s = NULL
3005
3006 ret_s = PyBytes_FromStringAndSize(NULL, length)
3007 try:
3008 ret_buf = PyBytes_AsString(ret_s)
3009 with nogil:
3010 ret = rados_read(self.io, _key, ret_buf, _length, _offset)
3011 if ret < 0:
3012 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
3013
3014 if ret != length:
3015 _PyBytes_Resize(&ret_s, ret)
3016
3017 return <object>ret_s
3018 finally:
3019 # We DECREF unconditionally: the cast to object above will have
3020 # INCREFed if necessary. This also takes care of exceptions,
3021 # including if _PyString_Resize fails (that will free the string
3022 # itself and set ret_s to NULL, hence XDECREF).
3023 ref.Py_XDECREF(ret_s)
3024
3025 @requires(('key', str_type), ('cls', str_type), ('method', str_type), ('data', bytes))
3026 def execute(self, key, cls, method, data, length=8192):
3027 """
3028 Execute an OSD class method on an object.
3029
3030 :param key: name of the object
3031 :type key: str
3032 :param cls: name of the object class
3033 :type cls: str
3034 :param method: name of the method
3035 :type method: str
3036 :param data: input data
3037 :type data: bytes
3038 :param length: size of output buffer in bytes (default=8192)
3039 :type length: int
3040
3041 :raises: :class:`TypeError`
3042 :raises: :class:`Error`
3043 :returns: (ret, method output)
3044 """
3045 self.require_ioctx_open()
3046
3047 key = cstr(key, 'key')
3048 cls = cstr(cls, 'cls')
3049 method = cstr(method, 'method')
3050 cdef:
3051 char *_key = key
3052 char *_cls = cls
3053 char *_method = method
3054 char *_data = data
3055 size_t _data_len = len(data)
3056
3057 char *ref_buf
3058 size_t _length = length
3059 PyObject* ret_s = NULL
3060
3061 ret_s = PyBytes_FromStringAndSize(NULL, length)
3062 try:
3063 ret_buf = PyBytes_AsString(ret_s)
3064 with nogil:
3065 ret = rados_exec(self.io, _key, _cls, _method, _data,
3066 _data_len, ret_buf, _length)
3067 if ret < 0:
3068 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
3069
3070 if ret != length:
3071 _PyBytes_Resize(&ret_s, ret)
3072
3073 return ret, <object>ret_s
3074 finally:
3075 # We DECREF unconditionally: the cast to object above will have
3076 # INCREFed if necessary. This also takes care of exceptions,
3077 # including if _PyString_Resize fails (that will free the string
3078 # itself and set ret_s to NULL, hence XDECREF).
3079 ref.Py_XDECREF(ret_s)
3080
3081 def get_stats(self):
3082 """
3083 Get pool usage statistics
3084
3085 :returns: dict - contains the following keys:
3086
3087 - ``num_bytes`` (int) - size of pool in bytes
3088
3089 - ``num_kb`` (int) - size of pool in kbytes
3090
3091 - ``num_objects`` (int) - number of objects in the pool
3092
3093 - ``num_object_clones`` (int) - number of object clones
3094
3095 - ``num_object_copies`` (int) - number of object copies
3096
3097 - ``num_objects_missing_on_primary`` (int) - number of objets
3098 missing on primary
3099
3100 - ``num_objects_unfound`` (int) - number of unfound objects
3101
3102 - ``num_objects_degraded`` (int) - number of degraded objects
3103
3104 - ``num_rd`` (int) - bytes read
3105
3106 - ``num_rd_kb`` (int) - kbytes read
3107
3108 - ``num_wr`` (int) - bytes written
3109
3110 - ``num_wr_kb`` (int) - kbytes written
3111 """
3112 self.require_ioctx_open()
3113 cdef rados_pool_stat_t stats
3114 with nogil:
3115 ret = rados_ioctx_pool_stat(self.io, &stats)
3116 if ret < 0:
3117 raise make_ex(ret, "Ioctx.get_stats(%s): get_stats failed" % self.name)
3118 return {'num_bytes': stats.num_bytes,
3119 'num_kb': stats.num_kb,
3120 'num_objects': stats.num_objects,
3121 'num_object_clones': stats.num_object_clones,
3122 'num_object_copies': stats.num_object_copies,
3123 "num_objects_missing_on_primary": stats.num_objects_missing_on_primary,
3124 "num_objects_unfound": stats.num_objects_unfound,
3125 "num_objects_degraded": stats.num_objects_degraded,
3126 "num_rd": stats.num_rd,
3127 "num_rd_kb": stats.num_rd_kb,
3128 "num_wr": stats.num_wr,
3129 "num_wr_kb": stats.num_wr_kb}
3130
3131 @requires(('key', str_type))
3132 def remove_object(self, key):
3133 """
3134 Delete an object
3135
3136 This does not delete any snapshots of the object.
3137
3138 :param key: the name of the object to delete
3139 :type key: str
3140
3141 :raises: :class:`TypeError`
3142 :raises: :class:`Error`
3143 :returns: bool - True on success
3144 """
3145 self.require_ioctx_open()
3146 key = cstr(key, 'key')
3147 cdef:
3148 char *_key = key
3149
3150 with nogil:
3151 ret = rados_remove(self.io, _key)
3152 if ret < 0:
3153 raise make_ex(ret, "Failed to remove '%s'" % key)
3154 return True
3155
3156 @requires(('key', str_type))
3157 def trunc(self, key, size):
3158 """
3159 Resize an object
3160
3161 If this enlarges the object, the new area is logically filled with
3162 zeroes. If this shrinks the object, the excess data is removed.
3163
3164 :param key: the name of the object to resize
3165 :type key: str
3166 :param size: the new size of the object in bytes
3167 :type size: int
3168
3169 :raises: :class:`TypeError`
3170 :raises: :class:`Error`
3171 :returns: int - 0 on success, otherwise raises error
3172 """
3173
3174 self.require_ioctx_open()
3175 key = cstr(key, 'key')
3176 cdef:
3177 char *_key = key
3178 uint64_t _size = size
3179
3180 with nogil:
3181 ret = rados_trunc(self.io, _key, _size)
3182 if ret < 0:
3183 raise make_ex(ret, "Ioctx.trunc(%s): failed to truncate %s" % (self.name, key))
3184 return ret
3185
3186 @requires(('key', str_type))
3187 def stat(self, key):
3188 """
3189 Get object stats (size/mtime)
3190
3191 :param key: the name of the object to get stats from
3192 :type key: str
3193
3194 :raises: :class:`TypeError`
3195 :raises: :class:`Error`
3196 :returns: (size,timestamp)
3197 """
3198 self.require_ioctx_open()
3199
3200 key = cstr(key, 'key')
3201 cdef:
3202 char *_key = key
3203 uint64_t psize
3204 time_t pmtime
3205
3206 with nogil:
3207 ret = rados_stat(self.io, _key, &psize, &pmtime)
3208 if ret < 0:
3209 raise make_ex(ret, "Failed to stat %r" % key)
3210 return psize, time.localtime(pmtime)
3211
3212 @requires(('key', str_type), ('xattr_name', str_type))
3213 def get_xattr(self, key, xattr_name):
3214 """
3215 Get the value of an extended attribute on an object.
3216
3217 :param key: the name of the object to get xattr from
3218 :type key: str
3219 :param xattr_name: which extended attribute to read
3220 :type xattr_name: str
3221
3222 :raises: :class:`TypeError`
3223 :raises: :class:`Error`
3224 :returns: str - value of the xattr
3225 """
3226 self.require_ioctx_open()
3227
3228 key = cstr(key, 'key')
3229 xattr_name = cstr(xattr_name, 'xattr_name')
3230 cdef:
3231 char *_key = key
3232 char *_xattr_name = xattr_name
3233 size_t ret_length = 4096
3234 char *ret_buf = NULL
3235
3236 try:
3237 while ret_length < 4096 * 1024 * 1024:
3238 ret_buf = <char *>realloc_chk(ret_buf, ret_length)
3239 with nogil:
3240 ret = rados_getxattr(self.io, _key, _xattr_name, ret_buf, ret_length)
3241 if ret == -errno.ERANGE:
3242 ret_length *= 2
3243 elif ret < 0:
3244 raise make_ex(ret, "Failed to get xattr %r" % xattr_name)
3245 else:
3246 break
3247 return ret_buf[:ret]
3248 finally:
3249 free(ret_buf)
3250
3251 @requires(('oid', str_type))
3252 def get_xattrs(self, oid):
3253 """
3254 Start iterating over xattrs on an object.
3255
3256 :param oid: the name of the object to get xattrs from
3257 :type oid: str
3258
3259 :raises: :class:`TypeError`
3260 :raises: :class:`Error`
3261 :returns: XattrIterator
3262 """
3263 self.require_ioctx_open()
3264 return XattrIterator(self, oid)
3265
3266 @requires(('key', str_type), ('xattr_name', str_type), ('xattr_value', bytes))
3267 def set_xattr(self, key, xattr_name, xattr_value):
3268 """
3269 Set an extended attribute on an object.
3270
3271 :param key: the name of the object to set xattr to
3272 :type key: str
3273 :param xattr_name: which extended attribute to set
3274 :type xattr_name: str
3275 :param xattr_value: the value of the extended attribute
3276 :type xattr_value: bytes
3277
3278 :raises: :class:`TypeError`
3279 :raises: :class:`Error`
3280 :returns: bool - True on success, otherwise raise an error
3281 """
3282 self.require_ioctx_open()
3283
3284 key = cstr(key, 'key')
3285 xattr_name = cstr(xattr_name, 'xattr_name')
3286 cdef:
3287 char *_key = key
3288 char *_xattr_name = xattr_name
3289 char *_xattr_value = xattr_value
3290 size_t _xattr_value_len = len(xattr_value)
3291
3292 with nogil:
3293 ret = rados_setxattr(self.io, _key, _xattr_name,
3294 _xattr_value, _xattr_value_len)
3295 if ret < 0:
3296 raise make_ex(ret, "Failed to set xattr %r" % xattr_name)
3297 return True
3298
3299 @requires(('key', str_type), ('xattr_name', str_type))
3300 def rm_xattr(self, key, xattr_name):
3301 """
3302 Removes an extended attribute on from an object.
3303
3304 :param key: the name of the object to remove xattr from
3305 :type key: str
3306 :param xattr_name: which extended attribute to remove
3307 :type xattr_name: str
3308
3309 :raises: :class:`TypeError`
3310 :raises: :class:`Error`
3311 :returns: bool - True on success, otherwise raise an error
3312 """
3313 self.require_ioctx_open()
3314
3315 key = cstr(key, 'key')
3316 xattr_name = cstr(xattr_name, 'xattr_name')
3317 cdef:
3318 char *_key = key
3319 char *_xattr_name = xattr_name
3320
3321 with nogil:
3322 ret = rados_rmxattr(self.io, _key, _xattr_name)
3323 if ret < 0:
3324 raise make_ex(ret, "Failed to delete key %r xattr %r" %
3325 (key, xattr_name))
3326 return True
3327
11fdf7f2
TL
3328 @requires(('obj', str_type), ('msg', str_type), ('timeout_ms', int))
3329 def notify(self, obj, msg='', timeout_ms=5000):
3330 """
3331 Send a rados notification to an object.
3332
3333 :param obj: the name of the object to notify
3334 :type obj: str
3335 :param msg: optional message to send in the notification
3336 :type msg: str
3337 :param timeout_ms: notify timeout (in ms)
3338 :type timeout_ms: int
3339
3340 :raises: :class:`TypeError`
3341 :raises: :class:`Error`
3342 :returns: bool - True on success, otherwise raise an error
3343 """
3344 self.require_ioctx_open()
3345
3346 msglen = len(msg)
3347 obj = cstr(obj, 'obj')
3348 msg = cstr(msg, 'msg')
3349 cdef:
3350 char *_obj = obj
3351 char *_msg = msg
3352 int _msglen = msglen
3353 uint64_t _timeout_ms = timeout_ms
3354
3355 with nogil:
3356 ret = rados_notify2(self.io, _obj, _msg, _msglen, _timeout_ms,
3357 NULL, NULL)
3358 if ret < 0:
3359 raise make_ex(ret, "Failed to notify %r" % (obj))
3360 return True
3361
7c673cae
FG
3362 def list_objects(self):
3363 """
3364 Get ObjectIterator on rados.Ioctx object.
3365
3366 :returns: ObjectIterator
3367 """
3368 self.require_ioctx_open()
3369 return ObjectIterator(self)
3370
3371 def list_snaps(self):
3372 """
3373 Get SnapIterator on rados.Ioctx object.
3374
3375 :returns: SnapIterator
3376 """
3377 self.require_ioctx_open()
3378 return SnapIterator(self)
3379
9f95a23c
TL
3380 def get_pool_id(self):
3381 """
3382 Get pool id
3383
3384 :returns: int - pool id
3385 """
3386 with nogil:
3387 ret = rados_ioctx_get_id(self.io)
3388 return ret;
3389
3390 def get_pool_name(self):
3391 """
3392 Get pool name
3393
3394 :returns: str - pool name
3395 """
3396 cdef:
3397 int name_len = 10
3398 char *name = NULL
3399
3400 try:
3401 while True:
3402 name = <char *>realloc_chk(name, name_len)
3403 with nogil:
3404 ret = rados_ioctx_get_pool_name(self.io, name, name_len)
3405 if ret > 0:
3406 break
3407 elif ret != -errno.ERANGE:
3408 raise make_ex(ret, "get pool name error")
3409 else:
3410 name_len = name_len * 2
3411
3412 return decode_cstr(name)
3413 finally:
3414 free(name)
3415
3416
7c673cae
FG
3417 @requires(('snap_name', str_type))
3418 def create_snap(self, snap_name):
3419 """
3420 Create a pool-wide snapshot
3421
3422 :param snap_name: the name of the snapshot
3423 :type snap_name: str
3424
3425 :raises: :class:`TypeError`
3426 :raises: :class:`Error`
3427 """
3428 self.require_ioctx_open()
3429 snap_name = cstr(snap_name, 'snap_name')
3430 cdef char *_snap_name = snap_name
3431
3432 with nogil:
3433 ret = rados_ioctx_snap_create(self.io, _snap_name)
3434 if ret != 0:
3435 raise make_ex(ret, "Failed to create snap %s" % snap_name)
3436
3437 @requires(('snap_name', str_type))
3438 def remove_snap(self, snap_name):
3439 """
3440 Removes a pool-wide snapshot
3441
3442 :param snap_name: the name of the snapshot
3443 :type snap_name: str
3444
3445 :raises: :class:`TypeError`
3446 :raises: :class:`Error`
3447 """
3448 self.require_ioctx_open()
3449 snap_name = cstr(snap_name, 'snap_name')
3450 cdef char *_snap_name = snap_name
3451
3452 with nogil:
3453 ret = rados_ioctx_snap_remove(self.io, _snap_name)
3454 if ret != 0:
3455 raise make_ex(ret, "Failed to remove snap %s" % snap_name)
3456
3457 @requires(('snap_name', str_type))
3458 def lookup_snap(self, snap_name):
3459 """
3460 Get the id of a pool snapshot
3461
3462 :param snap_name: the name of the snapshot to lookop
3463 :type snap_name: str
3464
3465 :raises: :class:`TypeError`
3466 :raises: :class:`Error`
3467 :returns: Snap - on success
3468 """
3469 self.require_ioctx_open()
3470 csnap_name = cstr(snap_name, 'snap_name')
3471 cdef:
3472 char *_snap_name = csnap_name
3473 rados_snap_t snap_id
3474
3475 with nogil:
3476 ret = rados_ioctx_snap_lookup(self.io, _snap_name, &snap_id)
3477 if ret != 0:
3478 raise make_ex(ret, "Failed to lookup snap %s" % snap_name)
3479 return Snap(self, snap_name, int(snap_id))
3480
3481 @requires(('oid', str_type), ('snap_name', str_type))
3482 def snap_rollback(self, oid, snap_name):
3483 """
3484 Rollback an object to a snapshot
3485
3486 :param oid: the name of the object
3487 :type oid: str
3488 :param snap_name: the name of the snapshot
3489 :type snap_name: str
3490
3491 :raises: :class:`TypeError`
3492 :raises: :class:`Error`
3493 """
3494 self.require_ioctx_open()
3495 oid = cstr(oid, 'oid')
3496 snap_name = cstr(snap_name, 'snap_name')
3497 cdef:
3498 char *_snap_name = snap_name
3499 char *_oid = oid
3500
3501 with nogil:
3502 ret = rados_ioctx_snap_rollback(self.io, _oid, _snap_name)
3503 if ret != 0:
3504 raise make_ex(ret, "Failed to rollback %s" % oid)
3505
28e407b8
AA
3506 def create_self_managed_snap(self):
3507 """
3508 Creates a self-managed snapshot
3509
3510 :returns: snap id on success
3511
3512 :raises: :class:`Error`
3513 """
3514 self.require_ioctx_open()
3515 cdef:
3516 rados_snap_t _snap_id
3517 with nogil:
3518 ret = rados_ioctx_selfmanaged_snap_create(self.io, &_snap_id)
3519 if ret != 0:
3520 raise make_ex(ret, "Failed to create self-managed snapshot")
3521 return int(_snap_id)
3522
3523 @requires(('snap_id', int))
3524 def remove_self_managed_snap(self, snap_id):
3525 """
3526 Removes a self-managed snapshot
3527
3528 :param snap_id: the name of the snapshot
3529 :type snap_id: int
3530
3531 :raises: :class:`TypeError`
3532 :raises: :class:`Error`
3533 """
3534 self.require_ioctx_open()
3535 cdef:
3536 rados_snap_t _snap_id = snap_id
3537 with nogil:
3538 ret = rados_ioctx_selfmanaged_snap_remove(self.io, _snap_id)
3539 if ret != 0:
3540 raise make_ex(ret, "Failed to remove self-managed snapshot")
3541
3542 def set_self_managed_snap_write(self, snaps):
3543 """
3544 Updates the write context to the specified self-managed
3545 snapshot ids.
3546
3547 :param snaps: all associated self-managed snapshot ids
3548 :type snaps: list
3549
3550 :raises: :class:`TypeError`
3551 :raises: :class:`Error`
3552 """
3553 self.require_ioctx_open()
3554 sorted_snaps = []
3555 snap_seq = 0
3556 if snaps:
3557 sorted_snaps = sorted([int(x) for x in snaps], reverse=True)
3558 snap_seq = sorted_snaps[0]
3559
3560 cdef:
3561 rados_snap_t _snap_seq = snap_seq
3562 rados_snap_t *_snaps = NULL
3563 int _num_snaps = len(sorted_snaps)
3564 try:
3565 _snaps = <rados_snap_t *>malloc(_num_snaps * sizeof(rados_snap_t))
3566 for i in range(len(sorted_snaps)):
3567 _snaps[i] = sorted_snaps[i]
3568 with nogil:
3569 ret = rados_ioctx_selfmanaged_snap_set_write_ctx(self.io,
3570 _snap_seq,
3571 _snaps,
3572 _num_snaps)
3573 if ret != 0:
3574 raise make_ex(ret, "Failed to update snapshot write context")
3575 finally:
3576 free(_snaps)
3577
3578 @requires(('oid', str_type), ('snap_id', int))
3579 def rollback_self_managed_snap(self, oid, snap_id):
3580 """
3581 Rolls an specific object back to a self-managed snapshot revision
3582
3583 :param oid: the name of the object
3584 :type oid: str
3585 :param snap_id: the name of the snapshot
3586 :type snap_id: int
3587
3588 :raises: :class:`TypeError`
3589 :raises: :class:`Error`
3590 """
3591 self.require_ioctx_open()
3592 oid = cstr(oid, 'oid')
3593 cdef:
3594 char *_oid = oid
3595 rados_snap_t _snap_id = snap_id
3596 with nogil:
3597 ret = rados_ioctx_selfmanaged_snap_rollback(self.io, _oid, _snap_id)
3598 if ret != 0:
3599 raise make_ex(ret, "Failed to rollback %s" % oid)
3600
7c673cae
FG
3601 def get_last_version(self):
3602 """
3603 Return the version of the last object read or written to.
3604
3605 This exposes the internal version number of the last object read or
3606 written via this io context
3607
3608 :returns: version of the last object used
3609 """
3610 self.require_ioctx_open()
3611 with nogil:
3612 ret = rados_get_last_version(self.io)
3613 return int(ret)
3614
3615 def create_write_op(self):
3616 """
3617 create write operation object.
3618 need call release_write_op after use
3619 """
3620 return WriteOp().create()
3621
3622 def create_read_op(self):
3623 """
3624 create read operation object.
3625 need call release_read_op after use
3626 """
3627 return ReadOp().create()
3628
3629 def release_write_op(self, write_op):
3630 """
3631 release memory alloc by create_write_op
3632 """
3633 write_op.release()
3634
3635 def release_read_op(self, read_op):
3636 """
3637 release memory alloc by create_read_op
3638 :para read_op: read_op object
3639 :type: int
3640 """
3641 read_op.release()
3642
3643 @requires(('write_op', WriteOp), ('keys', tuple), ('values', tuple))
3644 def set_omap(self, write_op, keys, values):
3645 """
3646 set keys values to write_op
3647 :para write_op: write_operation object
3648 :type write_op: WriteOp
3649 :para keys: a tuple of keys
3650 :type keys: tuple
3651 :para values: a tuple of values
3652 :type values: tuple
3653 """
3654
3655 if len(keys) != len(values):
3656 raise Error("Rados(): keys and values must have the same number of items")
3657
3658 keys = cstr_list(keys, 'keys')
eafe8130
TL
3659 values = cstr_list(values, 'values')
3660 lens = [len(v) for v in values]
7c673cae
FG
3661 cdef:
3662 WriteOp _write_op = write_op
3663 size_t key_num = len(keys)
3664 char **_keys = to_bytes_array(keys)
3665 char **_values = to_bytes_array(values)
eafe8130 3666 size_t *_lens = to_csize_t_array(lens)
7c673cae
FG
3667
3668 try:
3669 with nogil:
3670 rados_write_op_omap_set(_write_op.write_op,
3671 <const char**>_keys,
3672 <const char**>_values,
3673 <const size_t*>_lens, key_num)
3674 finally:
3675 free(_keys)
3676 free(_values)
3677 free(_lens)
3678
3679 @requires(('write_op', WriteOp), ('oid', str_type), ('mtime', opt(int)), ('flags', opt(int)))
3680 def operate_write_op(self, write_op, oid, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3681 """
11fdf7f2 3682 execute the real write operation
7c673cae
FG
3683 :para write_op: write operation object
3684 :type write_op: WriteOp
3685 :para oid: object name
3686 :type oid: str
3687 :para mtime: the time to set the mtime to, 0 for the current time
3688 :type mtime: int
3689 :para flags: flags to apply to the entire operation
3690 :type flags: int
3691 """
3692
3693 oid = cstr(oid, 'oid')
3694 cdef:
3695 WriteOp _write_op = write_op
3696 char *_oid = oid
3697 time_t _mtime = mtime
3698 int _flags = flags
3699
3700 with nogil:
3701 ret = rados_write_op_operate(_write_op.write_op, self.io, _oid, &_mtime, _flags)
3702 if ret != 0:
3703 raise make_ex(ret, "Failed to operate write op for oid %s" % oid)
3704
3705 @requires(('write_op', WriteOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('mtime', opt(int)), ('flags', opt(int)))
3706 def operate_aio_write_op(self, write_op, oid, oncomplete=None, onsafe=None, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3707 """
11fdf7f2 3708 execute the real write operation asynchronously
7c673cae
FG
3709 :para write_op: write operation object
3710 :type write_op: WriteOp
3711 :para oid: object name
3712 :type oid: str
3713 :param oncomplete: what to do when the remove is safe and complete in memory
3714 on all replicas
3715 :type oncomplete: completion
3716 :param onsafe: what to do when the remove is safe and complete on storage
3717 on all replicas
3718 :type onsafe: completion
3719 :para mtime: the time to set the mtime to, 0 for the current time
3720 :type mtime: int
3721 :para flags: flags to apply to the entire operation
3722 :type flags: int
3723
3724 :raises: :class:`Error`
3725 :returns: completion object
3726 """
3727
3728 oid = cstr(oid, 'oid')
3729 cdef:
3730 WriteOp _write_op = write_op
3731 char *_oid = oid
3732 Completion completion
3733 time_t _mtime = mtime
3734 int _flags = flags
3735
3736 completion = self.__get_completion(oncomplete, onsafe)
3737 self.__track_completion(completion)
3738
3739 with nogil:
3740 ret = rados_aio_write_op_operate(_write_op.write_op, self.io, completion.rados_comp, _oid,
3741 &_mtime, _flags)
3742 if ret != 0:
3743 completion._cleanup()
3744 raise make_ex(ret, "Failed to operate aio write op for oid %s" % oid)
3745 return completion
3746
3747 @requires(('read_op', ReadOp), ('oid', str_type), ('flag', opt(int)))
3748 def operate_read_op(self, read_op, oid, flag=LIBRADOS_OPERATION_NOFLAG):
3749 """
11fdf7f2 3750 execute the real read operation
7c673cae
FG
3751 :para read_op: read operation object
3752 :type read_op: ReadOp
3753 :para oid: object name
3754 :type oid: str
3755 :para flag: flags to apply to the entire operation
3756 :type flag: int
3757 """
3758 oid = cstr(oid, 'oid')
3759 cdef:
3760 ReadOp _read_op = read_op
3761 char *_oid = oid
3762 int _flag = flag
3763
3764 with nogil:
3765 ret = rados_read_op_operate(_read_op.read_op, self.io, _oid, _flag)
3766 if ret != 0:
3767 raise make_ex(ret, "Failed to operate read op for oid %s" % oid)
3768
3769 @requires(('read_op', ReadOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('flag', opt(int)))
3770 def operate_aio_read_op(self, read_op, oid, oncomplete=None, onsafe=None, flag=LIBRADOS_OPERATION_NOFLAG):
3771 """
11fdf7f2 3772 execute the real read operation
7c673cae
FG
3773 :para read_op: read operation object
3774 :type read_op: ReadOp
3775 :para oid: object name
3776 :type oid: str
3777 :param oncomplete: what to do when the remove is safe and complete in memory
3778 on all replicas
3779 :type oncomplete: completion
3780 :param onsafe: what to do when the remove is safe and complete on storage
3781 on all replicas
3782 :type onsafe: completion
3783 :para flag: flags to apply to the entire operation
3784 :type flag: int
3785 """
3786 oid = cstr(oid, 'oid')
3787 cdef:
3788 ReadOp _read_op = read_op
3789 char *_oid = oid
3790 Completion completion
3791 int _flag = flag
3792
3793 completion = self.__get_completion(oncomplete, onsafe)
3794 self.__track_completion(completion)
3795
3796 with nogil:
3797 ret = rados_aio_read_op_operate(_read_op.read_op, self.io, completion.rados_comp, _oid, _flag)
3798 if ret != 0:
3799 completion._cleanup()
3800 raise make_ex(ret, "Failed to operate aio read op for oid %s" % oid)
3801 return completion
3802
3803 @requires(('read_op', ReadOp), ('start_after', str_type), ('filter_prefix', str_type), ('max_return', int))
3804 def get_omap_vals(self, read_op, start_after, filter_prefix, max_return):
3805 """
3806 get the omap values
3807 :para read_op: read operation object
3808 :type read_op: ReadOp
3809 :para start_after: list keys starting after start_after
3810 :type start_after: str
3811 :para filter_prefix: list only keys beginning with filter_prefix
3812 :type filter_prefix: str
3813 :para max_return: list no more than max_return key/value pairs
3814 :type max_return: int
3815 :returns: an iterator over the requested omap values, return value from this action
3816 """
3817
3818 start_after = cstr(start_after, 'start_after') if start_after else None
3819 filter_prefix = cstr(filter_prefix, 'filter_prefix') if filter_prefix else None
3820 cdef:
3821 char *_start_after = opt_str(start_after)
3822 char *_filter_prefix = opt_str(filter_prefix)
3823 ReadOp _read_op = read_op
3824 rados_omap_iter_t iter_addr = NULL
3825 int _max_return = max_return
7c673cae
FG
3826
3827 with nogil:
d2e6a577 3828 rados_read_op_omap_get_vals2(_read_op.read_op, _start_after, _filter_prefix,
91327a77 3829 _max_return, &iter_addr, NULL, NULL)
7c673cae
FG
3830 it = OmapIterator(self)
3831 it.ctx = iter_addr
91327a77 3832 return it, 0 # 0 is meaningless; there for backward-compat
7c673cae
FG
3833
3834 @requires(('read_op', ReadOp), ('start_after', str_type), ('max_return', int))
3835 def get_omap_keys(self, read_op, start_after, max_return):
3836 """
3837 get the omap keys
3838 :para read_op: read operation object
3839 :type read_op: ReadOp
3840 :para start_after: list keys starting after start_after
3841 :type start_after: str
3842 :para max_return: list no more than max_return key/value pairs
3843 :type max_return: int
3844 :returns: an iterator over the requested omap values, return value from this action
3845 """
3846 start_after = cstr(start_after, 'start_after') if start_after else None
3847 cdef:
3848 char *_start_after = opt_str(start_after)
3849 ReadOp _read_op = read_op
3850 rados_omap_iter_t iter_addr = NULL
3851 int _max_return = max_return
7c673cae
FG
3852
3853 with nogil:
d2e6a577 3854 rados_read_op_omap_get_keys2(_read_op.read_op, _start_after,
91327a77 3855 _max_return, &iter_addr, NULL, NULL)
7c673cae
FG
3856 it = OmapIterator(self)
3857 it.ctx = iter_addr
91327a77 3858 return it, 0 # 0 is meaningless; there for backward-compat
7c673cae
FG
3859
3860 @requires(('read_op', ReadOp), ('keys', tuple))
3861 def get_omap_vals_by_keys(self, read_op, keys):
3862 """
3863 get the omap values by keys
3864 :para read_op: read operation object
3865 :type read_op: ReadOp
3866 :para keys: input key tuple
3867 :type keys: tuple
3868 :returns: an iterator over the requested omap values, return value from this action
3869 """
3870 keys = cstr_list(keys, 'keys')
3871 cdef:
3872 ReadOp _read_op = read_op
3873 rados_omap_iter_t iter_addr
3874 char **_keys = to_bytes_array(keys)
3875 size_t key_num = len(keys)
7c673cae
FG
3876
3877 try:
3878 with nogil:
3879 rados_read_op_omap_get_vals_by_keys(_read_op.read_op,
3880 <const char**>_keys,
91327a77 3881 key_num, &iter_addr, NULL)
7c673cae
FG
3882 it = OmapIterator(self)
3883 it.ctx = iter_addr
91327a77 3884 return it, 0 # 0 is meaningless; there for backward-compat
7c673cae
FG
3885 finally:
3886 free(_keys)
3887
3888 @requires(('write_op', WriteOp), ('keys', tuple))
3889 def remove_omap_keys(self, write_op, keys):
3890 """
3891 remove omap keys specifiled
3892 :para write_op: write operation object
3893 :type write_op: WriteOp
3894 :para keys: input key tuple
3895 :type keys: tuple
3896 """
3897
3898 keys = cstr_list(keys, 'keys')
3899 cdef:
3900 WriteOp _write_op = write_op
3901 size_t key_num = len(keys)
3902 char **_keys = to_bytes_array(keys)
3903
3904 try:
3905 with nogil:
3906 rados_write_op_omap_rm_keys(_write_op.write_op, <const char**>_keys, key_num)
3907 finally:
3908 free(_keys)
3909
3910 @requires(('write_op', WriteOp))
3911 def clear_omap(self, write_op):
3912 """
3913 Remove all key/value pairs from an object
3914 :para write_op: write operation object
3915 :type write_op: WriteOp
3916 """
3917
3918 cdef:
3919 WriteOp _write_op = write_op
3920
3921 with nogil:
3922 rados_write_op_omap_clear(_write_op.write_op)
3923
3924 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('desc', str_type),
3925 ('duration', opt(int)), ('flags', int))
3926 def lock_exclusive(self, key, name, cookie, desc="", duration=None, flags=0):
3927
3928 """
3929 Take an exclusive lock on an object
3930
3931 :param key: name of the object
3932 :type key: str
3933 :param name: name of the lock
3934 :type name: str
3935 :param cookie: cookie of the lock
3936 :type cookie: str
3937 :param desc: description of the lock
3938 :type desc: str
3939 :param duration: duration of the lock in seconds
3940 :type duration: int
3941 :param flags: flags
3942 :type flags: int
3943
3944 :raises: :class:`TypeError`
3945 :raises: :class:`Error`
3946 """
3947 self.require_ioctx_open()
3948
3949 key = cstr(key, 'key')
3950 name = cstr(name, 'name')
3951 cookie = cstr(cookie, 'cookie')
3952 desc = cstr(desc, 'desc')
3953
3954 cdef:
3955 char* _key = key
3956 char* _name = name
3957 char* _cookie = cookie
3958 char* _desc = desc
3959 uint8_t _flags = flags
3960 timeval _duration
3961
3962 if duration is None:
3963 with nogil:
3964 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3965 NULL, _flags)
3966 else:
3967 _duration.tv_sec = duration
3968 with nogil:
3969 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3970 &_duration, _flags)
3971
3972 if ret < 0:
3973 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
3974
3975 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('tag', str_type),
3976 ('desc', str_type), ('duration', opt(int)), ('flags', int))
3977 def lock_shared(self, key, name, cookie, tag, desc="", duration=None, flags=0):
3978
3979 """
3980 Take a shared lock on an object
3981
3982 :param key: name of the object
3983 :type key: str
3984 :param name: name of the lock
3985 :type name: str
3986 :param cookie: cookie of the lock
3987 :type cookie: str
3988 :param tag: tag of the lock
3989 :type tag: str
3990 :param desc: description of the lock
3991 :type desc: str
3992 :param duration: duration of the lock in seconds
3993 :type duration: int
3994 :param flags: flags
3995 :type flags: int
3996
3997 :raises: :class:`TypeError`
3998 :raises: :class:`Error`
3999 """
4000 self.require_ioctx_open()
4001
4002 key = cstr(key, 'key')
4003 tag = cstr(tag, 'tag')
4004 name = cstr(name, 'name')
4005 cookie = cstr(cookie, 'cookie')
4006 desc = cstr(desc, 'desc')
4007
4008 cdef:
4009 char* _key = key
4010 char* _tag = tag
4011 char* _name = name
4012 char* _cookie = cookie
4013 char* _desc = desc
4014 uint8_t _flags = flags
4015 timeval _duration
4016
4017 if duration is None:
4018 with nogil:
4019 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
4020 NULL, _flags)
4021 else:
4022 _duration.tv_sec = duration
4023 with nogil:
4024 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
4025 &_duration, _flags)
4026 if ret < 0:
4027 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
4028
4029 @requires(('key', str_type), ('name', str_type), ('cookie', str_type))
4030 def unlock(self, key, name, cookie):
4031
4032 """
4033 Release a shared or exclusive lock on an object
4034
4035 :param key: name of the object
4036 :type key: str
4037 :param name: name of the lock
4038 :type name: str
4039 :param cookie: cookie of the lock
4040 :type cookie: str
4041
4042 :raises: :class:`TypeError`
4043 :raises: :class:`Error`
4044 """
4045 self.require_ioctx_open()
4046
4047 key = cstr(key, 'key')
4048 name = cstr(name, 'name')
4049 cookie = cstr(cookie, 'cookie')
4050
4051 cdef:
4052 char* _key = key
4053 char* _name = name
4054 char* _cookie = cookie
4055
4056 with nogil:
4057 ret = rados_unlock(self.io, _key, _name, _cookie)
4058 if ret < 0:
4059 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
4060
11fdf7f2
TL
4061 def set_osdmap_full_try(self):
4062 """
4063 Set global osdmap_full_try label to true
4064 """
4065 with nogil:
4066 rados_set_osdmap_full_try(self.io)
4067
4068 def unset_osdmap_full_try(self):
4069 """
4070 Unset
4071 """
4072 with nogil:
4073 rados_unset_osdmap_full_try(self.io)
4074
c07f9fc5
FG
4075 def application_enable(self, app_name, force=False):
4076 """
4077 Enable an application on an OSD pool
4078
4079 :param app_name: application name
4080 :type app_name: str
4081 :param force: False if only a single app should exist per pool
4082 :type expire_seconds: boool
4083
4084 :raises: :class:`Error`
4085 """
4086 app_name = cstr(app_name, 'app_name')
4087 cdef:
4088 char *_app_name = app_name
4089 int _force = (1 if force else 0)
4090
4091 with nogil:
4092 ret = rados_application_enable(self.io, _app_name, _force)
4093 if ret < 0:
4094 raise make_ex(ret, "error enabling application")
4095
4096 def application_list(self):
4097 """
4098 Returns a list of enabled applications
4099
4100 :returns: list of app name string
4101 """
4102 cdef:
4103 size_t length = 128
4104 char *apps = NULL
4105
4106 try:
4107 while True:
4108 apps = <char *>realloc_chk(apps, length)
4109 with nogil:
4110 ret = rados_application_list(self.io, apps, &length)
4111 if ret == 0:
4112 return [decode_cstr(app) for app in
4113 apps[:length].split(b'\0') if app]
4114 elif ret == -errno.ENOENT:
4115 return None
4116 elif ret == -errno.ERANGE:
4117 pass
4118 else:
4119 raise make_ex(ret, "error listing applications")
4120 finally:
4121 free(apps)
4122
9f95a23c
TL
4123 def application_metadata_get(self, app_name, key):
4124 """
4125 Gets application metadata on an OSD pool for the given key
4126
4127 :param app_name: application name
4128 :type app_name: str
4129 :param key: metadata key
4130 :type key: str
4131 :returns: str - metadata value
4132
4133 :raises: :class:`Error`
4134 """
4135
4136 app_name = cstr(app_name, 'app_name')
4137 key = cstr(key, 'key')
4138 cdef:
4139 char *_app_name = app_name
4140 char *_key = key
4141 size_t size = 129
4142 char *value = NULL
4143 int ret
4144 try:
4145 while True:
4146 value = <char *>realloc_chk(value, size)
4147 with nogil:
4148 ret = rados_application_metadata_get(self.io, _app_name,
4149 _key, value, &size)
4150 if ret != -errno.ERANGE:
4151 break
4152 if ret == -errno.ENOENT:
4153 raise KeyError('no metadata %s for application %s' % (key, _app_name))
4154 elif ret != 0:
4155 raise make_ex(ret, 'error getting metadata %s for application %s' %
4156 (key, _app_name))
4157 return decode_cstr(value)
4158 finally:
4159 free(value)
4160
c07f9fc5
FG
4161 def application_metadata_set(self, app_name, key, value):
4162 """
4163 Sets application metadata on an OSD pool
4164
4165 :param app_name: application name
4166 :type app_name: str
4167 :param key: metadata key
4168 :type key: str
4169 :param value: metadata value
4170 :type value: str
4171
4172 :raises: :class:`Error`
4173 """
4174 app_name = cstr(app_name, 'app_name')
4175 key = cstr(key, 'key')
4176 value = cstr(value, 'value')
4177 cdef:
4178 char *_app_name = app_name
4179 char *_key = key
4180 char *_value = value
4181
4182 with nogil:
4183 ret = rados_application_metadata_set(self.io, _app_name, _key,
4184 _value)
4185 if ret < 0:
4186 raise make_ex(ret, "error setting application metadata")
4187
4188 def application_metadata_remove(self, app_name, key):
4189 """
4190 Remove application metadata from an OSD pool
4191
4192 :param app_name: application name
4193 :type app_name: str
4194 :param key: metadata key
4195 :type key: str
4196
4197 :raises: :class:`Error`
4198 """
4199 app_name = cstr(app_name, 'app_name')
4200 key = cstr(key, 'key')
4201 cdef:
4202 char *_app_name = app_name
4203 char *_key = key
4204
4205 with nogil:
4206 ret = rados_application_metadata_remove(self.io, _app_name, _key)
4207 if ret < 0:
4208 raise make_ex(ret, "error removing application metadata")
4209
4210 def application_metadata_list(self, app_name):
4211 """
4212 Returns a list of enabled applications
4213
4214 :param app_name: application name
4215 :type app_name: str
4216 :returns: list of key/value tuples
4217 """
4218 app_name = cstr(app_name, 'app_name')
4219 cdef:
4220 char *_app_name = app_name
4221 size_t key_length = 128
4222 size_t val_length = 128
4223 char *c_keys = NULL
4224 char *c_vals = NULL
4225
4226 try:
4227 while True:
4228 c_keys = <char *>realloc_chk(c_keys, key_length)
4229 c_vals = <char *>realloc_chk(c_vals, val_length)
4230 with nogil:
4231 ret = rados_application_metadata_list(self.io, _app_name,
4232 c_keys, &key_length,
4233 c_vals, &val_length)
4234 if ret == 0:
4235 keys = [decode_cstr(key) for key in
11fdf7f2 4236 c_keys[:key_length].split(b'\0')]
c07f9fc5 4237 vals = [decode_cstr(val) for val in
11fdf7f2 4238 c_vals[:val_length].split(b'\0')]
9f95a23c 4239 return list(zip(keys, vals))[:-1]
c07f9fc5
FG
4240 elif ret == -errno.ERANGE:
4241 pass
4242 else:
4243 raise make_ex(ret, "error listing application metadata")
4244 finally:
4245 free(c_keys)
4246 free(c_vals)
4247
11fdf7f2
TL
4248 def alignment(self):
4249 """
4250 Returns pool alignment
4251
4252 :returns:
4253 Number of alignment bytes required by the current pool, or None if
4254 alignment is not required.
4255 """
4256 cdef:
4257 int requires = 0
4258 uint64_t _alignment
4259
4260 with nogil:
4261 ret = rados_ioctx_pool_requires_alignment2(self.io, &requires)
4262 if ret != 0:
4263 raise make_ex(ret, "error checking alignment")
4264
4265 alignment = None
4266 if requires:
4267 with nogil:
4268 ret = rados_ioctx_pool_required_alignment2(self.io, &_alignment)
4269 if ret != 0:
4270 raise make_ex(ret, "error querying alignment")
4271 alignment = _alignment
4272 return alignment
4273
7c673cae
FG
4274
4275def set_object_locator(func):
4276 def retfunc(self, *args, **kwargs):
4277 if self.locator_key is not None:
4278 old_locator = self.ioctx.get_locator_key()
4279 self.ioctx.set_locator_key(self.locator_key)
4280 retval = func(self, *args, **kwargs)
4281 self.ioctx.set_locator_key(old_locator)
4282 return retval
4283 else:
4284 return func(self, *args, **kwargs)
4285 return retfunc
4286
4287
4288def set_object_namespace(func):
4289 def retfunc(self, *args, **kwargs):
4290 if self.nspace is None:
4291 raise LogicError("Namespace not set properly in context")
4292 old_nspace = self.ioctx.get_namespace()
4293 self.ioctx.set_namespace(self.nspace)
4294 retval = func(self, *args, **kwargs)
4295 self.ioctx.set_namespace(old_nspace)
4296 return retval
4297 return retfunc
4298
4299
4300class Object(object):
4301 """Rados object wrapper, makes the object look like a file"""
4302 def __init__(self, ioctx, key, locator_key=None, nspace=None):
4303 self.key = key
4304 self.ioctx = ioctx
4305 self.offset = 0
4306 self.state = "exists"
4307 self.locator_key = locator_key
4308 self.nspace = "" if nspace is None else nspace
4309
4310 def __str__(self):
4311 return "rados.Object(ioctx=%s,key=%s,nspace=%s,locator=%s)" % \
4312 (str(self.ioctx), self.key, "--default--"
4313 if self.nspace is "" else self.nspace, self.locator_key)
4314
4315 def require_object_exists(self):
4316 if self.state != "exists":
4317 raise ObjectStateError("The object is %s" % self.state)
4318
4319 @set_object_locator
4320 @set_object_namespace
4321 def read(self, length=1024 * 1024):
4322 self.require_object_exists()
4323 ret = self.ioctx.read(self.key, length, self.offset)
4324 self.offset += len(ret)
4325 return ret
4326
4327 @set_object_locator
4328 @set_object_namespace
4329 def write(self, string_to_write):
4330 self.require_object_exists()
4331 ret = self.ioctx.write(self.key, string_to_write, self.offset)
4332 if ret == 0:
4333 self.offset += len(string_to_write)
4334 return ret
4335
4336 @set_object_locator
4337 @set_object_namespace
4338 def remove(self):
4339 self.require_object_exists()
4340 self.ioctx.remove_object(self.key)
4341 self.state = "removed"
4342
4343 @set_object_locator
4344 @set_object_namespace
4345 def stat(self):
4346 self.require_object_exists()
4347 return self.ioctx.stat(self.key)
4348
4349 def seek(self, position):
4350 self.require_object_exists()
4351 self.offset = position
4352
4353 @set_object_locator
4354 @set_object_namespace
4355 def get_xattr(self, xattr_name):
4356 self.require_object_exists()
4357 return self.ioctx.get_xattr(self.key, xattr_name)
4358
4359 @set_object_locator
4360 @set_object_namespace
4361 def get_xattrs(self):
4362 self.require_object_exists()
4363 return self.ioctx.get_xattrs(self.key)
4364
4365 @set_object_locator
4366 @set_object_namespace
4367 def set_xattr(self, xattr_name, xattr_value):
4368 self.require_object_exists()
4369 return self.ioctx.set_xattr(self.key, xattr_name, xattr_value)
4370
4371 @set_object_locator
4372 @set_object_namespace
4373 def rm_xattr(self, xattr_name):
4374 self.require_object_exists()
4375 return self.ioctx.rm_xattr(self.key, xattr_name)
4376
4377MONITOR_LEVELS = [
4378 "debug",
4379 "info",
4380 "warn", "warning",
4381 "err", "error",
4382 "sec",
4383 ]
4384
4385
4386class MonitorLog(object):
4387 # NOTE(sileht): Keep this class for backward compat
4388 # method moved to Rados.monitor_log()
4389 """
4390 For watching cluster log messages. Instantiate an object and keep
4391 it around while callback is periodically called. Construct with
4392 'level' to monitor 'level' messages (one of MONITOR_LEVELS).
4393 arg will be passed to the callback.
4394
4395 callback will be called with:
4396 arg (given to __init__)
4397 line (the full line, including timestamp, who, level, msg)
4398 who (which entity issued the log message)
4399 timestamp_sec (sec of a struct timespec)
4400 timestamp_nsec (sec of a struct timespec)
4401 seq (sequence number)
4402 level (string representing the level of the log message)
4403 msg (the message itself)
4404 callback's return value is ignored
4405 """
4406 def __init__(self, cluster, level, callback, arg):
4407 self.level = level
4408 self.callback = callback
4409 self.arg = arg
4410 self.cluster = cluster
4411 self.cluster.monitor_log(level, callback, arg)
4412