]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: API to retrieve image mirroring status
authorMykola Golub <mgolub@mirantis.com>
Fri, 15 Apr 2016 05:42:17 +0000 (08:42 +0300)
committerMykola Golub <mgolub@mirantis.com>
Tue, 26 Apr 2016 12:52:09 +0000 (15:52 +0300)
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/test/librbd/test_mirroring.cc

index 49ed98e9d7d85aaaf349c5b04ff9899b211136bb..03c85b7185f6648e28d6aa900c006639f1876d7a 100644 (file)
@@ -113,6 +113,23 @@ typedef struct {
   bool primary;
 } rbd_mirror_image_info_t;
 
+typedef enum {
+  MIRROR_IMAGE_STATUS_STATE_UNKNOWN         = 0,
+  MIRROR_IMAGE_STATUS_STATE_ERROR           = 1,
+  MIRROR_IMAGE_STATUS_STATE_SYNCING         = 2,
+  MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = 3,
+  MIRROR_IMAGE_STATUS_STATE_REPLAYING       = 4,
+  MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = 5,
+  MIRROR_IMAGE_STATUS_STATE_STOPPED         = 6,
+} rbd_mirror_image_status_state_t;
+
+typedef struct {
+  rbd_mirror_image_status_state_t state;
+  char *description;
+  time_t last_update;
+  bool up;
+} rbd_mirror_image_status_t;
+
 CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra);
 
 /* image options */
@@ -208,6 +225,12 @@ CEPH_RBD_API int rbd_mirror_peer_set_client(rados_ioctx_t io_ctx,
 CEPH_RBD_API int rbd_mirror_peer_set_cluster(rados_ioctx_t io_ctx,
                                              const char *uuid,
                                              const char *cluster_name);
+CEPH_RBD_API int rbd_mirror_image_status_list(rados_ioctx_t io_ctx,
+    const char *start, size_t max, char **image_names,
+    rbd_mirror_image_info_t *images, rbd_mirror_image_status_t *image_statuses,
+    size_t *len);
+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_open(rados_ioctx_t io, const char *name,
                           rbd_image_t *image, const char *snap_name);
@@ -607,6 +630,8 @@ CEPH_RBD_API int rbd_mirror_image_resync(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 int rbd_mirror_image_get_status(rbd_image_t image,
+    rbd_mirror_image_status_t *mirror_image_status, size_t info_size);
 
 #ifdef __cplusplus
 }
index f328c424a24a0509af37a37b8e18e8e0a2be4e69..3cba391d3ebb3f8b209113a3cf05ab06485920bd 100644 (file)
@@ -60,6 +60,15 @@ namespace librbd {
     bool primary;
   } mirror_image_info_t;
 
+  typedef rbd_mirror_image_status_state_t mirror_image_status_state_t;
+
+  typedef struct {
+    mirror_image_status_state_t state;
+    std::string description;
+    time_t last_update;
+    bool up;
+  } mirror_image_status_t;
+
   typedef rbd_image_info_t image_info_t;
 
   class CEPH_RBD_API ProgressContext
@@ -132,6 +141,11 @@ public:
                              const std::string &client_name);
   int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
                               const std::string &cluster_name);
+  int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+      size_t max, std::map<std::string, mirror_image_info_t> *images,
+      std::map<std::string, mirror_image_status_t> *statuses);
+  int mirror_image_status_summary(IoCtx& io_ctx,
+      std::map<mirror_image_status_state_t, int> *states);
 
 private:
   /* We don't allow assignment or copying */
@@ -337,6 +351,8 @@ public:
   int mirror_image_resync();
   int mirror_image_get_info(mirror_image_info_t *mirror_image_info,
                             size_t info_size);
+  int mirror_image_get_status(mirror_image_status_t *mirror_image_status,
+                             size_t status_size);
 
 private:
   friend class RBD;
index 5276052c5190fd18f9031b27809082663c764625..4556880161f723331d27cd140062e77163ff3ba5 100644 (file)
@@ -2877,6 +2877,43 @@ remove_mirroring_image:
     return 0;
   }
 
