From: Mykola Golub Date: Thu, 25 Oct 2018 08:19:36 +0000 (+0300) Subject: librbd: API to get info which rbd-mirror daemon is mirroring image X-Git-Tag: v14.1.0~992^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e33796353446f5358f181c9db04c8e488409a52c;p=ceph.git librbd: API to get info which rbd-mirror daemon is mirroring image Signed-off-by: Mykola Golub --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 741012161068..0bb5f7e86a51 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -405,6 +405,15 @@ CEPH_RBD_API void rbd_mirror_image_status_list_cleanup(char **image_ids, CEPH_RBD_API int rbd_mirror_image_status_summary(rados_ioctx_t io_ctx, rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen); +CEPH_RBD_API int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx, + const char *start_id, + size_t max, char **image_ids, + char **instance_ids, + size_t *len); +CEPH_RBD_API void rbd_mirror_image_instance_id_list_cleanup(char **image_ids, + char **instance_ids, + size_t len); + /* pool metadata */ CEPH_RBD_API int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key, char *value, size_t *val_len); @@ -964,6 +973,9 @@ CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image, CEPH_RBD_API int rbd_mirror_image_get_status(rbd_image_t image, rbd_mirror_image_status_t *mirror_image_status, size_t status_size); +CEPH_RBD_API int rbd_mirror_image_get_instance_id(rbd_image_t image, + char *instance_id, + size_t *id_max_length); CEPH_RBD_API int rbd_aio_mirror_image_promote(rbd_image_t image, bool force, rbd_completion_t c); CEPH_RBD_API int rbd_aio_mirror_image_demote(rbd_image_t image, diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 380fc4d4ece1..f6a3d8be7ab3 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -250,6 +250,8 @@ public: size_t max, std::map *images); int mirror_image_status_summary(IoCtx& io_ctx, std::map *states); + int mirror_image_instance_id_list(IoCtx& io_ctx, const std::string &start_id, + size_t max, std::map *sevice_ids); // RBD groups support functions int group_create(IoCtx& io_ctx, const char *group_name); @@ -570,6 +572,7 @@ public: size_t info_size); int mirror_image_get_status(mirror_image_status_t *mirror_image_status, size_t status_size); + int mirror_image_get_instance_id(std::string *instance_id); int aio_mirror_image_promote(bool force, RBD::AioCompletion *c); int aio_mirror_image_demote(RBD::AioCompletion *c); int aio_mirror_image_get_info(mirror_image_info_t *mirror_image_info, diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index 4e12158dcc7b..66afdb565d3e 100644 --- a/src/librbd/api/Mirror.cc +++ b/src/librbd/api/Mirror.cc @@ -464,6 +464,38 @@ int Mirror::image_get_status(I *ictx, mirror_image_status_t *status) { return 0; } +template +int Mirror::image_get_instance_id(I *ictx, std::string *instance_id) { + CephContext *cct = ictx->cct; + ldout(cct, 20) << "ictx=" << ictx << dendl; + + cls::rbd::MirrorImage mirror_image; + int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &mirror_image); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r) + << dendl; + return r; + } else if (mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { + lderr(cct) << "mirroring is not currently enabled" << dendl; + return -EINVAL; + } + + entity_inst_t instance; + r = cls_client::mirror_image_instance_get(&ictx->md_ctx, + mirror_image.global_image_id, + &instance); + if (r < 0) { + if (r != -ENOENT && r != -ESTALE) { + lderr(cct) << "failed to get mirror image instance: " << cpp_strerror(r) + << dendl; + } + return r; + } + + *instance_id = stringify(instance.name.num()); + return 0; +} + template int Mirror::mode_get(librados::IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) { @@ -870,6 +902,28 @@ int Mirror::image_status_summary(librados::IoCtx& io_ctx, return 0; } +template +int Mirror::image_instance_id_list( + librados::IoCtx& io_ctx, const std::string &start_image_id, size_t max, + std::map *instance_ids) { + CephContext *cct = reinterpret_cast(io_ctx.cct()); + std::map instances; + + int r = librbd::cls_client::mirror_image_instance_list( + &io_ctx, start_image_id, max, &instances); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to list mirror image instances: " << cpp_strerror(r) + << dendl; + return r; + } + + for (auto it : instances) { + (*instance_ids)[it.first] = stringify(it.second.name.num()); + } + + return 0; +} + } // namespace api } // namespace librbd diff --git a/src/librbd/api/Mirror.h b/src/librbd/api/Mirror.h index a889e4b425cf..c2bc4464453a 100644 --- a/src/librbd/api/Mirror.h +++ b/src/librbd/api/Mirror.h @@ -41,6 +41,10 @@ struct Mirror { IdToMirrorImageStatus *images); static int image_status_summary(librados::IoCtx& io_ctx, MirrorImageStatusStates *states); + static int image_instance_id_list(librados::IoCtx& io_ctx, + const std::string &start_image_id, + size_t max, + std::map *ids); static int image_enable(ImageCtxT *ictx, bool relax_same_pool_parent_check); static int image_disable(ImageCtxT *ictx, bool force); @@ -57,7 +61,7 @@ struct Mirror { static int image_get_status(ImageCtxT *ictx, mirror_image_status_t *status); static void image_get_status(ImageCtxT *ictx, mirror_image_status_t *status, Context *on_finish); - + static int image_get_instance_id(ImageCtxT *ictx, std::string *instance_id); }; } // namespace api diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 7db9b78a5b61..794084d852b6 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -816,6 +816,13 @@ namespace librbd { return librbd::api::Mirror<>::image_status_summary(io_ctx, states); } + int RBD::mirror_image_instance_id_list(IoCtx& io_ctx, + const std::string &start_id, size_t max, + std::map *instance_ids) { + return librbd::api::Mirror<>::image_instance_id_list(io_ctx, start_id, max, + instance_ids); + } + int RBD::group_create(IoCtx& io_ctx, const char *group_name) { TracepointProvider::initialize(get_cct(io_ctx)); @@ -2344,6 +2351,12 @@ namespace librbd { return librbd::api::Mirror<>::image_get_status(ictx, mirror_image_status); } + int Image::mirror_image_get_instance_id(std::string *instance_id) { + ImageCtx *ictx = (ImageCtx *)ctx; + + return librbd::api::Mirror<>::image_get_instance_id(ictx, instance_id); + } + int Image::aio_mirror_image_promote(bool force, RBD::AioCompletion *c) { ImageCtx *ictx = (ImageCtx *)ctx; librbd::api::Mirror<>::image_promote( @@ -2659,6 +2672,38 @@ extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p, return 0; } +extern "C" int rbd_mirror_image_instance_id_list( + rados_ioctx_t p, const char *start_id, size_t max, char **image_ids, + char **instance_ids, size_t *len) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(p, io_ctx); + std::map cpp_instance_ids; + + int r = librbd::api::Mirror<>::image_instance_id_list(io_ctx, start_id, max, + &cpp_instance_ids); + if (r < 0) { + return r; + } + + size_t i = 0; + for (auto &it : cpp_instance_ids) { + ceph_assert(i < max); + image_ids[i] = strdup(it.first.c_str()); + instance_ids[i] = strdup(it.second.c_str()); + i++; + } + *len = i; + return 0; +} + +extern "C" void rbd_mirror_image_instance_id_list_cleanup( + char **image_ids, char **instance_ids, size_t len) { + for (size_t i = 0; i < len; i++) { + free(image_ids[i]); + free(instance_ids[i]); + } +} + /* images */ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size) { @@ -4998,6 +5043,28 @@ extern "C" int rbd_mirror_image_get_status(rbd_image_t image, return 0; } +extern "C" int rbd_mirror_image_get_instance_id(rbd_image_t image, + char *instance_id, + size_t *instance_id_max_length) +{ + librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; + + std::string cpp_instance_id; + int r = librbd::api::Mirror<>::image_get_instance_id(ictx, &cpp_instance_id); + if (r < 0) { + return r; + } + + if (cpp_instance_id.size() >= *instance_id_max_length) { + *instance_id_max_length = cpp_instance_id.size() + 1; + return -ERANGE; + } + + strcpy(instance_id, cpp_instance_id.c_str()); + *instance_id_max_length = cpp_instance_id.size() + 1; + return 0; +} + extern "C" int rbd_aio_mirror_image_promote(rbd_image_t image, bool force, rbd_completion_t c) { librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 871345dfe2f6..f1c687e0d719 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -304,6 +304,14 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_mirror_image_status_summary(rados_ioctx_t io, rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) + int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx, + const char *start_id, + size_t max, char **image_ids, + char **instance_ids, + size_t *len) + void rbd_mirror_image_instance_id_list_cleanup(char **image_ids, + char **instance_ids, + size_t len) int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key, char *value, size_t *val_len) @@ -453,6 +461,8 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_mirror_image_get_status(rbd_image_t image, rbd_mirror_image_status_t *mirror_image_status, size_t status_size) + int rbd_mirror_image_get_instance_id(rbd_image_t image, char *instance_id, + size_t *id_max_length) int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len, const char *buf, rbd_completion_t c, int op_flags) @@ -1577,7 +1587,7 @@ class RBD(object): :param ioctx: determines which RADOS pool is read :type ioctx: :class:`rados.Ioctx` - :returns: :class:`MirrorImageStatus` + :returns: :class:`MirrorImageStatusIterator` """ return MirrorImageStatusIterator(ioctx) @@ -1608,6 +1618,16 @@ class RBD(object): free(states) free(counts) + def mirror_image_instance_id_list(self, ioctx): + """ + Iterate over the mirror image instance ids of a pool. + + :param ioctx: determines which RADOS pool is read + :type ioctx: :class:`rados.Ioctx` + :returns: :class:`MirrorImageInstanceIdIterator` + """ + return MirrorImageInstanceIdIterator(ioctx) + def pool_metadata_get(self, ioctx, key): """ Get pool metadata for the given key. @@ -1857,6 +1877,8 @@ cdef class MirrorImageStatusIterator(object): * ``name`` (str) - mirror image name + * ``id`` (str) - mirror image id + * `info` (dict) - mirror image info * `state` (int) - mirror state @@ -1892,6 +1914,7 @@ cdef class MirrorImageStatusIterator(object): for i in range(self.size): yield { 'name' : decode_cstr(self.images[i].name), + 'id' : decode_cstr(self.image_ids[i]), 'info' : { 'global_id' : decode_cstr(self.images[i].info.global_id), 'state' : self.images[i].info.state, @@ -1934,6 +1957,73 @@ cdef class MirrorImageStatusIterator(object): free(self.last_read) self.last_read = strdup("") +cdef class MirrorImageInstanceIdIterator(object): + """ + Iterator over mirror image instance id for a pool. + + Yields ``(image_id, instance_id)`` tuple. + """ + + cdef: + rados_ioctx_t ioctx + size_t max_read + char *last_read + char **image_ids + char **instance_ids + size_t size + + def __init__(self, ioctx): + self.ioctx = convert_ioctx(ioctx) + self.max_read = 1024 + self.last_read = strdup("") + self.image_ids = realloc_chk(NULL, + sizeof(char *) * self.max_read) + self.instance_ids = realloc_chk(NULL, + sizeof(char *) * self.max_read) + self.size = 0 + self.get_next_chunk() + + def __iter__(self): + while self.size > 0: + for i in range(self.size): + yield (decode_cstr(self.image_ids[i]), + decode_cstr(self.instance_ids[i])) + if self.size < self.max_read: + break + self.get_next_chunk() + + def __dealloc__(self): + rbd_mirror_image_instance_id_list_cleanup(self.image_ids, + self.instance_ids, self.size) + if self.last_read: + free(self.last_read) + if self.image_ids: + free(self.image_ids) + if self.instance_ids: + free(self.instance_ids) + + def get_next_chunk(self): + if self.size > 0: + rbd_mirror_image_instance_id_list_cleanup(self.image_ids, + self.instance_ids, + self.size) + self.size = 0 + with nogil: + ret = rbd_mirror_image_instance_id_list(self.ioctx, self.last_read, + self.max_read, + self.image_ids, + self.instance_ids, + &self.size) + if ret < 0: + raise make_ex(ret, 'error listing mirror images instance ids') + if self.size > 0: + free(self.last_read) + last_read = decode_cstr(self.image_ids[self.size - 1]) + self.last_read = strdup(last_read) + else: + free(self.last_read) + self.last_read = strdup("") + cdef class PoolMetadataIterator(object): """ Iterator over pool metadata list. @@ -3581,6 +3671,8 @@ written." % (self.name, ret, length)) * ``name`` (str) - mirror image name + * ``id`` (str) - mirror image id + * `info` (dict) - mirror image info * ``state`` (int) - status mirror state @@ -3599,6 +3691,7 @@ written." % (self.name, ret, length)) raise make_ex(ret, 'error getting mirror status for image %s' % self.name) status = { 'name' : decode_cstr(c_status.name), + 'id' : self.id(), 'info' : { 'global_id' : decode_cstr(c_status.info.global_id), 'state' : int(c_status.info.state), @@ -3614,6 +3707,30 @@ written." % (self.name, ret, length)) free(c_status.description) return status + def mirror_image_get_instance_id(self): + """ + Get mirror instance id for the image. + + :returns: str - instance id + """ + cdef: + int ret = -errno.ERANGE + size_t size = 32 + char *instance_id = NULL + try: + while ret == -errno.ERANGE and size <= 4096: + instance_id = realloc_chk(instance_id, size) + with nogil: + ret = rbd_mirror_image_get_instance_id(self.image, + instance_id, &size) + if ret != 0: + raise make_ex(ret, + 'error getting mirror instance id for image %s' % + self.name) + return decode_cstr(instance_id) + finally: + free(instance_id) + def aio_read(self, offset, length, oncomplete, fadvise_flags=0): """ Asynchronously read data from the image diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc index b4fdeae3f330..245f81943cbb 100644 --- a/src/test/librbd/test_mirroring.cc +++ b/src/test/librbd/test_mirroring.cc @@ -75,6 +75,10 @@ public: ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + std::string instance_id; + ASSERT_EQ(mirror_state == RBD_MIRROR_IMAGE_ENABLED ? -ENOENT : -EINVAL, + image.mirror_image_get_instance_id(&instance_id)); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -104,6 +108,10 @@ public: ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + std::string instance_id; + ASSERT_EQ(mirror_state == RBD_MIRROR_IMAGE_ENABLED ? -ENOENT : -EINVAL, + image.mirror_image_get_instance_id(&instance_id)); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -122,6 +130,11 @@ public: ASSERT_EQ(images.size(), states_count); *images_count = images.size(); + + std::map instance_ids; + ASSERT_EQ(0, m_rbd.mirror_image_instance_id_list(m_ioctx, "", 4096, + &instance_ids)); + ASSERT_TRUE(instance_ids.empty()); } void check_mirroring_on_create(uint64_t features, diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 9dc98537336c..3b8ef8e29ee0 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -1762,6 +1762,10 @@ class TestMirroring(object): states = self.rbd.mirror_image_status_summary(ioctx) eq([(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, 1)], states) + assert_raises(ImageNotFound, self.image.mirror_image_get_instance_id) + instance_ids = list(self.rbd.mirror_image_instance_id_list(ioctx)) + eq(0, len(instance_ids)) + N = 65 for i in range(N): self.rbd.create(ioctx, image_name + str(i), IMG_SIZE, IMG_ORDER,