]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: API to get info which rbd-mirror daemon is mirroring image
authorMykola Golub <mgolub@suse.com>
Thu, 25 Oct 2018 08:19:36 +0000 (11:19 +0300)
committerMykola Golub <mgolub@suse.com>
Sat, 3 Nov 2018 08:20:42 +0000 (10:20 +0200)
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/librbd/test_mirroring.cc
src/test/pybind/test_rbd.py

index 74101216106894d2aee6651d903580498272030a..0bb5f7e86a51d29511ff1d1da5a1b7721a51ea94 100644 (file)
@@ -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,
index 380fc4d4ece1e71fb7ec80a6a8e23ad0bd9a77b0..f6a3d8be7ab3a9cb31138a046ea986ce4f0ef239 100644 (file)
@@ -250,6 +250,8 @@ public:
       size_t max, std::map<std::string, mirror_image_status_t> *images);
   int mirror_image_status_summary(IoCtx& io_ctx,
       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);
 
   // 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,
index 4e12158dcc7bf29692242133c63c910c87969d00..66afdb565d3e39587bf40704c7d7a9766451a48a 100644 (file)
@@ -464,6 +464,38 @@ int Mirror<I>::image_get_status(I *ictx, mirror_image_status_t *status) {
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::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 <typename I>
 int Mirror<I>::mode_get(librados::IoCtx& io_ctx,
                         rbd_mirror_mode_t *mirror_mode) {
@@ -870,6 +902,28 @@ int Mirror<I>::image_status_summary(librados::IoCtx& io_ctx,
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::image_instance_id_list(
+    librados::IoCtx& io_ctx, const std::string &start_image_id, size_t max,
+    std::map<std::string, std::string> *instance_ids) {
+  CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+  std::map<std::string, entity_inst_t> 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
 
index a889e4b425cfcd4b2a5b6be260dbd438a8a119a2..c2bc4464453aff5967b48ea9b4d677c1a014ff29 100644 (file)
@@ -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<std::string, std::string> *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
index 7db9b78a5b612671fce08a8b8a7df424fe5546b4..794084d852b65d0141e0598a560552f304c281d7 100644 (file)
@@ -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<std::string, std::string> *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<tracepoint_traits>(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<std::string, std::string> 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;
index 871345dfe2f6b3a275f282ed602004f59fd6779a..f1c687e0d71992b986c6b0d0f4f84267fed0033e 100644 (file)
@@ -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 = <char **>realloc_chk(NULL,
+            sizeof(char *) * self.max_read)
+        self.instance_ids = <char **>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 =  <char *>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
index b4fdeae3f3301055418074dc67edfd0bab5a1aef..245f81943cbb52a1701c8a29b3e7c1713f059172 100644 (file)
@@ -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<std::string, std::string> 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,
index 9dc98537336cb6efd1a94c60bdbf6170a5297f4d..3b8ef8e29ee057d9abaacf5f14e12fddb064f9e9 100644 (file)
@@ -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,