+  int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
+                             size_t status_size) {
+    CephContext *cct = ictx->cct;
+    ldout(cct, 20) << __func__ << ": ictx=" << ictx << dendl;
+    if (status_size < sizeof(mirror_image_status_t)) {
+      return -ERANGE;
+    }
+
+    cls::rbd::MirrorImageStatus
+      s(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found");
+
+    cls::rbd::MirrorImage image;
+    int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &image);
+    if (r < 0 && r != -ENOENT) {
+      lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r)
+                << dendl;
+      return r;
+    }
+
+    if (r == 0) {
+      r = cls_client::mirror_image_status_get(&ictx->md_ctx,
+                                             image.global_image_id, &s);
+      if (r < 0 && r != -ENOENT) {
+       lderr(cct) << "failed to retrieve image mirror status: "
+                  << cpp_strerror(r) << dendl;
+       return r;
+      }
+    }
+
+    *status = mirror_image_status_t{
+      static_cast<mirror_image_status_state_t>(s.state),
+      s.description,
+      s.last_update.sec(),
+      s.up};
+    return 0;
+  }
+
   int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) {
     CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
     ldout(cct, 20) << __func__ << dendl;
@@ -3242,6 +3279,80 @@ remove_mirroring_image:
     return 0;
   }
 
+  int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+      size_t max, std::map<std::string, mirror_image_info_t> *images,
+      std::map<std::string, mirror_image_status_t> *statuses) {
+    CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+    int r;
+
+    map<string, string> id_to_name;
+    {
+      map<string, string> name_to_id;
+      r = list_images_v2(io_ctx, name_to_id);
+      if (r < 0) {
+       return r;
+      }
+      for (auto it : name_to_id) {
+       id_to_name[it.second] = it.first;
+      }
+    }
+
+    map<std::string, cls::rbd::MirrorImage> images_;
+    map<std::string, cls::rbd::MirrorImageStatus> statuses_;
+
+    r = librbd::cls_client::mirror_image_status_list(&io_ctx, start, max,
+                                                    &images_, &statuses_);
+    if (r < 0) {
+      lderr(cct) << "Failed to list mirror image statuses: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    cls::rbd::MirrorImageStatus
+      unknown_status(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found");
+
+    for (auto it = images_.begin(); it != images_.end(); ++it) {
+      auto &image_id = it->first;
+      auto &info = it->second;
+      auto &image_name = id_to_name[image_id];
+      if (image_name.empty()) {
+       lderr(cct) << "Failed to find image name for image " << image_id
+                  << ", using image id as name" << dendl;
+       image_name = image_id;
+      }
+      (*images)[image_name] = mirror_image_info_t{
+       info.global_image_id,
+       static_cast<mirror_image_state_t>(info.state),
+       false}; // XXX: To set "primary" properly would require additional call.
+      auto s_it = statuses_.find(image_id);
+      auto &s = s_it != statuses_.end() ? s_it->second : unknown_status;
+      (*statuses)[image_name] = mirror_image_status_t{
+       static_cast<mirror_image_status_state_t>(s.state),
+       s.description,
+       s.last_update.sec(),
+       s.up};
+    }
+
+    return 0;
+  }
+
+  int mirror_image_status_summary(IoCtx& io_ctx,
+    std::map<mirror_image_status_state_t, int> *states) {
+    CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+
+    std::map<cls::rbd::MirrorImageStatusState, int> states_;
+    int r = cls_client::mirror_image_status_get_summary(&io_ctx, &states_);
+    if (r < 0) {
+      lderr(cct) << "Failed to get mirror status summary: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    }
+    for (auto &s : states_) {
+      (*states)[static_cast<mirror_image_status_state_t>(s.first)] = s.second;
+    }
+    return 0;
+  }
+
   void rbd_req_cb(completion_t cb, void *arg)
   {
     AioObjectRequest *req = reinterpret_cast<AioObjectRequest *>(arg);
index c2413f4e0695083cb0bb802ebebc85c0d63a6192..c58c5f2c3d27087c61577962a1bcd07822652a8e 100644 (file)
@@ -189,6 +189,11 @@ namespace librbd {
                              const std::string &client_name);
   int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
                               const std::string &cluster_name);
+  int mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+      size_t max, std::map<std::string, mirror_image_info_t> *images,
+      std::map<std::string, mirror_image_status_t> *statuses);
+  int mirror_image_status_summary(IoCtx& io_ctx,
+      std::map<mirror_image_status_state_t, int> *states);
 
   int mirror_image_enable(ImageCtx *ictx);
   int mirror_image_disable(ImageCtx *ictx, bool force);
@@ -197,6 +202,8 @@ namespace librbd {
   int mirror_image_resync(ImageCtx *ictx);
   int mirror_image_get_info(ImageCtx *ictx, mirror_image_info_t *mirror_image_info,
                             size_t info_size);
+  int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status,
+                             size_t status_size);
 }
 
 #endif
index 0cc3f9521650171e86c2eb51a45989a744f304df..339bbf367f6d5039166331f5608b05e48dd37b3a 100644 (file)
@@ -132,6 +132,21 @@ struct C_CloseComplete : public Context {
   }
 };
 
