diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 5e6b4587a78..fd4341ee1a0 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -4466,10 +4466,87 @@ written." % (self.name, ret, length)) """ List image-level config overrides. - :returns: :class:`ConfigPoolIterator` + :returns: :class:`ConfigImageIterator` """ return ConfigImageIterator(self) + + def config_set(self, key, value): + """ + Set an image-level configuration override. + + :param key: key + :type key: str + :param value: value + :type value: str + """ + conf_key = 'conf_' + key + conf_key = cstr(conf_key, 'key') + value = cstr(value, 'value') + cdef: + char *_key = conf_key + char *_value = value + with nogil: + ret = rbd_metadata_set(self.image, _key, _value) + + if ret != 0: + raise make_ex(ret, 'error setting config %s for image %s' % + (key, self.name)) + + + def config_get(self, key): + """ + Get an image-level configuration override. + + :param key: key + :type key: str + :returns: str - value + """ + conf_key = 'conf_' + key + conf_key = cstr(conf_key, 'key') + cdef: + char *_key = conf_key + size_t size = 4096 + char *value = NULL + int ret + try: + while True: + value = realloc_chk(value, size) + with nogil: + ret = rbd_metadata_get(self.image, _key, value, &size) + if ret != -errno.ERANGE: + break + if ret == -errno.ENOENT: + raise KeyError('no config %s for image %s' % (key, self.name)) + if ret != 0: + raise make_ex(ret, 'error getting config %s for image %s' % + (key, self.name)) + return decode_cstr(value) + finally: + free(value) + + + def config_remove(self, key): + """ + Remove an image-level configuration override. + + :param key: key + :type key: str + """ + conf_key = 'conf_' + key + conf_key = cstr(conf_key, 'key') + cdef: + char *_key = conf_key + with nogil: + ret = rbd_metadata_remove(self.image, _key) + + if ret == -errno.ENOENT: + raise KeyError('no config %s for image %s' % (key, self.name)) + if ret != 0: + raise make_ex(ret, 'error removing config %s for image %s' % + (key, self.name)) + + def snap_get_namespace_type(self, snap_id): """ Get the snapshot namespace type. diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 0742ab8069c..86a7a99b4df 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -1137,6 +1137,20 @@ class TestImage(object): for option in image.config_list(): eq(option['source'], RBD_CONFIG_SOURCE_CONFIG) + def test_image_config_set_and_get_and_remove(self): + with Image(ioctx, image_name) as image: + for option in image.config_list(): + eq(option['source'], RBD_CONFIG_SOURCE_CONFIG) + + image.config_set("rbd_request_timed_out_seconds", "100") + modify_value = image.config_get("rbd_request_timed_out_seconds") + eq(modify_value, '100') + + image.config_remove("rbd_request_timed_out_seconds") + + for option in image.config_list(): + eq(option['source'], RBD_CONFIG_SOURCE_CONFIG) + def test_sparsify(self): assert_raises(InvalidArgument, self.image.sparsify, 16) self.image.sparsify(4096)