diff options
author | David Coles <dcoles@gaikai.com> | 2015-10-15 23:58:53 +0200 |
---|---|---|
committer | David Coles <dcoles@gaikai.com> | 2015-10-20 00:06:52 +0200 |
commit | ab6b92398071a5e364514afe2bdb57a634c04ceb (patch) | |
tree | f310a591abdd2c0902b031503f5da06e988c7ffd /src | |
parent | Merge pull request #5335 from zhouyuan/radosgw_admin_secret_key_alias (diff) | |
download | ceph-ab6b92398071a5e364514afe2bdb57a634c04ceb.tar.xz ceph-ab6b92398071a5e364514afe2bdb57a634c04ceb.zip |
pybind: Add Python 3 support for rados and rbd modules
Python 3 explicitly distinguishes between strings (which can contain any Unicode
character) and 8-bit byte strings. This means that we must explicitly encode and
decode strings that use C-style char* string APIs.
Functions that take a true-strings now have their values encoded to UTF-8 before
being passed to the C API, while functions that accept binary data only accept
the bytes type. To help with this the `cstr` helper function has been introduced
as a way of easily a string into a C-string compatible form.
There is also a number of general Python 3 compatibility fixes:
- dict.iteritems() is replaced with just dict.items()
- xrange() is replaced with just range
- Iterators now use the __next__ magic method
- zip() and map() now return iterators, rather than lists
- print() is now a function
- contextlib.nexted() is replaced with multiple manager with-statement (from Python 2.7)
This also required updating of the unit-tests for these modules, mostly due to
explicitly distinguishing between strings and byte strings.
Signed-off-by: David Coles <dcoles@gaikai.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/pybind/rados.py | 195 | ||||
-rw-r--r-- | src/pybind/rbd.py | 95 | ||||
-rw-r--r-- | src/test/pybind/test_rados.py | 181 | ||||
-rw-r--r-- | src/test/pybind/test_rbd.py | 181 |
4 files changed, 340 insertions, 312 deletions
diff --git a/src/pybind/rados.py b/src/pybind/rados.py index 804a1692020..30be4f93789 100644 --- a/src/pybind/rados.py +++ b/src/pybind/rados.py @@ -12,6 +12,7 @@ import errno import threading import time +from collections import Iterator from datetime import datetime from functools import wraps from itertools import chain @@ -261,6 +262,19 @@ def requires(*types): return wrapper +def cstr(val, encoding="utf-8"): + """ + Create a C-style string from a Python string + + :param str val: Python string + :rtype: c_char_p + """ + if val is None: + return c_char_p(None) + + return c_char_p(val.encode(encoding)) + + class Rados(object): """librados python wrapper""" def require_state(self, *args): @@ -297,15 +311,15 @@ Rados object in state %s." % self.state) if clustername is None: clustername = 'ceph' ret = run_in_thread(self.librados.rados_create2, - (byref(self.cluster), c_char_p(clustername), - c_char_p(name), c_uint64(flags))) + (byref(self.cluster), cstr(clustername), + cstr(name), c_uint64(flags))) if ret != 0: raise Error("rados_initialize failed with error code: %d" % ret) self.state = "configuring" # order is important: conf_defaults, then conffile, then conf if conf_defaults: - for key, value in conf_defaults.iteritems(): + for key, value in conf_defaults.items(): self.conf_set(key, value) if conffile is not None: # read the default conf file when '' is given @@ -313,7 +327,7 @@ Rados object in state %s." % self.state) conffile = None self.conf_read_file(conffile) if conf: - for key, value in conf.iteritems(): + for key, value in conf.items(): self.conf_set(key, value) def shutdown(self): @@ -358,7 +372,7 @@ Rados object in state %s." % self.state) """ self.require_state("configuring", "connected") ret = run_in_thread(self.librados.rados_conf_read_file, - (self.cluster, c_char_p(path))) + (self.cluster, cstr(path))) if (ret != 0): raise make_ex(ret, "error calling conf_read_file") @@ -372,7 +386,7 @@ Rados object in state %s." % self.state) return # create instances of arrays of c_char_p's, both len(args) long # cretargs will always be a subset of cargs (perhaps identical) - cargs = (c_char_p * len(args))(*args) + cargs = (c_char_p * len(args))(*map(cstr, args)) cretargs = (c_char_p * len(args))() ret = run_in_thread(self.librados.rados_conf_parse_argv_remainder, (self.cluster, len(args), cargs, cretargs)) @@ -395,7 +409,7 @@ Rados object in state %s." % self.state) if not var: return ret = run_in_thread(self.librados.rados_conf_parse_env, - (self.cluster, c_char_p(var))) + (self.cluster, cstr(var))) if (ret != 0): raise make_ex(ret, "error calling conf_parse_env") @@ -415,10 +429,10 @@ Rados object in state %s." % self.state) while True: ret_buf = create_string_buffer(length) ret = run_in_thread(self.librados.rados_conf_get, - (self.cluster, c_char_p(option), ret_buf, - c_size_t(length))) + (self.cluster, cstr(option), ret_buf, + c_size_t(length))) if (ret == 0): - return ret_buf.value + return ret_buf.value.decode("utf-8") elif (ret == -errno.ENAMETOOLONG): length = length * 2 elif (ret == -errno.ENOENT): @@ -440,7 +454,7 @@ Rados object in state %s." % self.state) """ self.require_state("configuring", "connected") ret = run_in_thread(self.librados.rados_conf_set, - (self.cluster, c_char_p(option), c_char_p(val))) + (self.cluster, cstr(option), cstr(val))) if (ret != 0): raise make_ex(ret, "error calling conf_set") @@ -463,7 +477,7 @@ Rados object in state %s." % self.state) outstrlen = c_long() ret = run_in_thread(self.librados.rados_ping_monitor, - (self.cluster, c_char_p(mon_id), + (self.cluster, cstr(mon_id), outstrp, byref(outstrlen))) my_outstr = outstrp.contents[:(outstrlen.value)] @@ -528,7 +542,7 @@ Rados object in state %s." % self.state) """ self.require_state("connected") ret = run_in_thread(self.librados.rados_pool_lookup, - (self.cluster, c_char_p(pool_name))) + (self.cluster, cstr(pool_name))) if (ret >= 0): return True elif (ret == -errno.ENOENT): @@ -549,7 +563,7 @@ Rados object in state %s." % self.state) """ self.require_state("connected") ret = run_in_thread(self.librados.rados_pool_lookup, - (self.cluster, c_char_p(pool_name))) + (self.cluster, cstr(pool_name))) if (ret >= 0): return int(ret) elif (ret == -errno.ENOENT): @@ -606,20 +620,20 @@ Rados object in state %s." % self.state) if auid is None: if crush_rule is None: ret = run_in_thread(self.librados.rados_pool_create, - (self.cluster, c_char_p(pool_name))) + (self.cluster, cstr(pool_name))) else: ret = run_in_thread(self.librados. rados_pool_create_with_crush_rule, - (self.cluster, c_char_p(pool_name), + (self.cluster, cstr(pool_name), c_ubyte(crush_rule))) elif crush_rule is None: ret = run_in_thread(self.librados.rados_pool_create_with_auid, - (self.cluster, c_char_p(pool_name), + (self.cluster, cstr(pool_name), c_uint64(auid))) else: ret = run_in_thread(self.librados.rados_pool_create_with_all, - (self.cluster, c_char_p(pool_name), + (self.cluster, cstr(pool_name), c_uint64(auid), c_ubyte(crush_rule))) if ret < 0: raise make_ex(ret, "error creating pool '%s'" % pool_name) @@ -654,7 +668,7 @@ Rados object in state %s." % self.state) """ self.require_state("connected") ret = run_in_thread(self.librados.rados_pool_delete, - (self.cluster, c_char_p(pool_name))) + (self.cluster, cstr(pool_name))) if ret < 0: raise make_ex(ret, "error deleting pool '%s'" % pool_name) @@ -674,7 +688,8 @@ Rados object in state %s." % self.state) size = c_size_t(ret) else: break - return filter(lambda name: name != '', c_names.raw.split('\0')) + + return [name for name in c_names.raw.decode("utf-8").split('\0') if len(name) > 0] def get_fsid(self): """ @@ -709,7 +724,7 @@ Rados object in state %s." % self.state) self.require_state("connected") ioctx = c_void_p() ret = run_in_thread(self.librados.rados_ioctx_create, - (self.cluster, c_char_p(ioctx_name), byref(ioctx))) + (self.cluster, cstr(ioctx_name), byref(ioctx))) if ret < 0: raise make_ex(ret, "error opening pool '%s'" % ioctx_name) return Ioctx(ioctx_name, self.librados, ioctx) @@ -724,11 +739,11 @@ Rados object in state %s." % self.state) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() - cmdarr = (c_char_p * len(cmd))(*cmd) + cmdarr = (c_char_p * len(cmd))(*map(cstr, cmd)) if target: ret = run_in_thread(self.librados.rados_mon_command_target, - (self.cluster, c_char_p(target), cmdarr, + (self.cluster, cstr(target), cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) @@ -761,7 +776,7 @@ Rados object in state %s." % self.state) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() - cmdarr = (c_char_p * len(cmd))(*cmd) + cmdarr = (c_char_p * len(cmd))(*map(cstr, cmd)) ret = run_in_thread(self.librados.rados_osd_command, (self.cluster, osdid, cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), @@ -790,9 +805,9 @@ Rados object in state %s." % self.state) outbuflen = c_long() outsp = pointer(pointer(c_char())) outslen = c_long() - cmdarr = (c_char_p * len(cmd))(*cmd) + cmdarr = (c_char_p * len(cmd))(*map(cstr, cmd)) ret = run_in_thread(self.librados.rados_pg_command, - (self.cluster, c_char_p(pgid), cmdarr, len(cmd), + (self.cluster, cstr(pgid), cmdarr, len(cmd), c_char_p(inbuf), len(inbuf), outbufp, byref(outbuflen), outsp, byref(outslen)), timeout) @@ -826,13 +841,13 @@ Rados object in state %s." % self.state) """ self.require_state("connected") ret = run_in_thread(self.librados.rados_blacklist_add, - (self.cluster, c_char_p(client_address), + (self.cluster, cstr(client_address), c_uint32(expire_seconds))) if ret < 0: raise make_ex(ret, "error blacklisting client '%s'" % client_address) -class OmapIterator(object): +class OmapIterator(Iterator): """Omap iterator""" def __init__(self, ioctx, ctx): self.ioctx = ioctx @@ -842,6 +857,9 @@ class OmapIterator(object): return self def next(self): + return self.__next__() + + def __next__(self): """ Get the next key-value pair in the object :returns: next rados.OmapItem @@ -855,7 +873,7 @@ class OmapIterator(object): raise make_ex(ret, "error iterating over the omap") if key_.value is None: raise StopIteration() - key = ctypes.string_at(key_) + key = key_.value.decode("utf-8") val = None if val_.value is not None: val = ctypes.string_at(val_, len_) @@ -865,7 +883,7 @@ class OmapIterator(object): run_in_thread(self.ioctx.librados.rados_omap_get_end, (self.ctx,)) -class ObjectIterator(object): +class ObjectIterator(Iterator): """rados.Ioctx Object iterator""" def __init__(self, ioctx): self.ioctx = ioctx @@ -880,26 +898,33 @@ class ObjectIterator(object): return self def next(self): + return self.__next__() + + def __next__(self): """ Get the next object name and locator in the pool :raises: StopIteration :returns: next rados.Ioctx Object """ - key = c_char_p() - locator = c_char_p() - nspace = c_char_p() + key_ = c_char_p() + locator_ = c_char_p() + nspace_ = c_char_p() ret = run_in_thread(self.ioctx.librados.rados_nobjects_list_next, - (self.ctx, byref(key), byref(locator), byref(nspace))) + (self.ctx, byref(key_), byref(locator_), byref(nspace_))) if ret < 0: raise StopIteration() - return Object(self.ioctx, key.value, locator.value, nspace.value) + + key = None if key_.value is None else key_.value.decode("utf-8") + locator = None if locator_.value is None else locator_.value.decode("utf-8") + nspace = None if nspace_.value is None else nspace_.value.decode("utf-8") + return Object(self.ioctx, key, locator, nspace) def __del__(self): run_in_thread(self.ioctx.librados.rados_nobjects_list_close, (self.ctx,)) -class XattrIterator(object): +class XattrIterator(Iterator): """Extended attribute iterator""" def __init__(self, ioctx, it, oid): self.ioctx = ioctx @@ -910,6 +935,9 @@ class XattrIterator(object): return self def next(self): + return self.__next__() + + def __next__(self): """ Get the next xattr on the object @@ -926,7 +954,7 @@ class XattrIterator(object): in '%s'" % self.oid) if name_.value is None: raise StopIteration() - name = ctypes.string_at(name_) + name = ctypes.string_at(name_).decode("utf-8") val = ctypes.string_at(val_, len_) return (name, val) @@ -934,7 +962,7 @@ in '%s'" % self.oid) run_in_thread(self.ioctx.librados.rados_getxattrs_end, (self.it,)) -class SnapIterator(object): +class SnapIterator(Iterator): """Snapshot iterator""" def __init__(self, ioctx): self.ioctx = ioctx @@ -958,6 +986,9 @@ ioctx '%s'" % self.ioctx.name) return self def next(self): + return self.__next__() + + def __next__(self): """ Get the next Snapshot @@ -979,7 +1010,7 @@ ioctx '%s'" % self.ioctx.name) elif (ret != -errno.ERANGE): raise make_ex(ret, "rados_snap_get_name error") name_len = name_len * 2 - snap = Snap(self.ioctx, name.value, snap_id) + snap = Snap(self.ioctx, name.value.decode("utf-8"), snap_id) self.cur_snap = self.cur_snap + 1 return snap @@ -1244,7 +1275,7 @@ class Ioctx(object): """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_write, - (self.io, c_char_p(object_name), + (self.io, cstr(object_name), completion.rados_comp, c_char_p(to_write), c_size_t(len(to_write)), c_uint64(offset))) if ret < 0: @@ -1276,7 +1307,7 @@ class Ioctx(object): """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_write_full, - (self.io, c_char_p(object_name), + (self.io, cstr(object_name), completion.rados_comp, c_char_p(to_write), c_size_t(len(to_write)))) if ret < 0: @@ -1307,7 +1338,7 @@ class Ioctx(object): """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_append, - (self.io, c_char_p(object_name), + (self.io, cstr(object_name), completion.rados_comp, c_char_p(to_append), c_size_t(len(to_append)))) if ret < 0: @@ -1354,7 +1385,7 @@ class Ioctx(object): completion = self.__get_completion(oncomplete_, None) ret = run_in_thread(self.librados.rados_aio_read, - (self.io, c_char_p(object_name), + (self.io, cstr(object_name), completion.rados_comp, buf, c_size_t(length), c_uint64(offset))) if ret < 0: @@ -1379,7 +1410,7 @@ class Ioctx(object): """ completion = self.__get_completion(oncomplete, onsafe) ret = run_in_thread(self.librados.rados_aio_remove, - (self.io, c_char_p(object_name), + (self.io, cstr(object_name), completion.rados_comp)) if ret < 0: raise make_ex(ret, "error removing %s" % object_name) @@ -1428,7 +1459,7 @@ class Ioctx(object): """ self.require_ioctx_open() run_in_thread(self.librados.rados_ioctx_locator_set_key, - (self.io, c_char_p(loc_key))) + (self.io, cstr(loc_key))) self.locator_key = loc_key def get_locator_key(self): @@ -1459,7 +1490,7 @@ class Ioctx(object): if nspace is None: nspace = "" run_in_thread(self.librados.rados_ioctx_set_namespace, - (self.io, c_char_p(nspace))) + (self.io, cstr(nspace))) self.nspace = nspace def get_namespace(self): @@ -1485,7 +1516,7 @@ class Ioctx(object): self.state = "closed" - @requires(('key', str), ('data', str)) + @requires(('key', str), ('data', bytes)) def write(self, key, data, offset=0): """ Write data to an object synchronously @@ -1493,7 +1524,7 @@ class Ioctx(object): :param key: name of the object :type key: str :param data: data to write - :type data: str + :type data: bytes :param offset: byte offset in the object to begin writing at :type offset: int @@ -1504,7 +1535,7 @@ class Ioctx(object): self.require_ioctx_open() length = len(data) ret = run_in_thread(self.librados.rados_write, - (self.io, c_char_p(key), c_char_p(data), + (self.io, cstr(key), c_char_p(data), c_size_t(length), c_uint64(offset))) if ret == 0: return ret @@ -1515,7 +1546,7 @@ class Ioctx(object): raise LogicError("Ioctx.write(%s): rados_write \ returned %d, but should return zero on success." % (self.name, ret)) - @requires(('key', str), ('data', str)) + @requires(('key', str), ('data', bytes)) def write_full(self, key, data): """ Write an entire object synchronously. @@ -1526,7 +1557,7 @@ returned %d, but should return zero on success." % (self.name, ret)) :param key: name of the object :type key: str :param data: data to write - :type data: str + :type data: bytes :raises: :class:`TypeError` :raises: :class:`Error` @@ -1535,7 +1566,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() length = len(data) ret = run_in_thread(self.librados.rados_write_full, - (self.io, c_char_p(key), c_char_p(data), + (self.io, cstr(key), c_char_p(data), c_size_t(length))) if ret == 0: return ret @@ -1546,7 +1577,7 @@ returned %d, but should return zero on success." % (self.name, ret)) raise LogicError("Ioctx.write_full(%s): rados_write_full \ returned %d, but should return zero on success." % (self.name, ret)) - @requires(('key', str), ('data', str)) + @requires(('key', str), ('data', bytes)) def append(self, key, data): """ Append data to an object synchronously @@ -1554,7 +1585,7 @@ returned %d, but should return zero on success." % (self.name, ret)) :param key: name of the object :type key: str :param data: data to write - :type data: str + :type data: bytes :raises: :class:`TypeError` :raises: :class:`LogicError` @@ -1563,7 +1594,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() length = len(data) ret = run_in_thread(self.librados.rados_append, - (self.io, c_char_p(key), c_char_p(data), + (self.io, cstr(key), c_char_p(data), c_size_t(length))) if ret == 0: return ret @@ -1593,7 +1624,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() ret_buf = create_string_buffer(length) ret = run_in_thread(self.librados.rados_read, - (self.io, c_char_p(key), ret_buf, c_size_t(length), + (self.io, cstr(key), ret_buf, c_size_t(length), c_uint64(offset))) if ret < 0: raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key)) @@ -1665,7 +1696,7 @@ returned %d, but should return zero on success." % (self.name, ret)) """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_remove, - (self.io, c_char_p(key))) + (self.io, cstr(key))) if ret < 0: raise make_ex(ret, "Failed to remove '%s'" % key) return True @@ -1690,7 +1721,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() ret = run_in_thread(self.librados.rados_trunc, - (self.io, c_char_p(key), c_uint64(size))) + (self.io, cstr(key), c_uint64(size))) if ret < 0: raise make_ex(ret, "Ioctx.trunc(%s): failed to truncate %s" % (self.name, key)) return ret @@ -1712,7 +1743,7 @@ returned %d, but should return zero on success." % (self.name, ret)) pmtime = c_uint64() ret = run_in_thread(self.librados.rados_stat, - (self.io, c_char_p(key), pointer(psize), + (self.io, cstr(key), pointer(psize), pointer(pmtime))) if ret < 0: raise make_ex(ret, "Failed to stat %r" % key) @@ -1737,7 +1768,7 @@ returned %d, but should return zero on success." % (self.name, ret)) while ret_length < 4096 * 1024 * 1024: ret_buf = create_string_buffer(ret_length) ret = run_in_thread(self.librados.rados_getxattr, - (self.io, c_char_p(key), c_char_p(xattr_name), + (self.io, cstr(key), cstr(xattr_name), ret_buf, c_size_t(ret_length))) if (ret == -errno.ERANGE): ret_length *= 2 @@ -1753,7 +1784,7 @@ returned %d, but should return zero on success." % (self.name, ret)) Start iterating over xattrs on an object. :param oid: the name of the object to get xattrs from - :type key: str + :type oid: str :raises: :class:`TypeError` :raises: :class:`Error` @@ -1762,12 +1793,12 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() it = c_void_p(0) ret = run_in_thread(self.librados.rados_getxattrs, - (self.io, oid, byref(it))) + (self.io, cstr(oid), byref(it))) if ret != 0: raise make_ex(ret, "Failed to get rados xattrs for object %r" % oid) return XattrIterator(self, it, oid) - @requires(('key', str), ('xattr_name', str), ('xattr_value', str)) + @requires(('key', str), ('xattr_name', str), ('xattr_value', bytes)) def set_xattr(self, key, xattr_name, xattr_value): """ Set an extended attribute on an object. @@ -1777,7 +1808,7 @@ returned %d, but should return zero on success." % (self.name, ret)) :param xattr_name: which extended attribute to set :type xattr_name: str :param xattr_value: the value of the extended attribute - :type xattr_value: str + :type xattr_value: bytes :raises: :class:`TypeError` :raises: :class:`Error` @@ -1785,7 +1816,7 @@ returned %d, but should return zero on success." % (self.name, ret)) """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_setxattr, - (self.io, c_char_p(key), c_char_p(xattr_name), + (self.io, cstr(key), cstr(xattr_name), c_char_p(xattr_value), c_size_t(len(xattr_value)))) if ret < 0: raise make_ex(ret, "Failed to set xattr %r" % xattr_name) @@ -1807,7 +1838,7 @@ returned %d, but should return zero on success." % (self.name, ret)) """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_rmxattr, - (self.io, c_char_p(key), c_char_p(xattr_name))) + (self.io, cstr(key), cstr(xattr_name))) if ret < 0: raise make_ex(ret, "Failed to delete key %r xattr %r" % (key, xattr_name)) @@ -1844,7 +1875,7 @@ returned %d, but should return zero on success." % (self.name, ret)) """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_ioctx_snap_create, - (self.io, c_char_p(snap_name))) + (self.io, cstr(snap_name))) if (ret != 0): raise make_ex(ret, "Failed to create snap %s" % snap_name) @@ -1861,7 +1892,7 @@ returned %d, but should return zero on success." % (self.name, ret)) """ self.require_ioctx_open() ret = run_in_thread(self.librados.rados_ioctx_snap_remove, - (self.io, c_char_p(snap_name))) + (self.io, cstr(snap_name))) if (ret != 0): raise make_ex(ret, "Failed to remove snap %s" % snap_name) @@ -1880,7 +1911,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() snap_id = c_uint64() ret = run_in_thread(self.librados.rados_ioctx_snap_lookup, - (self.io, c_char_p(snap_name), byref(snap_id))) + (self.io, cstr(snap_name), byref(snap_id))) if (ret != 0): raise make_ex(ret, "Failed to lookup snap %s" % snap_name) return Snap(self, snap_name, snap_id) @@ -1945,7 +1976,7 @@ returned %d, but should return zero on success." % (self.name, ret)) key_num = len(keys) key_array_type = c_char_p*key_num key_array = key_array_type() - key_array[:] = keys + key_array[:] = [cstr(key) for key in keys] value_array_type = c_char_p*key_num value_array = value_array_type() @@ -1974,7 +2005,7 @@ returned %d, but should return zero on success." % (self.name, ret)) :type flags: int """ run_in_thread(self.librados.rados_write_op_operate, - (c_void_p(write_op), self.io, c_char_p(oid), + (c_void_p(write_op), self.io, cstr(oid), c_long(mtime), c_int(flags),)) @requires(('read_op', int), ('oid', str), ('flag', opt(int))) @@ -1989,7 +2020,7 @@ returned %d, but should return zero on success." % (self.name, ret)) :type flag: int """ run_in_thread(self.librados.rados_read_op_operate, - (c_void_p(read_op), self.io, c_char_p(oid), c_int(flag),)) + (c_void_p(read_op), self.io, cstr(oid), c_int(flag),)) @requires(('read_op', int), ('start_after', str), ('filter_prefix', str), ('max_return', int)) def get_omap_vals(self, read_op, start_after, filter_prefix, max_return): @@ -2008,8 +2039,8 @@ returned %d, but should return zero on success." % (self.name, ret)) prval = c_int() iter_addr = c_void_p() run_in_thread(self.librados.rados_read_op_omap_get_vals, - (c_void_p(read_op), c_char_p(start_after), - c_char_p(filter_prefix), c_int(max_return), + (c_void_p(read_op), cstr(start_after), + cstr(filter_prefix), c_int(max_return), byref(iter_addr), pointer(prval))) return OmapIterator(self, iter_addr), prval.value @@ -2028,7 +2059,7 @@ returned %d, but should return zero on success." % (self.name, ret)) prval = c_int() iter_addr = c_void_p() run_in_thread(self.librados.rados_read_op_omap_get_keys, - (c_void_p(read_op), c_char_p(start_after), + (c_void_p(read_op), cstr(start_after), c_int(max_return), byref(iter_addr), pointer(prval))) return OmapIterator(self, iter_addr), prval.value @@ -2047,7 +2078,7 @@ returned %d, but should return zero on success." % (self.name, ret)) key_num = len(keys) key_array_type = c_char_p*key_num key_array = key_array_type() - key_array[:] = keys + key_array[:] = [cstr(key) for key in keys] run_in_thread(self.librados.rados_read_op_omap_get_vals_by_keys, (c_void_p(read_op), byref(key_array), c_int(key_num), byref(iter_addr), pointer(prval))) @@ -2065,7 +2096,7 @@ returned %d, but should return zero on success." % (self.name, ret)) key_num = len(keys) key_array_type = c_char_p*key_num key_array = key_array_type() - key_array[:] = keys + key_array[:] = [cstr(key) for key in keys] run_in_thread(self.librados.rados_write_op_omap_rm_keys, (c_void_p(write_op), byref(key_array), c_int(key_num))) @@ -2105,8 +2136,8 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() ret = run_in_thread(self.librados.rados_lock_exclusive, - (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie), - c_char_p(desc), + (self.io, cstr(key), cstr(name), cstr(cookie), + cstr(desc), timeval(duration, None) if duration is None else None, c_uint8(flags))) if ret < 0: @@ -2140,8 +2171,8 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() ret = run_in_thread(self.librados.rados_lock_shared, - (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie), - c_char_p(tag), c_char_p(desc), + (self.io, cstr(key), cstr(name), cstr(cookie), + cstr(tag), cstr(desc), timeval(duration, None) if duration is None else None, c_uint8(flags))) if ret < 0: @@ -2166,7 +2197,7 @@ returned %d, but should return zero on success." % (self.name, ret)) self.require_ioctx_open() ret = run_in_thread(self.librados.rados_unlock, - (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie))) + (self.io, cstr(key), cstr(name), cstr(cookie))) if ret < 0: raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key)) diff --git a/src/pybind/rbd.py b/src/pybind/rbd.py index b570a00ebd6..b04e8453f25 100644 --- a/src/pybind/rbd.py +++ b/src/pybind/rbd.py @@ -15,6 +15,7 @@ to interact correctly with librbd. If unicode is passed to these methods, a :class:`TypeError` will be raised. """ # Copyright 2011 Josh Durgin +from collections import Iterable from ctypes import CDLL, c_char, c_char_p, c_size_t, c_void_p, c_int, \ create_string_buffer, byref, Structure, c_uint64, c_int64, c_uint8, \ CFUNCTYPE @@ -194,6 +195,19 @@ def load_librbd(): raise EnvironmentError("Unable to load librbd: %s" % e) +def cstr(val, encoding="utf-8"): + """ + Create a C-style string from a Python string + + :param str val: Python string + :rtype: c_char_p + """ + if val is None: + return c_char_p(None) + + return c_char_p(val.encode(encoding)) + + class RBD(object): """ This class wraps librbd CRUD functions. @@ -250,7 +264,7 @@ class RBD(object): if features != 0 or stripe_unit != 0 or stripe_count != 0: raise InvalidArgument('format 1 images do not support feature' ' masks or non-default striping') - ret = self.librbd.rbd_create(ioctx.io, c_char_p(name), + ret = self.librbd.rbd_create(ioctx.io, cstr(name), c_uint64(size), byref(c_int(order))) else: @@ -262,14 +276,14 @@ class RBD(object): raise FunctionNotSupported('installed version of librbd does' ' not support stripe unit or count') if has_create3: - ret = self.librbd.rbd_create3(ioctx.io, c_char_p(name), + ret = self.librbd.rbd_create3(ioctx.io, cstr(name), c_uint64(size), c_uint64(features), byref(c_int(order)), c_uint64(stripe_unit), c_uint64(stripe_count)) else: - ret = self.librbd.rbd_create2(ioctx.io, c_char_p(name), + ret = self.librbd.rbd_create2(ioctx.io, cstr(name), c_uint64(size), c_uint64(features), byref(c_int(order))) @@ -308,9 +322,9 @@ class RBD(object): if not isinstance(c_name, str): raise TypeError('child name must be a string') - ret = self.librbd.rbd_clone(p_ioctx.io, c_char_p(p_name), - c_char_p(p_snapname), - c_ioctx.io, c_char_p(c_name), + ret = self.librbd.rbd_clone(p_ioctx.io, cstr(p_name), + cstr(p_snapname), + c_ioctx.io, cstr(c_name), c_uint64(features), byref(c_int(order))) if ret < 0: @@ -332,7 +346,8 @@ class RBD(object): break elif ret != -errno.ERANGE: raise make_ex(ret, 'error listing images') - return filter(lambda name: name != '', c_names.raw.split('\0')) + + return [name for name in c_names.raw.decode("utf-8").split('\0') if len(name) > 0] def remove(self, ioctx, name): """ @@ -353,7 +368,7 @@ class RBD(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_remove(ioctx.io, c_char_p(name)) + ret = self.librbd.rbd_remove(ioctx.io, cstr(name)) if ret != 0: raise make_ex(ret, 'error removing image') @@ -371,7 +386,7 @@ class RBD(object): """ if not isinstance(src, str) or not isinstance(dest, str): raise TypeError('src and dest must be strings') - ret = self.librbd.rbd_rename(ioctx.io, c_char_p(src), c_char_p(dest)) + ret = self.librbd.rbd_rename(ioctx.io, cstr(src), cstr(dest)) if ret != 0: raise make_ex(ret, 'error renaming image') @@ -420,12 +435,12 @@ class Image(object): if not hasattr(self.librbd, 'rbd_open_read_only'): raise FunctionNotSupported('installed version of librbd does ' 'not support open in read-only mode') - ret = self.librbd.rbd_open_read_only(ioctx.io, c_char_p(name), + ret = self.librbd.rbd_open_read_only(ioctx.io, cstr(name), byref(self.image), - c_char_p(snapshot)) + cstr(snapshot)) else: - ret = self.librbd.rbd_open(ioctx.io, c_char_p(name), - byref(self.image), c_char_p(snapshot)) + ret = self.librbd.rbd_open(ioctx.io, cstr(name), + byref(self.image), cstr(snapshot)) if ret != 0: raise make_ex(ret, 'error opening image %s at snapshot %s' % (name, snapshot)) self.closed = False @@ -644,7 +659,7 @@ class Image(object): """ if not isinstance(dest_name, str): raise TypeError('dest_name must be a string') - ret = self.librbd.rbd_copy(self.image, dest_ioctx.io, c_char_p(dest_name)) + ret = self.librbd.rbd_copy(self.image, dest_ioctx.io, cstr(dest_name)) if ret < 0: raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name)) @@ -666,7 +681,7 @@ class Image(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_create(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_create(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error creating snapshot %s from %s' % (name, self.name)) @@ -680,7 +695,7 @@ class Image(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_remove(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_remove(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error removing snapshot %s from %s' % (name, self.name)) @@ -696,7 +711,7 @@ class Image(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_rollback(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_rollback(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error rolling back image %s to snapshot %s' % (self.name, name)) @@ -711,7 +726,7 @@ class Image(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_protect(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_protect(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error protecting snapshot %s@%s' % (self.name, name)) @@ -726,7 +741,7 @@ class Image(object): """ if not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_unprotect(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_unprotect(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error unprotecting snapshot %s@%s' % (self.name, name)) @@ -742,7 +757,7 @@ class Image(object): if not isinstance(name, str): raise TypeError('name must be a string') is_protected = c_int() - ret = self.librbd.rbd_snap_is_protected(self.image, c_char_p(name), + ret = self.librbd.rbd_snap_is_protected(self.image, cstr(name), byref(is_protected)) if ret != 0: raise make_ex(ret, 'error checking if snapshot %s@%s is protected' % (self.name, name)) @@ -759,7 +774,7 @@ class Image(object): """ if name is not None and not isinstance(name, str): raise TypeError('name must be a string') - ret = self.librbd.rbd_snap_set(self.image, c_char_p(name)) + ret = self.librbd.rbd_snap_set(self.image, cstr(name)) if ret != 0: raise make_ex(ret, 'error setting image %s to snapshot %s' % (self.name, name)) @@ -838,7 +853,7 @@ class Image(object): cb_holder = DiffIterateCB(iterate_cb) cb = RBD_DIFF_CB(cb_holder.callback) ret = self.librbd.rbd_diff_iterate2(self.image, - c_char_p(from_snapshot), + cstr(from_snapshot), c_uint64(offset), c_uint64(length), c_uint8(include_parent), @@ -855,7 +870,7 @@ class Image(object): part of the write would fall outside the image. :param data: the data to be written - :type data: str + :type data: bytes :param offset: where to start writing data :type offset: int :param fadvise_flags: fadvise flags for this write @@ -864,8 +879,8 @@ class Image(object): :raises: :class:`IncompleteWriteError`, :class:`LogicError`, :class:`InvalidArgument`, :class:`IOError` """ - if not isinstance(data, str): - raise TypeError('data must be a string') + if not isinstance(data, bytes): + raise TypeError('data must be a byte string') length = len(data) if fadvise_flags == 0: @@ -967,7 +982,7 @@ written." % (self.name, ret, length)) return [] pools = c_pools.raw[:pools_size.value - 1].split('\0') images = c_images.raw[:images_size.value - 1].split('\0') - return zip(pools, images) + return list(zip(pools, images)) def list_lockers(self): """ @@ -1010,13 +1025,13 @@ written." % (self.name, ret, length)) raise make_ex(ret, 'error listing images') if ret == 0: return [] - clients = c_clients.raw[:clients_size.value - 1].split('\0') - cookies = c_cookies.raw[:cookies_size.value - 1].split('\0') - addrs = c_addrs.raw[:addrs_size.value - 1].split('\0') + clients = [client.decode("utf-8") for client in c_clients.raw[:clients_size.value - 1].split(b'\0')] + cookies = [cookie.decode("utf-8") for cookie in c_cookies.raw[:cookies_size.value - 1].split(b'\0')] + addrs = [addr.decode("utf-8") for addr in c_addrs.raw[:addrs_size.value - 1].split(b'\0')] return { - 'tag' : c_tag.value, + 'tag' : c_tag.value.decode("utf-8"), 'exclusive' : exclusive.value == 1, - 'lockers' : zip(clients, cookies, addrs), + 'lockers' : list(zip(clients, cookies, addrs)), } def lock_exclusive(self, cookie): @@ -1028,7 +1043,7 @@ written." % (self.name, ret, length)) """ if not isinstance(cookie, str): raise TypeError('cookie must be a string') - ret = self.librbd.rbd_lock_exclusive(self.image, c_char_p(cookie)) + ret = self.librbd.rbd_lock_exclusive(self.image, cstr(cookie)) if ret < 0: raise make_ex(ret, 'error acquiring exclusive lock on image') @@ -1044,8 +1059,8 @@ written." % (self.name, ret, length)) raise TypeError('cookie must be a string') if not isinstance(tag, str): raise TypeError('tag must be a string') - ret = self.librbd.rbd_lock_shared(self.image, c_char_p(cookie), - c_char_p(tag)) + ret = self.librbd.rbd_lock_shared(self.image, cstr(cookie), + cstr(tag)) if ret < 0: raise make_ex(ret, 'error acquiring shared lock on image') @@ -1055,7 +1070,7 @@ written." % (self.name, ret, length)) """ if not isinstance(cookie, str): raise TypeError('cookie must be a string') - ret = self.librbd.rbd_unlock(self.image, c_char_p(cookie)) + ret = self.librbd.rbd_unlock(self.image, cstr(cookie)) if ret < 0: raise make_ex(ret, 'error unlocking image') @@ -1067,8 +1082,8 @@ written." % (self.name, ret, length)) raise TypeError('client must be a string') if not isinstance(cookie, str): raise TypeError('cookie must be a string') - ret = self.librbd.rbd_break_lock(self.image, c_char_p(client), - c_char_p(cookie)) + ret = self.librbd.rbd_break_lock(self.image, cstr(client), + cstr(cookie)) if ret < 0: raise make_ex(ret, 'error unlocking image') @@ -1082,7 +1097,7 @@ class DiffIterateCB(object): return 0 -class SnapIterator(object): +class SnapIterator(Iterable): """ Iterator over snapshot info for an image. @@ -1110,11 +1125,11 @@ class SnapIterator(object): raise make_ex(ret, 'error listing snapshots for image %s' % (image.name,)) def __iter__(self): - for i in xrange(self.num_snaps): + for i in range(self.num_snaps): yield { 'id' : self.snaps[i].id, 'size' : self.snaps[i].size, - 'name' : self.snaps[i].name, + 'name' : self.snaps[i].name.decode("utf-8"), } def __del__(self): diff --git a/src/test/pybind/test_rados.py b/src/test/pybind/test_rados.py index d05c25bd864..11457a7bc3b 100644 --- a/src/test/pybind/test_rados.py +++ b/src/test/pybind/test_rados.py @@ -1,3 +1,4 @@ +from __future__ import print_function from nose.tools import eq_ as eq, ok_ as ok, assert_raises from rados import (Rados, Error, RadosStateError, Object, ObjectExists, ObjectNotFound, ObjectBusy, requires, opt, @@ -13,16 +14,6 @@ def test_rados_init_error(): assert_raises(Error, Rados, conffile='', name='invalid') assert_raises(Error, Rados, conffile='', name='bad.invalid') -def test_rados_init_type_error(): - assert_raises(TypeError, Rados, rados_id=u'admin') - assert_raises(TypeError, Rados, rados_id=u'') - assert_raises(TypeError, Rados, name=u'client.admin') - assert_raises(TypeError, Rados, name=u'') - assert_raises(TypeError, Rados, conffile=u'blah') - assert_raises(TypeError, Rados, conffile=u'') - assert_raises(TypeError, Rados, clusternaem=u'blah') - assert_raises(TypeError, Rados, clustername=u'') - def test_rados_init(): with Rados(conffile='', rados_id='admin'): pass @@ -91,9 +82,9 @@ class TestRadosStateError(object): assert_raises(RadosStateError, rados.list_pools) assert_raises(RadosStateError, rados.get_fsid) assert_raises(RadosStateError, rados.open_ioctx, 'foo') - assert_raises(RadosStateError, rados.mon_command, '', '') - assert_raises(RadosStateError, rados.osd_command, 0, '', '') - assert_raises(RadosStateError, rados.pg_command, '', '', '') + assert_raises(RadosStateError, rados.mon_command, '', b'') + assert_raises(RadosStateError, rados.osd_command, 0, '', b'') + assert_raises(RadosStateError, rados.pg_command, '', '', b'') assert_raises(RadosStateError, rados.wait_for_latest_osdmap) assert_raises(RadosStateError, rados.blacklist_add, '127.0.0.1/123', 0) @@ -179,12 +170,12 @@ class TestRados(object): tier_pool_id = self.rados.pool_lookup('foo-cache') cmd = {"prefix":"osd tier add", "pool":"foo", "tierpool":"foo-cache", "force_nonempty":""} - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, 0) try: cmd = {"prefix":"osd tier cache-mode", "pool":"foo-cache", "tierpool":"foo-cache", "mode":"readonly"} - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, 0) eq(self.rados.wait_for_latest_osdmap(), 0) @@ -193,7 +184,7 @@ class TestRados(object): eq(pool_id, self.rados.get_pool_base_tier(tier_pool_id)) finally: cmd = {"prefix":"osd tier remove", "pool":"foo", "tierpool":"foo-cache"} - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, 0) finally: self.rados.delete_pool('foo-cache') @@ -218,7 +209,7 @@ class TestIoctx(object): def tearDown(self): cmd = {"prefix":"osd unset", "key":"noup"} - self.rados.mon_command(json.dumps(cmd), '') + self.rados.mon_command(json.dumps(cmd), b'') self.ioctx.close() self.rados.delete_pool('test_pool') self.rados.shutdown() @@ -228,29 +219,29 @@ class TestIoctx(object): self.ioctx.change_auid(ADMIN_AUID) def test_write(self): - self.ioctx.write('abc', 'abc') - eq(self.ioctx.read('abc'), 'abc') + self.ioctx.write('abc', b'abc') + eq(self.ioctx.read('abc'), b'abc') def test_write_full(self): - self.ioctx.write('abc', 'abc') - eq(self.ioctx.read('abc'), 'abc') - self.ioctx.write_full('abc', 'd') - eq(self.ioctx.read('abc'), 'd') + self.ioctx.write('abc', b'abc') + eq(self.ioctx.read('abc'), b'abc') + self.ioctx.write_full('abc', b'd') + eq(self.ioctx.read('abc'), b'd') def test_append(self): - self.ioctx.write('abc', 'a') - self.ioctx.append('abc', 'b') - self.ioctx.append('abc', 'c') - eq(self.ioctx.read('abc'), 'abc') + self.ioctx.write('abc', b'a') + self.ioctx.append('abc', b'b') + self.ioctx.append('abc', b'c') + eq(self.ioctx.read('abc'), b'abc') def test_write_zeros(self): - self.ioctx.write('abc', 'a\0b\0c') - eq(self.ioctx.read('abc'), 'a\0b\0c') + self.ioctx.write('abc', b'a\0b\0c') + eq(self.ioctx.read('abc'), b'a\0b\0c') def test_trunc(self): - self.ioctx.write('abc', 'abc') + self.ioctx.write('abc', b'abc') self.ioctx.trunc('abc', 2) - eq(self.ioctx.read('abc'), 'ab') + eq(self.ioctx.read('abc'), b'ab') size = self.ioctx.stat('abc')[0] eq(size, 2) @@ -258,24 +249,24 @@ class TestIoctx(object): eq(list(self.ioctx.list_objects()), []) def test_list_objects(self): - self.ioctx.write('a', '') - self.ioctx.write('b', 'foo') - self.ioctx.write_full('c', 'bar') - self.ioctx.append('d', 'jazz') + self.ioctx.write('a', b'') + self.ioctx.write('b', b'foo') + self.ioctx.write_full('c', b'bar') + self.ioctx.append('d', b'jazz') object_names = [obj.key for obj in self.ioctx.list_objects()] eq(sorted(object_names), ['a', 'b', 'c', 'd']) def test_list_ns_objects(self): - self.ioctx.write('a', '') - self.ioctx.write('b', 'foo') - self.ioctx.write_full('c', 'bar') - self.ioctx.append('d', 'jazz') + self.ioctx.write('a', b'') + self.ioctx.write('b', b'foo') + self.ioctx.write_full('c', b'bar') + self.ioctx.append('d', b'jazz') self.ioctx.set_namespace("ns1") - self.ioctx.write('ns1-a', '') - self.ioctx.write('ns1-b', 'foo') - self.ioctx.write_full('ns1-c', 'bar') - self.ioctx.append('ns1-d', 'jazz') - self.ioctx.append('d', 'jazz') + self.ioctx.write('ns1-a', b'') + self.ioctx.write('ns1-b', b'foo') + self.ioctx.write_full('ns1-c', b'bar') + self.ioctx.append('ns1-d', b'jazz') + self.ioctx.append('d', b'jazz') self.ioctx.set_namespace(LIBRADOS_ALL_NSPACES) object_names = [(obj.nspace, obj.key) for obj in self.ioctx.list_objects()] eq(sorted(object_names), [('', 'a'), ('','b'), ('','c'), ('','d'),\ @@ -283,9 +274,9 @@ class TestIoctx(object): ('ns1', 'ns1-c'), ('ns1', 'ns1-d')]) def test_xattrs(self): - xattrs = dict(a='1', b='2', c='3', d='a\0b', e='\0') - self.ioctx.write('abc', '') - for key, value in xattrs.iteritems(): + xattrs = dict(a=b'1', b=b'2', c=b'3', d=b'a\0b', e=b'\0') + self.ioctx.write('abc', b'') + for key, value in xattrs.items(): self.ioctx.set_xattr('abc', key, value) eq(self.ioctx.get_xattr('abc', key), value) stored_xattrs = {} @@ -294,10 +285,10 @@ class TestIoctx(object): eq(stored_xattrs, xattrs) def test_obj_xattrs(self): - xattrs = dict(a='1', b='2', c='3', d='a\0b', e='\0') - self.ioctx.write('abc', '') + xattrs = dict(a=b'1', b=b'2', c=b'3', d=b'a\0b', e=b'\0') + self.ioctx.write('abc', b'') obj = list(self.ioctx.list_objects())[0] - for key, value in xattrs.iteritems(): + for key, value in xattrs.items(): obj.set_xattr(key, value) eq(obj.get_xattr(key), value) stored_xattrs = {} @@ -339,7 +330,7 @@ class TestIoctx(object): def test_set_omap(self): keys = ("1", "2", "3", "4") - values = ("aaa", "bbb", "ccc", "\x04\x04\x04\x04") + values = (b"aaa", b"bbb", b"ccc", b"\x04\x04\x04\x04") with WriteOpCtx(self.ioctx) as write_op: self.ioctx.set_omap(write_op, keys, values) self.ioctx.operate_write_op(write_op, "hw") @@ -347,22 +338,22 @@ class TestIoctx(object): iter, ret = self.ioctx.get_omap_vals(read_op, "", "", 4) self.ioctx.operate_read_op(read_op, "hw") iter.next() - eq(list(iter), [("2", "bbb"), ("3", "ccc"), ("4", "\x04\x04\x04\x04")]) + eq(list(iter), [("2", b"bbb"), ("3", b"ccc"), ("4", b"\x04\x04\x04\x04")]) def test_get_omap_vals_by_keys(self): keys = ("1", "2", "3", "4") - values = ("aaa", "bbb", "ccc", "\x04\x04\x04\x04") + values = (b"aaa", b"bbb", b"ccc", b"\x04\x04\x04\x04") with WriteOpCtx(self.ioctx) as write_op: self.ioctx.set_omap(write_op, keys, values) self.ioctx.operate_write_op(write_op, "hw") with ReadOpCtx(self.ioctx) as read_op: iter, ret = self.ioctx.get_omap_vals_by_keys(read_op,("3","4",)) self.ioctx.operate_read_op(read_op, "hw") - eq(list(iter), [("3", "ccc"), ("4", "\x04\x04\x04\x04")]) + eq(list(iter), [("3", b"ccc"), ("4", b"\x04\x04\x04\x04")]) def test_get_omap_keys(self): keys = ("1", "2", "3") - values = ("aaa", "bbb", "ccc") + values = (b"aaa", b"bbb", b"ccc") with WriteOpCtx(self.ioctx) as write_op: self.ioctx.set_omap(write_op, keys, values) self.ioctx.operate_write_op(write_op, "hw") @@ -373,7 +364,7 @@ class TestIoctx(object): def test_clear_omap(self): keys = ("1", "2", "3") - values = ("aaa", "bbb", "ccc") + values = (b"aaa", b"bbb", b"ccc") with WriteOpCtx(self.ioctx) as write_op: self.ioctx.set_omap(write_op, keys, values) self.ioctx.operate_write_op(write_op, "hw") @@ -387,17 +378,17 @@ class TestIoctx(object): def test_locator(self): self.ioctx.set_locator_key("bar") - self.ioctx.write('foo', 'contents1') + self.ioctx.write('foo', b'contents1') objects = [i for i in self.ioctx.list_objects()] eq(len(objects), 1) eq(self.ioctx.get_locator_key(), "bar") self.ioctx.set_locator_key("") objects[0].seek(0) - objects[0].write("contents2") + objects[0].write(b"contents2") eq(self.ioctx.get_locator_key(), "") self.ioctx.set_locator_key("bar") contents = self.ioctx.read("foo") - eq(contents, "contents2") + eq(contents, b"contents2") eq(self.ioctx.get_locator_key(), "bar") objects[0].remove() objects = [i for i in self.ioctx.list_objects()] @@ -412,7 +403,7 @@ class TestIoctx(object): count[0] += 1 lock.notify() return 0 - comp = self.ioctx.aio_write("foo", "bar", 0, cb, cb) + comp = self.ioctx.aio_write("foo", b"bar", 0, cb, cb) comp.wait_for_complete() comp.wait_for_safe() with lock: @@ -420,7 +411,7 @@ class TestIoctx(object): lock.wait() eq(comp.get_return_value(), 0) contents = self.ioctx.read("foo") - eq(contents, "bar") + eq(contents, b"bar") [i.remove() for i in self.ioctx.list_objects()] def test_aio_append(self): @@ -431,11 +422,11 @@ class TestIoctx(object): count[0] += 1 lock.notify() return 0 - comp = self.ioctx.aio_write("foo", "bar", 0, cb, cb) - comp2 = self.ioctx.aio_append("foo", "baz", cb, cb) + comp = self.ioctx.aio_write("foo", b"bar", 0, cb, cb) + comp2 = self.ioctx.aio_append("foo", b"baz", cb, cb) comp.wait_for_complete() contents = self.ioctx.read("foo") - eq(contents, "barbaz") + eq(contents, b"barbaz") with lock: while count[0] < 4: lock.wait() @@ -451,8 +442,8 @@ class TestIoctx(object): count[0] += 1 lock.notify() return 0 - self.ioctx.aio_write("foo", "barbaz", 0, cb, cb) - comp = self.ioctx.aio_write_full("foo", "bar", cb, cb) + self.ioctx.aio_write("foo", b"barbaz", 0, cb, cb) + comp = self.ioctx.aio_write_full("foo", b"bar", cb, cb) comp.wait_for_complete() comp.wait_for_safe() with lock: @@ -460,7 +451,7 @@ class TestIoctx(object): lock.wait() eq(comp.get_return_value(), 0) contents = self.ioctx.read("foo") - eq(contents, "bar") + eq(contents, b"bar") [i.remove() for i in self.ioctx.list_objects()] def _take_down_acting_set(self, pool, objectname): @@ -472,14 +463,14 @@ class TestIoctx(object): "object":objectname, "format":"json", } - r, jsonout, _ = self.rados.mon_command(json.dumps(cmd), '') - objmap = json.loads(jsonout) + r, jsonout, _ = self.rados.mon_command(json.dumps(cmd), b'') + objmap = json.loads(jsonout.decode("utf-8")) acting_set = objmap['acting'] cmd = {"prefix":"osd set", "key":"noup"} - r, _, _ = self.rados.mon_command(json.dumps(cmd), '') + r, _, _ = self.rados.mon_command(json.dumps(cmd), b'') eq(r, 0) cmd = {"prefix":"osd down", "ids":[str(i) for i in acting_set]} - r, _, _ = self.rados.mon_command(json.dumps(cmd), '') + r, _, _ = self.rados.mon_command(json.dumps(cmd), b'') eq(r, 0) # wait for OSDs to acknowledge the down @@ -487,7 +478,7 @@ class TestIoctx(object): def _let_osds_back_up(self): cmd = {"prefix":"osd unset", "key":"noup"} - r, _, _ = self.rados.mon_command(json.dumps(cmd), '') + r, _, _ = self.rados.mon_command(json.dumps(cmd), b'') eq(r, 0) def test_aio_read(self): @@ -498,7 +489,7 @@ class TestIoctx(object): with lock: retval[0] = buf lock.notify() - payload = "bar\000frob" + payload = b"bar\000frob" self.ioctx.write("foo", payload) # test1: use wait_for_complete() and wait for cb by @@ -570,7 +561,7 @@ class TestObject(object): self.rados.create_pool('test_pool') assert self.rados.pool_exists('test_pool') self.ioctx = self.rados.open_ioctx('test_pool') - self.ioctx.write('foo', 'bar') + self.ioctx.write('foo', b'bar') self.object = Object(self.ioctx, 'foo') def tearDown(self): @@ -579,21 +570,21 @@ class TestObject(object): self.rados.shutdown() def test_read(self): - eq(self.object.read(3), 'bar') - eq(self.object.read(100), '') + eq(self.object.read(3), b'bar') + eq(self.object.read(100), b'') def test_seek(self): - self.object.write('blah') + self.object.write(b'blah') self.object.seek(0) - eq(self.object.read(4), 'blah') + eq(self.object.read(4), b'blah') self.object.seek(1) - eq(self.object.read(3), 'lah') + eq(self.object.read(3), b'lah') def test_write(self): - self.object.write('barbaz') + self.object.write(b'barbaz') self.object.seek(0) - eq(self.object.read(3), 'bar') - eq(self.object.read(3), 'baz') + eq(self.object.read(3), b'bar') + eq(self.object.read(3), b'baz') class TestCommand(object): @@ -608,53 +599,53 @@ class TestCommand(object): # check for success and some plain output with epoch in it cmd = {"prefix":"mon dump"} - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, 0) assert len(buf) > 0 - assert('epoch' in buf) + assert(b'epoch' in buf) # JSON, and grab current epoch cmd['format'] = 'json' - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, 0) assert len(buf) > 0 - d = json.loads(buf) + d = json.loads(buf.decode("utf-8")) assert('epoch' in d) epoch = d['epoch'] # assume epoch + 1000 does not exist; test for ENOENT cmd['epoch'] = epoch + 1000 - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30) eq(ret, -errno.ENOENT) eq(len(buf), 0) del cmd['epoch'] # send to specific target by name target = d['mons'][0]['name'] - print target - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30, + print(target) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30, target=target) eq(ret, 0) assert len(buf) > 0 - d = json.loads(buf) + d = json.loads(buf.decode("utf-8")) assert('epoch' in d) # and by rank target = d['mons'][0]['rank'] - print target - ret, buf, errs = self.rados.mon_command(json.dumps(cmd), '', timeout=30, + print(target) + ret, buf, errs = self.rados.mon_command(json.dumps(cmd), b'', timeout=30, target=target) eq(ret, 0) assert len(buf) > 0 - d = json.loads(buf) + d = json.loads(buf.decode("utf-8")) assert('epoch' in d) def test_osd_bench(self): cmd = dict(prefix='bench', size=4096, count=8192) - ret, buf, err = self.rados.osd_command(0, json.dumps(cmd), '', + ret, buf, err = self.rados.osd_command(0, json.dumps(cmd), b'', timeout=30) eq(ret, 0) assert len(err) > 0 - out = json.loads(err) + out = json.loads(err.decode("utf-8")) eq(out['blocksize'], cmd['size']) eq(out['bytes_written'], cmd['count']) diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index a98b5dcea9f..1498524ee9b 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -1,10 +1,9 @@ # vim: expandtab smarttab shiftwidth=4 softtabstop=4 import functools import socket -import struct import os +import time -from contextlib import nested from nose import with_setup, SkipTest from nose.tools import eq_ as eq, assert_raises from rados import (Rados, @@ -17,7 +16,6 @@ from rbd import (RBD, Image, ImageNotFound, InvalidArgument, ImageExists, RBD_FEATURE_LAYERING, RBD_FEATURE_STRIPINGV2, RBD_FEATURE_EXCLUSIVE_LOCK) - rados = None ioctx = None features = None @@ -166,7 +164,7 @@ def check_default_params(format, order=None, features=None, stripe_count=None, else: assert_raises(exception, RBD().create, ioctx, image_name, IMG_SIZE) finally: - for k, v in orig_vals.iteritems(): + for k, v in orig_vals.items(): rados.conf_set(k, v) def test_create_defaults(): @@ -240,13 +238,13 @@ def test_open_read_only(): eq(data, read) def test_open_dne(): - for i in xrange(100): + for i in range(100): image_name = get_temp_image_name() assert_raises(ImageNotFound, Image, ioctx, image_name + 'dne') assert_raises(ImageNotFound, Image, ioctx, image_name, 'snap') def test_open_readonly_dne(): - for i in xrange(100): + for i in range(100): image_name = get_temp_image_name() assert_raises(ImageNotFound, Image, ioctx, image_name + 'dne', read_only=True) @@ -301,10 +299,10 @@ class TestImage(object): eq(features | RBD_FEATURE_EXCLUSIVE_LOCK, self.image.features()) def test_invalidate_cache(self): - self.image.write('abc', 0) - eq('abc', self.image.read(0, 3)) + self.image.write(b'abc', 0) + eq(b'abc', self.image.read(0, 3)) self.image.invalidate_cache() - eq('abc', self.image.read(0, 3)) + eq(b'abc', self.image.read(0, 3)) def test_stat(self): info = self.image.stat() @@ -325,13 +323,13 @@ class TestImage(object): def test_read(self): data = self.image.read(0, 20) - eq(data, '\0' * 20) + eq(data, b'\0' * 20) def test_read_with_fadvise_flags(self): data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) - eq(data, '\0' * 20) + eq(data, b'\0' * 20) data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_RANDOM) - eq(data, '\0' * 20) + eq(data, b'\0' * 20) def test_large_write(self): data = rand_data(IMG_SIZE) @@ -339,7 +337,7 @@ class TestImage(object): def test_large_read(self): data = self.image.read(0, IMG_SIZE) - eq(data, '\0' * IMG_SIZE) + eq(data, b'\0' * IMG_SIZE) def test_write_read(self): data = rand_data(256) @@ -374,24 +372,24 @@ class TestImage(object): self.image.remove_snap('snap2') def test_resize_down(self): - new_size = IMG_SIZE / 2 + new_size = IMG_SIZE // 2 data = rand_data(256) - self.image.write(data, IMG_SIZE / 2); + self.image.write(data, IMG_SIZE // 2); self.image.resize(new_size) self.image.resize(IMG_SIZE) - read = self.image.read(IMG_SIZE / 2, 256) - eq('\0' * 256, read) + read = self.image.read(IMG_SIZE // 2, 256) + eq(b'\0' * 256, read) def test_resize_bytes(self): - new_size = IMG_SIZE / 2 - 5 + new_size = IMG_SIZE // 2 - 5 data = rand_data(256) - self.image.write(data, IMG_SIZE / 2 - 10); + self.image.write(data, IMG_SIZE // 2 - 10); self.image.resize(new_size) self.image.resize(IMG_SIZE) - read = self.image.read(IMG_SIZE / 2 - 10, 5) + read = self.image.read(IMG_SIZE // 2 - 10, 5) eq(data[:5], read) - read = self.image.read(IMG_SIZE / 2 - 5, 251) - eq('\0' * 251, read) + read = self.image.read(IMG_SIZE // 2 - 5, 251) + eq(b'\0' * 251, read) def test_copy(self): global ioctx @@ -410,7 +408,7 @@ class TestImage(object): global ioctx self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) @@ -418,22 +416,22 @@ class TestImage(object): at_snapshot = Image(ioctx, image_name, 'snap1') snap_data = at_snapshot.read(0, 256) at_snapshot.close() - eq(snap_data, '\0' * 256) + eq(snap_data, b'\0' * 256) self.image.remove_snap('snap1') def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') - eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) + eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.create_snap('snap2') - eq(['snap1', 'snap2'], map(lambda snap: snap['name'], self.image.list_snaps())) + eq(['snap1', 'snap2'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') - eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) + eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') eq([], list(self.image.list_snaps())) @@ -469,35 +467,35 @@ class TestImage(object): eq(read, data) def test_rollback_to_snap(self): - self.image.write('\0' * 256, 0) + self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_to_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_with_resize(self): read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap('snap1') @@ -521,31 +519,31 @@ class TestImage(object): self.image.remove_snap('snap2') def test_set_snap(self): - self.image.write('\0' * 256, 0) + self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_set_no_snap(self): - self.image.write('\0' * 256, 0) + self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) @@ -554,19 +552,19 @@ class TestImage(object): def test_set_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_many_snaps(self): num_snaps = 200 - for i in xrange(num_snaps): + for i in range(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap['name'])) @@ -574,14 +572,14 @@ class TestImage(object): for i, snap in enumerate(snaps): eq(snap['size'], IMG_SIZE) eq(snap['name'], str(i)) - for i in xrange(num_snaps): + for i in range(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): - self.image.write('\0' * 256, 0) + self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) @@ -594,10 +592,10 @@ class TestImage(object): eq(read, data) def test_set_snap_recreated(self): - self.image.write('\0' * 256, 0) + self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) - eq(read, '\0' * 256) + eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) @@ -633,14 +631,14 @@ class TestImage(object): eq([], self.image.list_lockers()) num_shared = 10 - for i in xrange(num_shared): + for i in range(num_shared): self.image.lock_shared(str(i), 'tag') lockers = self.image.list_lockers() eq('tag', lockers['tag']) assert not lockers['exclusive'] eq(num_shared, len(lockers['lockers'])) cookies = sorted(map(lambda x: x[1], lockers['lockers'])) - for i in xrange(num_shared): + for i in range(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) @@ -680,7 +678,7 @@ class TestClone(object): create_image() self.image = Image(ioctx, image_name) data = rand_data(256) - self.image.write(data, IMG_SIZE / 2) + self.image.write(data, IMG_SIZE // 2) self.image.create_snap('snap1') global features self.image.protect_snap('snap1') @@ -758,52 +756,52 @@ class TestClone(object): eq(clone_info['size'], self.clone.overlap()) def test_resize_stat(self): - self.clone.resize(IMG_SIZE / 2) + self.clone.resize(IMG_SIZE // 2) image_info = self.image.stat() clone_info = self.clone.stat() - eq(clone_info['size'], IMG_SIZE / 2) + eq(clone_info['size'], IMG_SIZE // 2) eq(image_info['size'], IMG_SIZE) - eq(self.clone.overlap(), IMG_SIZE / 2) + eq(self.clone.overlap(), IMG_SIZE // 2) self.clone.resize(IMG_SIZE * 2) image_info = self.image.stat() clone_info = self.clone.stat() eq(clone_info['size'], IMG_SIZE * 2) eq(image_info['size'], IMG_SIZE) - eq(self.clone.overlap(), IMG_SIZE / 2) + eq(self.clone.overlap(), IMG_SIZE // 2) def test_resize_io(self): - parent_data = self.image.read(IMG_SIZE / 2, 256) + parent_data = self.image.read(IMG_SIZE // 2, 256) self.image.resize(0) - self.clone.resize(IMG_SIZE / 2 + 128) - child_data = self.clone.read(IMG_SIZE / 2, 128) + self.clone.resize(IMG_SIZE // 2 + 128) + child_data = self.clone.read(IMG_SIZE // 2, 128) eq(child_data, parent_data[:128]) self.clone.resize(IMG_SIZE) - child_data = self.clone.read(IMG_SIZE / 2, 256) - eq(child_data, parent_data[:128] + ('\0' * 128)) - self.clone.resize(IMG_SIZE / 2 + 1) - child_data = self.clone.read(IMG_SIZE / 2, 1) + child_data = self.clone.read(IMG_SIZE // 2, 256) + eq(child_data, parent_data[:128] + (b'\0' * 128)) + self.clone.resize(IMG_SIZE // 2 + 1) + child_data = self.clone.read(IMG_SIZE // 2, 1) eq(child_data, parent_data[0]) self.clone.resize(0) self.clone.resize(IMG_SIZE) - child_data = self.clone.read(IMG_SIZE / 2, 256) - eq(child_data, '\0' * 256) + child_data = self.clone.read(IMG_SIZE // 2, 256) + eq(child_data, b'\0' * 256) def test_read(self): - parent_data = self.image.read(IMG_SIZE / 2, 256) - child_data = self.clone.read(IMG_SIZE / 2, 256) + parent_data = self.image.read(IMG_SIZE // 2, 256) + child_data = self.clone.read(IMG_SIZE // 2, 256) eq(child_data, parent_data) def test_write(self): - parent_data = self.image.read(IMG_SIZE / 2, 256) + parent_data = self.image.read(IMG_SIZE // 2, 256) new_data = rand_data(256) - self.clone.write(new_data, IMG_SIZE / 2 + 256) - child_data = self.clone.read(IMG_SIZE / 2 + 256, 256) + self.clone.write(new_data, IMG_SIZE // 2 + 256) + child_data = self.clone.read(IMG_SIZE // 2 + 256, 256) eq(child_data, new_data) - child_data = self.clone.read(IMG_SIZE / 2, 256) + child_data = self.clone.read(IMG_SIZE // 2, 256) eq(child_data, parent_data) - parent_data = self.image.read(IMG_SIZE / 2 + 256, 256) - eq(parent_data, '\0' * 256) + parent_data = self.image.read(IMG_SIZE // 2 + 256, 256) + eq(parent_data, b'\0' * 256) def check_children(self, expected): actual = self.image.list_children() @@ -823,13 +821,13 @@ class TestClone(object): clone_name = get_temp_image_name() + '_' expected_children = [] - for i in xrange(10): + for i in range(10): self.rbd.clone(ioctx, image_name, 'snap1', ioctx, clone_name + str(i), features) expected_children.append((pool_name, clone_name + str(i))) self.check_children(expected_children) - for i in xrange(10): + for i in range(10): self.rbd.remove(ioctx, clone_name + str(i)) expected_children.pop(0) self.check_children(expected_children) @@ -899,15 +897,15 @@ class TestClone(object): with Image(ioctx, clone_name2) as clone: with Image(ioctx, clone_name2) as clone2: # cache object non-existence - data = clone.read(IMG_SIZE / 2, 256) - clone2_data = clone2.read(IMG_SIZE / 2, 256) + data = clone.read(IMG_SIZE // 2, 256) + clone2_data = clone2.read(IMG_SIZE // 2, 256) eq(data, clone2_data) clone.flatten() assert_raises(ImageNotFound, clone.parent_info) assert_raises(ImageNotFound, clone2.parent_info) - after_flatten = clone.read(IMG_SIZE / 2, 256) + after_flatten = clone.read(IMG_SIZE // 2, 256) eq(data, after_flatten) - after_flatten = clone2.read(IMG_SIZE / 2, 256) + after_flatten = clone2.read(IMG_SIZE // 2, 256) eq(data, after_flatten) self.rbd.remove(ioctx, clone_name2) @@ -962,8 +960,7 @@ class TestExclusiveLock(object): rados2.shutdown() def test_ownership(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: image1.write('0'*256, 0) eq(image1.is_exclusive_lock_owner(), True) eq(image2.is_exclusive_lock_owner(), False) @@ -974,7 +971,7 @@ class TestExclusiveLock(object): eq(image.is_exclusive_lock_owner(), True) try: with Image(ioctx, image_name) as image: - image.write('0'*256, 0) + image.write(b'0'*256, 0) eq(image.is_exclusive_lock_owner(), True) image.set_snap('snap') eq(image.is_exclusive_lock_owner(), False) @@ -994,14 +991,13 @@ class TestExclusiveLock(object): image.protect_snap('snap') try: RBD().clone(ioctx, image_name, 'snap', ioctx, 'clone', features) - with nested(Image(ioctx, 'clone'), Image(ioctx2, 'clone')) as ( - image1, image2): + with Image(ioctx, 'clone') as image1, Image(ioctx2, 'clone') as image2: data = rand_data(256) image1.write(data, 0) image2.flatten() assert_raises(ImageNotFound, image1.parent_info) parent = True - for x in xrange(30): + for x in range(30): try: image2.parent_info() except ImageNotFound: @@ -1015,27 +1011,24 @@ class TestExclusiveLock(object): image.remove_snap('snap') def test_follower_resize(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): - image1.write('0'*256, 0) + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: + image1.write(b'0'*256, 0) for new_size in [IMG_SIZE * 2, IMG_SIZE / 2]: image2.resize(new_size); eq(new_size, image1.size()) - for x in xrange(30): + for x in range(30): if new_size == image2.size(): break time.sleep(1) eq(new_size, image2.size()) def test_follower_snap_create(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: image2.create_snap('snap1') image1.remove_snap('snap1') def test_follower_snap_rollback(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: image1.create_snap('snap') try: assert_raises(ReadOnlyImage, image2.rollback_to_snap, 'snap') @@ -1044,8 +1037,7 @@ class TestExclusiveLock(object): image1.remove_snap('snap') def test_follower_discard(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: data = rand_data(256) image1.write(data, 0) image2.discard(0, 256) @@ -1055,8 +1047,7 @@ class TestExclusiveLock(object): eq(256*'\0', read) def test_follower_write(self): - with nested(Image(ioctx, image_name), Image(ioctx2, image_name)) as ( - image1, image2): + with Image(ioctx, image_name) as image1, Image(ioctx2, image_name) as image2: data = rand_data(256) image1.write(data, 0) image2.write(data, IMG_SIZE / 2) |