+void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
+                               rbd_mirror_image_info_t *c_info) {
+  c_info->global_id = strdup(cpp_info.global_id.c_str());
+  c_info->state = cpp_info.state;
+  c_info->primary = cpp_info.primary;
+}
+
+void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_status,
+                                 rbd_mirror_image_status_t *c_status) {
+  c_status->state = cpp_status.state;
+  c_status->description = strdup(cpp_status.description.c_str());
+  c_status->last_update = cpp_status.last_update;
+  c_status->up = cpp_status.up;
+}
+
 } // anonymous namespace
 
 namespace librbd {
@@ -411,6 +426,18 @@ namespace librbd {
     return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name);
   }
 
+  int RBD::mirror_image_status_list(IoCtx& io_ctx, const std::string &start,
+      size_t max, std::map<std::string, mirror_image_info_t> *images,
+      std::map<std::string, mirror_image_status_t> *statuses) {
+    return librbd::mirror_image_status_list(io_ctx, start, max, images,
+                                           statuses);
+  }
+
+  int RBD::mirror_image_status_summary(IoCtx& io_ctx,
+      std::map<mirror_image_status_state_t, int> *states) {
+    return librbd::mirror_image_status_summary(io_ctx, states);
+  }
+
   RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
   {
     pc = reinterpret_cast<void*>(librbd::AioCompletion::create(
@@ -1258,6 +1285,13 @@ namespace librbd {
     return librbd::mirror_image_get_info(ictx, mirror_image_info, info_size);
   }
 
+  int Image::mirror_image_get_status(mirror_image_status_t *mirror_image_status,
+                                    size_t status_size) {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    return librbd::mirror_image_get_status(ictx, mirror_image_status,
+                                          status_size);
+  }
+
 } // namespace librbd
 
 extern "C" void rbd_version(int *major, int *minor, int *extra)
@@ -1425,6 +1459,58 @@ extern "C" int rbd_mirror_peer_set_cluster(rados_ioctx_t p, const char *uuid,
   return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name);
 }
 
+extern "C" int rbd_mirror_image_status_list(rados_ioctx_t p, const char *start,
+    size_t max, char **image_names, rbd_mirror_image_info_t *images,
+    rbd_mirror_image_status_t *statuses, size_t *len) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  std::map<std::string, librbd::mirror_image_info_t> cpp_images;
+  std::map<std::string, librbd::mirror_image_status_t> cpp_statuses;
+
+  int r = librbd::mirror_image_status_list(io_ctx, start, max, &cpp_images,
+                                          &cpp_statuses);
+  if (r < 0) {
+    return r;
+  }
+
+  size_t i = 0;
+  for (auto &it : cpp_images) {
+    assert(i < max);
+    const std::string &image_name = it.first;
+    image_names[i] = strdup(image_name.c_str());
+    mirror_image_info_cpp_to_c(it.second, &images[i]);
+    mirror_image_status_cpp_to_c(cpp_statuses[image_name], &statuses[i]);
+    i++;
+  }
+  *len = i;
+  return 0;
+}
+
+extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p,
+    rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) {
+
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+
+  std::map<librbd::mirror_image_status_state_t, int> states_;
+  int r = librbd::mirror_image_status_summary(io_ctx, &states_);
+  if (r < 0) {
+    return r;
+  }
+
+  size_t i = 0;
+  for (auto &it : states_) {
+    if (i == *maxlen) {
+      return -ERANGE;
+    }
+    states[i] = it.first;
+    counts[i] = it.second;
+    i++;
+  }
+  *maxlen = i;
+  return 0;
+}
+
 /* images */
 extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
 {
@@ -2628,9 +2714,24 @@ extern "C" int rbd_mirror_image_get_info(rbd_image_t image,
     return r;
   }
 
-  mirror_image_info->global_id = strdup(cpp_mirror_image.global_id.c_str());
-  mirror_image_info->state = cpp_mirror_image.state;
-  mirror_image_info->primary = cpp_mirror_image.primary;
+  mirror_image_info_cpp_to_c(cpp_mirror_image, mirror_image_info);
+  return 0;
+}
+
+extern "C" int rbd_mirror_image_get_status(rbd_image_t image,
+                                          rbd_mirror_image_status_t *status,
+                                          size_t status_size)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+
+  librbd::mirror_image_status_t cpp_status;
+  int r = librbd::mirror_image_get_status(ictx, &cpp_status,
+                                         sizeof(cpp_status));
+  if (r < 0) {
+    return r;
+  }
+
+  mirror_image_status_cpp_to_c(cpp_status, status);
   return 0;
 }
 
