]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: add API to list mirror image info
authorMykola Golub <mgolub@suse.com>
Fri, 27 Dec 2019 08:54:31 +0000 (08:54 +0000)
committerJason Dillaman <dillaman@redhat.com>
Sun, 26 Jan 2020 16:20:29 +0000 (11:20 -0500)
Signed-off-by: Mykola Golub <mgolub@suse.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/pybind/test_rbd.py

index fbb83f68afa1acea8759c9e3f72a3dbb29f9694e..7395f803dd38338d2242ce8393c5da1e2c025e7f 100644 (file)
@@ -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);
 
index f5f304c94bd74677675a7b4262458eb9a0e8d501..ded3c296e69f1f7c1cc0b4812918f4c3918d04cb 100644 (file)
@@ -347,6 +347,10 @@ public:
       std::map<mirror_image_status_state_t, int> *states);
   int mirror_image_instance_id_list(IoCtx& io_ctx, const std::string &start_id,
       size_t max, std::map<std::string, std::string> *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<std::string, std::pair<mirror_image_mode_t,
+                                      mirror_image_info_t>> *entries);
 
   /// mirror_peer_ commands are deprecated to mirror_peer_site_ equivalents
   int mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
index 185aa56263ee33860c456ab8762e54bcab4f4171..bc3e10fed1668c80c250add3c1a067d6132ec22a 100644 (file)
@@ -1715,6 +1715,69 @@ int Mirror<I>::image_instance_id_list(
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::image_info_list(
+    librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
+    const std::string &start_id, size_t max,
+    std::map<std::string, std::pair<mirror_image_mode_t,
+                                    mirror_image_info_t>> *entries) {
+  CephContext *cct = reinterpret_cast<CephContext *>(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<std::string, cls::rbd::MirrorImage> images;
+    map<std::string, cls::rbd::MirrorImageStatus> 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<mirror_image_mode_t>(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 <typename I>
 int Mirror<I>::image_snapshot_create(I *ictx, uint64_t *snap_id) {
   CephContext *cct = ictx->cct;
index 949cb136d182cf4ab13c4b73a696cb851db3a068..02db23f2d3c12748484257d6fbf5cecbc9d75bac 100644 (file)
@@ -69,6 +69,12 @@ struct Mirror {
                                     size_t max,
                                     std::map<std::string, std::string> *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<std::string, std::pair<mirror_image_mode_t,
+                                      mirror_image_info_t>> *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);
index d7987a15e2bf2cfd3101b7c60c1b1841ce5f8ece..c745b6229d6995cf43da46e95feec46b691e8da1 100644 (file)
@@ -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<std::string, std::pair<mirror_image_mode_t,
+                                      mirror_image_info_t>> *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<tracepoint_traits>(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<std::string, std::pair<librbd::mirror_image_mode_t,
+                                  librbd::mirror_image_info_t>> 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)
 {
index 9dc084a8237318b49fd32d5daf63838440df5471..2552be67adeec2cdcac4d18350b104e00f118f2b 100644 (file)
@@ -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 = <char **>realloc_chk(NULL,
+            sizeof(char *) * self.max_read)
+        self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
+            sizeof(rbd_mirror_image_info_t) * self.max_read)
+        self.mode_entries = <rbd_mirror_image_mode_t *>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):
index 3af8804638f6305e5f8f1a1de6bdff9a06c184ba..47908bb9bfe6416a71d7e6b38f0fc020ab30019f 100644 (file)
@@ -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())