From: Mykola Golub Date: Fri, 27 Dec 2019 08:54:31 +0000 (+0000) Subject: librbd: add API to list mirror image info X-Git-Tag: v15.1.0~46^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ab24bb86f6c25857ede2937bf4e7bbd205135677;p=ceph.git librbd: add API to list mirror image info Signed-off-by: Mykola Golub --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index fbb83f68afa1..7395f803dd38 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -587,6 +587,14 @@ CEPH_RBD_API int rbd_mirror_image_instance_id_list(rados_ioctx_t io_ctx, CEPH_RBD_API void rbd_mirror_image_instance_id_list_cleanup(char **image_ids, char **instance_ids, size_t len); +CEPH_RBD_API int rbd_mirror_image_info_list( + rados_ioctx_t io_ctx, rbd_mirror_image_mode_t *mode_filter, + const char *start_id, size_t max, char **image_ids, + rbd_mirror_image_mode_t *mode_entries, + rbd_mirror_image_info_t *info_entries, size_t *num_entries); +CEPH_RBD_API void rbd_mirror_image_info_list_cleanup( + char **image_ids, rbd_mirror_image_info_t *info_entries, + size_t num_entries); /* pool metadata */ CEPH_RBD_API int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key, @@ -1193,6 +1201,8 @@ CEPH_RBD_API int rbd_mirror_image_create_snapshot(rbd_image_t image, CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image, rbd_mirror_image_info_t *mirror_image_info, size_t info_size); +CEPH_RBD_API void rbd_mirror_image_get_info_cleanup( + rbd_mirror_image_info_t *mirror_image_info); CEPH_RBD_API int rbd_mirror_image_get_mode(rbd_image_t image, rbd_mirror_image_mode_t *mode); diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index f5f304c94bd7..ded3c296e69f 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -347,6 +347,10 @@ public: std::map *states); int mirror_image_instance_id_list(IoCtx& io_ctx, const std::string &start_id, size_t max, std::map *sevice_ids); + int mirror_image_info_list(IoCtx& io_ctx, mirror_image_mode_t *mode_filter, + const std::string &start_id, size_t max, + std::map> *entries); /// mirror_peer_ commands are deprecated to mirror_peer_site_ equivalents int mirror_peer_add(IoCtx& io_ctx, std::string *uuid, diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index 185aa56263ee..bc3e10fed166 100644 --- a/src/librbd/api/Mirror.cc +++ b/src/librbd/api/Mirror.cc @@ -1715,6 +1715,69 @@ int Mirror::image_instance_id_list( return 0; } +template +int Mirror::image_info_list( + librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter, + const std::string &start_id, size_t max, + std::map> *entries) { + CephContext *cct = reinterpret_cast(io_ctx.cct()); + ldout(cct, 20) << "pool=" << io_ctx.get_pool_name() << ", mode_filter=" + << (mode_filter ? stringify(*mode_filter) : "null") + << ", start_id=" << start_id << ", max=" << max << dendl; + + std::string last_read = start_id; + entries->clear(); + + while (entries->size() < max) { + map images; + map statuses; + + int r = librbd::cls_client::mirror_image_status_list(&io_ctx, last_read, + max, &images, + &statuses); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to list mirror image statuses: " + << cpp_strerror(r) << dendl; + return r; + } + + if (images.empty()) { + break; + } + + for (auto &it : images) { + auto &image_id = it.first; + auto &image = it.second; + auto mode = static_cast(image.mode); + + if ((mode_filter && mode != *mode_filter) || + image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { + continue; + } + + // need to call get_info for every image to retrieve promotion state + // TODO: optimize + + mirror_image_info_t info; + I *image_ctx = I::create("", image_id, nullptr, io_ctx, true); + r = image_ctx->state->open(0); + if (r < 0) { + continue; + } + r = image_get_info(image_ctx, &info); + image_ctx->state->close(); + if (r >= 0) { + (*entries)[image_id] = {mode, info}; + } + } + + last_read = images.rbegin()->first; + } + + return 0; +} + template int Mirror::image_snapshot_create(I *ictx, uint64_t *snap_id) { CephContext *cct = ictx->cct; diff --git a/src/librbd/api/Mirror.h b/src/librbd/api/Mirror.h index 949cb136d182..02db23f2d3c1 100644 --- a/src/librbd/api/Mirror.h +++ b/src/librbd/api/Mirror.h @@ -69,6 +69,12 @@ struct Mirror { size_t max, std::map *ids); + static int image_info_list( + librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter, + const std::string &start_id, size_t max, + std::map> *entries); + static int image_enable(ImageCtxT *ictx, mirror_image_mode_t mode, bool relax_same_pool_parent_check); static int image_disable(ImageCtxT *ictx, bool force); diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index d7987a15e2bf..c745b6229d69 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -1172,6 +1172,15 @@ namespace librbd { instance_ids); } + int RBD::mirror_image_info_list( + IoCtx& io_ctx, mirror_image_mode_t *mode_filter, + const std::string &start_id, size_t max, + std::map> *entries) { + return librbd::api::Mirror<>::image_info_list(io_ctx, mode_filter, start_id, + max, entries); + } + int RBD::group_create(IoCtx& io_ctx, const char *group_name) { TracepointProvider::initialize(get_cct(io_ctx)); @@ -3340,7 +3349,7 @@ extern "C" int rbd_mirror_image_global_status_list(rados_ioctx_t p, extern "C" void rbd_mirror_image_global_status_cleanup( rbd_mirror_image_global_status_t *global_status) { free(global_status->name); - free(global_status->info.global_id); + rbd_mirror_image_get_info_cleanup(&global_status->info); for (auto idx = 0U; idx < global_status->site_statuses_count; ++idx) { free(global_status->site_statuses[idx].fsid); free(global_status->site_statuses[idx].description); @@ -3460,7 +3469,7 @@ extern "C" void rbd_mirror_image_status_list_cleanup(char **image_ids, for (size_t i = 0; i < len; i++) { free(image_ids[i]); free(images[i].name); - free(images[i].info.global_id); + rbd_mirror_image_get_info_cleanup(&images[i].info); free(images[i].description); } } @@ -3524,6 +3533,43 @@ extern "C" void rbd_mirror_image_instance_id_list_cleanup( } } +extern "C" int rbd_mirror_image_info_list( + rados_ioctx_t p, rbd_mirror_image_mode_t *mode_filter, + const char *start_id, size_t max, char **image_ids, + rbd_mirror_image_mode_t *mode_entries, + rbd_mirror_image_info_t *info_entries, size_t *num_entries) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(p, io_ctx); + std::map> cpp_entries; + + int r = librbd::api::Mirror<>::image_info_list(io_ctx, mode_filter, start_id, + max, &cpp_entries); + if (r < 0) { + return r; + } + + ceph_assert(cpp_entries.size() <= max); + + for (auto &it : cpp_entries) { + *(image_ids++) = strdup(it.first.c_str()); + *(mode_entries++) = it.second.first; + mirror_image_info_cpp_to_c(it.second.second, info_entries++); + } + *num_entries = cpp_entries.size(); + + return 0; +} + +extern "C" void rbd_mirror_image_info_list_cleanup( + char **image_ids, rbd_mirror_image_info_t *info_entries, + size_t num_entries) { + for (size_t i = 0; i < num_entries; i++) { + free(*(image_ids++)); + rbd_mirror_image_get_info_cleanup(info_entries++); + } +} + /* helpers */ extern "C" void rbd_image_spec_cleanup(rbd_image_spec_t *image) @@ -6228,6 +6274,12 @@ extern "C" int rbd_mirror_image_get_info(rbd_image_t image, return 0; } +extern "C" void rbd_mirror_image_get_info_cleanup( + rbd_mirror_image_info_t *mirror_image_info) +{ + free(mirror_image_info->global_id); +} + extern "C" int rbd_mirror_image_get_mode(rbd_image_t image, rbd_mirror_image_mode_t *mode) { diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 9dc084a82373..2552be67adee 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -425,6 +425,16 @@ cdef extern from "rbd/librbd.h" nogil: void rbd_mirror_image_instance_id_list_cleanup(char **image_ids, char **instance_ids, size_t len) + int rbd_mirror_image_info_list(rados_ioctx_t io_ctx, + rbd_mirror_image_mode_t *mode_filter, + const char *start_id, size_t max, + char **image_ids, + rbd_mirror_image_mode_t *mode_entries, + rbd_mirror_image_info_t *info_entries, + size_t *num_entries) + void rbd_mirror_image_info_list_cleanup(char **image_ids, + rbd_mirror_image_info_t *info_entries, + size_t num_entries) int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key, char *value, size_t *val_len) @@ -593,6 +603,8 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_mirror_image_get_info(rbd_image_t image, rbd_mirror_image_info_t *mirror_image_info, size_t info_size) + void rbd_mirror_image_get_info_cleanup( + rbd_mirror_image_info_t *mirror_image_info) int rbd_mirror_image_get_mode(rbd_image_t image, rbd_mirror_image_mode_t *mode) int rbd_mirror_image_get_global_status( @@ -2127,6 +2139,17 @@ class RBD(object): """ return MirrorImageInstanceIdIterator(ioctx) + def mirror_image_info_list(self, ioctx, mode_filter=None): + """ + Iterate over the mirror image instance ids of a pool. + + :param ioctx: determines which RADOS pool is read + :param mode_filter: list images in this image mirror mode + :type ioctx: :class:`rados.Ioctx` + :returns: :class:`MirrorImageInfoIterator` + """ + return MirrorImageInfoIterator(ioctx, mode_filter) + def pool_metadata_get(self, ioctx, key): """ Get pool metadata for the given key. @@ -2867,6 +2890,88 @@ cdef class MirrorImageInstanceIdIterator(object): free(self.last_read) self.last_read = strdup("") +cdef class MirrorImageInfoIterator(object): + """ + Iterator over mirror image info for a pool. + + Yields ``(image_id, info)`` tuple. + """ + + cdef: + rados_ioctx_t ioctx + rbd_mirror_image_mode_t mode_filter + rbd_mirror_image_mode_t *mode_filter_ptr + size_t max_read + char *last_read + char **image_ids + rbd_mirror_image_info_t *info_entries + rbd_mirror_image_mode_t *mode_entries + size_t size + + def __init__(self, ioctx, mode_filter): + self.ioctx = convert_ioctx(ioctx) + if mode_filter is not None: + self.mode_filter = mode_filter + self.mode_filter_ptr = &self.mode_filter + else: + self.mode_filter_ptr = NULL + self.max_read = 1024 + self.last_read = strdup("") + self.image_ids = realloc_chk(NULL, + sizeof(char *) * self.max_read) + self.info_entries = realloc_chk(NULL, + sizeof(rbd_mirror_image_info_t) * self.max_read) + self.mode_entries = realloc_chk(NULL, + sizeof(rbd_mirror_image_mode_t) * 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]), + { + 'mode' : int(self.mode_entries[i]), + 'global_id' : decode_cstr(self.info_entries[i].global_id), + 'state' : int(self.info_entries[i].state), + 'primary' : self.info_entries[i].primary, + }) + if self.size < self.max_read: + break + self.get_next_chunk() + + def __dealloc__(self): + rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries, + self.size) + if self.last_read: + free(self.last_read) + if self.image_ids: + free(self.image_ids) + if self.info_entries: + free(self.info_entries) + if self.mode_entries: + free(self.mode_entries) + + def get_next_chunk(self): + if self.size > 0: + rbd_mirror_image_info_list_cleanup(self.image_ids, + self.info_entries, self.size) + self.size = 0 + with nogil: + ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr, + self.last_read, self.max_read, + self.image_ids, self.mode_entries, + self.info_entries, &self.size) + if ret < 0: + raise make_ex(ret, 'error listing mirror image info') + if self.size > 0: + last_read = cstr(self.image_ids[self.size - 1], 'last_read') + free(self.last_read) + self.last_read = strdup(last_read) + else: + free(self.last_read) + self.last_read = strdup("") + cdef class PoolMetadataIterator(object): """ Iterator over pool metadata list. @@ -4622,7 +4727,7 @@ written." % (self.name, ret, length)) 'state' : int(c_info.state), 'primary' : c_info.primary, } - free(c_info.global_id) + rbd_mirror_image_get_info_cleanup(&c_info) return info def mirror_image_get_mode(self): diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 3af8804638f6..47908bb9bfe6 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -28,7 +28,7 @@ from rbd import (RBD, Group, Image, ImageNotFound, InvalidArgument, ImageExists, RBD_MIRROR_MODE_DISABLED, RBD_MIRROR_MODE_IMAGE, RBD_MIRROR_MODE_POOL, RBD_MIRROR_IMAGE_ENABLED, RBD_MIRROR_IMAGE_DISABLED, MIRROR_IMAGE_STATUS_STATE_UNKNOWN, - RBD_MIRROR_IMAGE_MODE_SNAPSHOT, + RBD_MIRROR_IMAGE_MODE_JOURNAL, RBD_MIRROR_IMAGE_MODE_SNAPSHOT, RBD_LOCK_MODE_EXCLUSIVE, RBD_OPERATION_FEATURE_GROUP, RBD_SNAP_NAMESPACE_TYPE_TRASH, RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY, @@ -1996,12 +1996,20 @@ class TestMirroring(object): info = self.image.mirror_image_get_info() self.check_info(info, global_id, RBD_MIRROR_IMAGE_ENABLED, False) + entries = dict(self.rbd.mirror_image_info_list(ioctx)) + info['mode'] = RBD_MIRROR_IMAGE_MODE_JOURNAL; + eq(info, entries[self.image.id()]) + self.image.mirror_image_resync() self.image.mirror_image_promote(True) info = self.image.mirror_image_get_info() self.check_info(info, global_id, RBD_MIRROR_IMAGE_ENABLED, True) + entries = dict(self.rbd.mirror_image_info_list(ioctx)) + info['mode'] = RBD_MIRROR_IMAGE_MODE_JOURNAL; + eq(info, entries[self.image.id()]) + fail = False try: self.image.mirror_image_resync() @@ -2068,6 +2076,14 @@ class TestMirroring(object): mode = self.image.mirror_image_get_mode() eq(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mode) + info = self.image.mirror_image_get_info() + eq(True, info['primary']) + entries = dict( + self.rbd.mirror_image_info_list(ioctx, + RBD_MIRROR_IMAGE_MODE_SNAPSHOT)) + info['mode'] = RBD_MIRROR_IMAGE_MODE_SNAPSHOT; + eq(info, entries[self.image.id()]) + snap_id = self.image.mirror_image_create_snapshot() snaps = list(self.image.list_snaps())