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