index e7ccf3f8473c30c839eb5b26bc41160adb48f92c..75514dd0e8880ec56f17df74d4e14616d1644e88 100644 (file)
@@ -68,6 +68,10 @@ public:
     ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
     ASSERT_EQ(mirror_state, mirror_image.state);
 
+    librbd::mirror_image_status_t status;
+    ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+    ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
     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));
@@ -93,17 +97,42 @@ public:
     ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
     ASSERT_EQ(mirror_state, mirror_image.state);
 
+    librbd::mirror_image_status_t status;
+    ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+    ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
     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));
   }
 
+  void check_mirroring_status(size_t *images_count) {
+    std::map<std::string, librbd::mirror_image_info_t> images;
+    std::map<std::string, librbd::mirror_image_status_t> statuses;
+    ASSERT_EQ(0, m_rbd.mirror_image_status_list(m_ioctx, "", 4096, &images,
+           &statuses));
+    ASSERT_EQ(images.size(), statuses.size());
+
+    std::map<librbd::mirror_image_status_state_t, int> states;
+    ASSERT_EQ(0, m_rbd.mirror_image_status_summary(m_ioctx, &states));
+    size_t states_count = 0;
+    for (auto &s : states) {
+      states_count += s.second;
+    }
+    ASSERT_EQ(images.size(), states_count);
+
+    *images_count = images.size();
+  }
+
   void check_mirroring_on_create(uint64_t features,
                                  rbd_mirror_mode_t mirror_mode,
                                  rbd_mirror_image_state_t mirror_state) {
 
     ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, mirror_mode));
 
+    size_t mirror_images_count = 0;
+    check_mirroring_status(&mirror_images_count);
+
     int order = 20;
     ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 4096, features, &order));
     librbd::Image image;
@@ -113,9 +142,25 @@ public:
     ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
     ASSERT_EQ(mirror_state, mirror_image.state);
 
+    librbd::mirror_image_status_t status;
+    ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+    ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
+    size_t mirror_images_new_count = 0;
+    check_mirroring_status(&mirror_images_new_count);
+    if (mirror_mode == RBD_MIRROR_MODE_POOL &&
+       mirror_state == RBD_MIRROR_IMAGE_ENABLED) {
+      ASSERT_EQ(mirror_images_new_count, mirror_images_count + 1);
+    } else {
+      ASSERT_EQ(mirror_images_new_count, mirror_images_count);
+    }
+
     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));
+
+    check_mirroring_status(&mirror_images_new_count);
+    ASSERT_EQ(mirror_images_new_count, mirror_images_count);
   }
 
   void check_mirroring_on_update_features(uint64_t init_features,
@@ -141,6 +186,10 @@ public:
     ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
     ASSERT_EQ(mirror_state, mirror_image.state);
 
+    librbd::mirror_image_status_t status;
+    ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+    ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
     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));
@@ -180,6 +229,10 @@ public:
       ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)));
       ASSERT_EQ(mirror_state, mirror_image.state);
 
+      librbd::mirror_image_status_t status;
+      ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status)));
+      ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state);
+
       ASSERT_EQ(0, image.close());
       ASSERT_EQ(0, m_rbd.remove(m_ioctx, img_name_str.c_str()));
     }