]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cls::rbd:: methods to store/retrieve mirroring status
authorMykola Golub <mgolub@mirantis.com>
Tue, 5 Apr 2016 11:24:07 +0000 (14:24 +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/cls/rbd/cls_rbd.cc
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/cls/rbd/cls_rbd_types.cc
src/cls/rbd/cls_rbd_types.h

index ad7d6b1a39c1f5ffb22cfda87f187f7fc1e29f60..1b38eabfbe1903e2cb55590ed46554bebeb11377 100644 (file)
@@ -40,6 +40,7 @@
 #include "common/bit_vector.hpp"
 #include "common/errno.h"
 #include "objclass/objclass.h"
+#include "osd/osd_types.h"
 #include "include/rbd_types.h"
 #include "include/rbd/object_map_types.h"
 
@@ -125,6 +126,12 @@ cls_method_handle_t h_mirror_image_get_image_id;
 cls_method_handle_t h_mirror_image_get;
 cls_method_handle_t h_mirror_image_set;
 cls_method_handle_t h_mirror_image_remove;
+cls_method_handle_t h_mirror_image_status_set;
+cls_method_handle_t h_mirror_image_status_remove;
+cls_method_handle_t h_mirror_image_status_get;
+cls_method_handle_t h_mirror_image_status_list;
+cls_method_handle_t h_mirror_image_status_get_summary;
+cls_method_handle_t h_mirror_image_status_remove_down;
 
 #define RBD_MAX_KEYS_READ 64
 #define RBD_SNAP_KEY_PREFIX "snapshot_"
@@ -2965,6 +2972,7 @@ static const std::string MODE("mirror_mode");
 static const std::string PEER_KEY_PREFIX("mirror_peer_");
 static const std::string IMAGE_KEY_PREFIX("image_");
 static const std::string GLOBAL_KEY_PREFIX("global_");
+static const std::string STATUS_GLOBAL_KEY_PREFIX("status_global_");
 
 std::string peer_key(const std::string &uuid) {
   return PEER_KEY_PREFIX + uuid;
@@ -2978,6 +2986,10 @@ std::string global_key(const string &global_id) {
   return GLOBAL_KEY_PREFIX + global_id;
 }
 
+std::string status_global_key(const string &global_id) {
+  return STATUS_GLOBAL_KEY_PREFIX + global_id;
+}
+
 int uuid_get(cls_method_context_t hctx, std::string *mirror_uuid) {
   bufferlist mirror_uuid_bl;
   int r = cls_cxx_map_get_val(hctx, mirror::UUID, &mirror_uuid_bl);
@@ -3162,6 +3174,296 @@ int image_remove(cls_method_context_t hctx, const string &image_id) {
   return 0;
 }
 
+struct MirrorImageStatusOnDisk : cls::rbd::MirrorImageStatus {
+  entity_inst_t origin;
+
+  MirrorImageStatusOnDisk() {
+  }
+  MirrorImageStatusOnDisk(const cls::rbd::MirrorImageStatus &status) :
+    cls::rbd::MirrorImageStatus(status) {
+  }
+
+  void encode_meta(bufferlist &bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(origin, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void encode(bufferlist &bl) const {
+    encode_meta(bl);
+    cls::rbd::MirrorImageStatus::encode(bl);
+  }
+
+  void decode_meta(bufferlist::iterator &it) {
+    DECODE_START(1, it);
+    ::decode(origin, it);
+    DECODE_FINISH(it);
+  }
+
+  void decode(bufferlist::iterator &it) {
+    decode_meta(it);
+    cls::rbd::MirrorImageStatus::decode(it);
+  }
+};
+WRITE_CLASS_ENCODER(MirrorImageStatusOnDisk)
+
+int image_status_set(cls_method_context_t hctx, const string &global_image_id,
+                    const cls::rbd::MirrorImageStatus &status) {
+  MirrorImageStatusOnDisk ondisk_status(status);
+  ondisk_status.up = false;
+  ondisk_status.last_update = ceph_clock_now(g_ceph_context);
+
+  int r = cls_get_request_origin(hctx, &ondisk_status.origin);
+  assert(r == 0);
+
+  bufferlist bl;
+  encode(ondisk_status, bl);
+
+  r = cls_cxx_map_set_val(hctx, status_global_key(global_image_id), &bl);
+  if (r < 0) {
+    CLS_ERR("error setting status for mirrored image, global id '%s': %s",
+           global_image_id.c_str(), cpp_strerror(r).c_str());
+    return r;
+  }
+  return 0;
+}
+
+int image_status_remove(cls_method_context_t hctx,
+                       const string &global_image_id) {
+
+  int r = cls_cxx_map_remove_key(hctx, status_global_key(global_image_id));
+  if (r < 0) {
+    CLS_ERR("error removing status for mirrored image, global id '%s': %s",
+           global_image_id.c_str(), cpp_strerror(r).c_str());
+    return r;
+  }
+  return 0;
+}
+
+int image_status_get(cls_method_context_t hctx, const string &global_image_id,
+                    cls::rbd::MirrorImageStatus *status) {
+
+  bufferlist bl;
+  int r = cls_cxx_map_get_val(hctx, status_global_key(global_image_id), &bl);
+  if (r < 0) {
+    if (r != -ENOENT) {
+      CLS_ERR("error reading status for mirrored image, global id '%s': '%s'",
+             global_image_id.c_str(), cpp_strerror(r).c_str());
+    }
+    return r;
+  }
+
+  MirrorImageStatusOnDisk ondisk_status;
+  try {
+    bufferlist::iterator it = bl.begin();
+    decode(ondisk_status, it);
+  } catch (const buffer::error &err) {
+    CLS_ERR("could not decode status for mirrored image, global id '%s'",
+           global_image_id.c_str());
+    return -EIO;
+  }
+
+  obj_list_watch_response_t watchers;
+  r = cls_cxx_list_watchers(hctx, &watchers);
+  if (r < 0 && r != -ENOENT) {
+    CLS_ERR("error listing watchers: '%s'", cpp_strerror(r).c_str());
+    return r;
+  }
+
+  *status = static_cast<cls::rbd::MirrorImageStatus>(ondisk_status);
+  status->up = false;
+  for (auto &w : watchers.entries) {
+    if (w.name == ondisk_status.origin.name &&
+       w.addr == ondisk_status.origin.addr) {
+      status->up = true;
+      break;
+    }
+  }
+
+  return 0;
+}
+
+int image_status_list(cls_method_context_t hctx,
+       const std::string &start_after, uint64_t max_return,
+       map<std::string, cls::rbd::MirrorImage> *mirror_images,
+        map<std::string, cls::rbd::MirrorImageStatus> *mirror_statuses) {
+  std::string last_read = image_key(start_after);
+  int max_read = RBD_MAX_KEYS_READ;
+  int r = max_read;
+
+  while (r == max_read && mirror_images->size() < max_return) {
+    std::map<std::string, bufferlist> vals;
+    CLS_LOG(20, "last_read = '%s'", last_read.c_str());
+    r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX, max_read,
+                            &vals);
+    if (r < 0) {
+      CLS_ERR("error reading mirror image directory by name: %s",
+              cpp_strerror(r).c_str());
+      return r;
+    }
+
+    for (auto it = vals.begin(); it != vals.end() &&
+          mirror_images->size() < max_return; ++it) {
+      const std::string &image_id = it->first.substr(IMAGE_KEY_PREFIX.size());
+      cls::rbd::MirrorImage mirror_image;
+      bufferlist::iterator iter = it->second.begin();
+      try {
+       ::decode(mirror_image, iter);
+      } catch (const buffer::error &err) {
+       CLS_ERR("could not decode mirror image payload of image '%s'",
+                image_id.c_str());
+       return -EIO;
+      }
+
+      (*mirror_images)[image_id] = mirror_image;
+
+      cls::rbd::MirrorImageStatus status;
+      r = image_status_get(hctx, mirror_image.global_image_id, &status);
+      if (r < 0) {
+       continue;
+      }
+
+      (*mirror_statuses)[image_id] = status;
+    }
+    if (!vals.empty()) {
+      last_read = image_key(mirror_images->rbegin()->first);
+    }
+  }
+
+  return 0;
+}
+
+int image_status_get_summary(cls_method_context_t hctx,
+       std::map<cls::rbd::MirrorImageStatusState, int> *states) {
+  obj_list_watch_response_t watchers_;
+  int r = cls_cxx_list_watchers(hctx, &watchers_);
+  if (r < 0) {
+    if (r != -ENOENT) {
+      CLS_ERR("error listing watchers: '%s'", cpp_strerror(r).c_str());
+    }
+    return r;
+  }
+
+  set<entity_inst_t> watchers;
+  for (auto &w : watchers_.entries) {
+    watchers.insert(entity_inst_t(w.name, w.addr));
+  }
+
+  states->clear();
+
+  string last_read = IMAGE_KEY_PREFIX;
+  int max_read = RBD_MAX_KEYS_READ;
+  r = max_read;
+  while (r == max_read) {
+    map<string, bufferlist> vals;
+    r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX,
+                            max_read, &vals);
+    if (r < 0) {
+      CLS_ERR("error reading mirrored images: %s", cpp_strerror(r).c_str());
+      return r;
+    }
+
+    for (auto &list_it : vals) {
+      const string &key = list_it.first;
+
+      if (0 != key.compare(0, IMAGE_KEY_PREFIX.size(), IMAGE_KEY_PREFIX)) {
+       break;
+      }
+
+      cls::rbd::MirrorImage mirror_image;
+      bufferlist::iterator iter = list_it.second.begin();
+      try {
+       ::decode(mirror_image, iter);
+      } catch (const buffer::error &err) {
+       CLS_ERR("could not decode mirror image payload for key '%s'",
+                key.c_str());
+       return -EIO;
+      }
+
+      cls::rbd::MirrorImageStatus status;
+      r = image_status_get(hctx, mirror_image.global_image_id, &status);
+      if (r < 0) {
+       // Ignore.
+      }
+
+      cls::rbd::MirrorImageStatusState state = status.up ? status.state :
+       cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN;
+      (*states)[state]++;
+    }
+
+    if (!vals.empty()) {
+      last_read = vals.rbegin()->first;
+    }
+  }
+
+  return 0;
+}
+
+int image_status_remove_down(cls_method_context_t hctx) {
+  obj_list_watch_response_t watchers_;
+  int r = cls_cxx_list_watchers(hctx, &watchers_);
+  if (r < 0) {
+    if (r != -ENOENT) {
+      CLS_ERR("error listing watchers: '%s'", cpp_strerror(r).c_str());
+    }
+    return r;
+  }
+
+  set<entity_inst_t> watchers;
+  for (auto &w : watchers_.entries) {
+    watchers.insert(entity_inst_t(w.name, w.addr));
+  }
+
+  string last_read = STATUS_GLOBAL_KEY_PREFIX;
+  int max_read = RBD_MAX_KEYS_READ;
+  r = max_read;
+  while (r == max_read) {
+    map<string, bufferlist> vals;
+    r = cls_cxx_map_get_vals(hctx, last_read, STATUS_GLOBAL_KEY_PREFIX,
+                            max_read, &vals);
+    if (r < 0) {
+      CLS_ERR("error reading mirrored images: %s", cpp_strerror(r).c_str());
+      return r;
+    }
+
+    for (auto &list_it : vals) {
+      const string &key = list_it.first;
+
+      if (0 != key.compare(0, STATUS_GLOBAL_KEY_PREFIX.size(),
+                          STATUS_GLOBAL_KEY_PREFIX)) {
+       break;
+      }
+
+      MirrorImageStatusOnDisk status;
+      try {
+       bufferlist::iterator it = list_it.second.begin();
+       status.decode_meta(it);
+      } catch (const buffer::error &err) {
+       CLS_ERR("could not decode status metadata for mirrored image '%s'",
+               key.c_str());
+       return -EIO;
+      }
+
+      if (watchers.find(status.origin) == watchers.end()) {
+       CLS_LOG(20, "removing stale status object for key %s",
+               key.c_str());
+       int r1 = cls_cxx_map_remove_key(hctx, key);
+       if (r1 < 0) {
+         CLS_ERR("error removing stale status for key '%s': %s",
+                 key.c_str(), cpp_strerror(r1).c_str());
+         return r1;
+       }
+      }
+    }
+
+    if (!vals.empty()) {
+      last_read = vals.rbegin()->first;
+    }
+  }
+
+  return 0;
+}
+
 } // namespace mirror
 
 /**
@@ -3676,6 +3978,158 @@ int mirror_image_remove(cls_method_context_t hctx, bufferlist *in,
   return 0;
 }
 
+/**
+ * Input:
+ * @param global_image_id (std::string)
+ * @param status (cls::rbd::MirrorImageStatus)
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_set(cls_method_context_t hctx, bufferlist *in,
+                           bufferlist *out) {
+  string global_image_id;
+  cls::rbd::MirrorImageStatus status;
+  try {
+    bufferlist::iterator it = in->begin();
+    ::decode(global_image_id, it);
+    ::decode(status, it);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  int r = mirror::image_status_set(hctx, global_image_id, status);
+  if (r < 0) {
+    return r;
+  }
+  return 0;
+}
+
+/**
+ * Input:
+ * @param global_image_id (std::string)
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_remove(cls_method_context_t hctx, bufferlist *in,
+                              bufferlist *out) {
+  string global_image_id;
+  try {
+    bufferlist::iterator it = in->begin();
+    ::decode(global_image_id, it);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  int r = mirror::image_status_remove(hctx, global_image_id);
+  if (r < 0) {
+    return r;
+  }
+  return 0;
+}
+
+/**
+ * Input:
+ * @param global_image_id (std::string)
+ *
+ * Output:
+ * @param cls::rbd::MirrorImageStatus - metadata associated with the global_image_id
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_get(cls_method_context_t hctx, bufferlist *in,
+                           bufferlist *out) {
+  string global_image_id;
+  try {
+    bufferlist::iterator it = in->begin();
+    ::decode(global_image_id, it);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  cls::rbd::MirrorImageStatus status;
+  int r = mirror::image_status_get(hctx, global_image_id, &status);
+  if (r < 0) {
+    return r;
+  }
+
+  ::encode(status, *out);
+  return 0;
+}
+
+/**
+ * Input:
+ * @param start_after which name to begin listing after
+ *        (use the empty string to start at the beginning)
+ * @param max_return the maximum number of names to list
+ *
+ * Output:
+ * @param std::map<std::string, cls::rbd::MirrorImage>: image id to image map
+ * @param std::map<std::string, cls::rbd::MirrorImageStatus>: image it to status map
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_list(cls_method_context_t hctx, bufferlist *in,
+                            bufferlist *out) {
+  std::string start_after;
+  uint64_t max_return;
+  try {
+    bufferlist::iterator iter = in->begin();
+    ::decode(start_after, iter);
+    ::decode(max_return, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  map<std::string, cls::rbd::MirrorImage> images;
+  map<std::string, cls::rbd::MirrorImageStatus> statuses;
+  int r = mirror::image_status_list(hctx, start_after, max_return, &images,
+                                   &statuses);
+  if (r < 0) {
+    return r;
+  }
+
+  ::encode(images, *out);
+  ::encode(statuses, *out);
+  return 0;
+}
+
+/**
+ * Input:
+ * none
+ *
+ * Output:
+ * @param std::map<cls::rbd::MirrorImageStatusState, int>: states counts
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_get_summary(cls_method_context_t hctx, bufferlist *in,
+                                   bufferlist *out) {
+  std::map<cls::rbd::MirrorImageStatusState, int> states;
+
+  int r = mirror::image_status_get_summary(hctx, &states);
+  if (r < 0) {
+    return r;
+  }
+
+  ::encode(states, *out);
+  return 0;
+}
+
+/**
+ * Input:
+ * none
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_image_status_remove_down(cls_method_context_t hctx, bufferlist *in,
+                                   bufferlist *out) {
+  int r = mirror::image_status_remove_down(hctx);
+  if (r < 0) {
+    return r;
+  }
+  return 0;
+}
+
 void __cls_init()
 {
   CLS_LOG(20, "Loaded rbd class!");
@@ -3871,5 +4325,24 @@ void __cls_init()
   cls_register_cxx_method(h_class, "mirror_image_remove",
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           mirror_image_remove, &h_mirror_image_remove);
+  cls_register_cxx_method(h_class, "mirror_image_status_set",
+                          CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE,
+                          mirror_image_status_set, &h_mirror_image_status_set);
+  cls_register_cxx_method(h_class, "mirror_image_status_remove",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          mirror_image_status_remove,
+                         &h_mirror_image_status_remove);
+  cls_register_cxx_method(h_class, "mirror_image_status_get", CLS_METHOD_RD,
+                          mirror_image_status_get, &h_mirror_image_status_get);
+  cls_register_cxx_method(h_class, "mirror_image_status_list", CLS_METHOD_RD,
+                          mirror_image_status_list,
+                         &h_mirror_image_status_list);
+  cls_register_cxx_method(h_class, "mirror_image_status_get_summary",
+                         CLS_METHOD_RD, mirror_image_status_get_summary,
+                         &h_mirror_image_status_get_summary);
+  cls_register_cxx_method(h_class, "mirror_image_status_remove_down",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          mirror_image_status_remove_down,
+                         &h_mirror_image_status_remove_down);
   return;
 }
index 5fe8452028a9fe0f49eea24aea9c488a82e7f6e6..ec57f7f8daae2faba81896d7818568132d28f381 100644 (file)
@@ -1236,5 +1236,163 @@ namespace librbd {
       return 0;
     }
 
+    int mirror_image_status_set(librados::IoCtx *ioctx,
+                               const std::string &global_image_id,
+                               const cls::rbd::MirrorImageStatus &status) {
+      librados::ObjectWriteOperation op;
+      mirror_image_status_set(&op, global_image_id, status);
+      return ioctx->operate(RBD_MIRRORING, &op);
+    }
+
+    void mirror_image_status_set(librados::ObjectWriteOperation *op,
+                                const std::string &global_image_id,
+                                const cls::rbd::MirrorImageStatus &status) {
+      bufferlist bl;
+      ::encode(global_image_id, bl);
+      ::encode(status, bl);
+      op->exec("rbd", "mirror_image_status_set", bl);
+    }
+
+    int mirror_image_status_remove(librados::IoCtx *ioctx,
+                                  const std::string &global_image_id) {
+      librados::ObjectWriteOperation op;
+      mirror_image_status_remove(&op, global_image_id);
+      return ioctx->operate(RBD_MIRRORING, &op);
+    }
+
+    void mirror_image_status_remove(librados::ObjectWriteOperation *op,
+                                   const std::string &global_image_id) {
+      bufferlist bl;
+      ::encode(global_image_id, bl);
+      op->exec("rbd", "mirror_image_status_remove", bl);
+    }
+
+    int mirror_image_status_get(librados::IoCtx *ioctx,
+                               const std::string &global_image_id,
+                               cls::rbd::MirrorImageStatus *status) {
+      librados::ObjectReadOperation op;
+      mirror_image_status_get_start(&op, global_image_id);
+
+      bufferlist out_bl;
+      int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl);
+      if (r < 0) {
+       return r;
+      }
+
+      bufferlist::iterator iter = out_bl.begin();
+      r = mirror_image_status_get_finish(&iter, status);
+      if (r < 0) {
+       return r;
+      }
+      return 0;
+    }
+
+    void mirror_image_status_get_start(librados::ObjectReadOperation *op,
+                                      const std::string &global_image_id) {
+      bufferlist bl;
+      ::encode(global_image_id, bl);
+      op->exec("rbd", "mirror_image_status_get", bl);
+    }
+
+    int mirror_image_status_get_finish(bufferlist::iterator *iter,
+                                      cls::rbd::MirrorImageStatus *status) {
+      try {
+       ::decode(*status, *iter);
+      } catch (const buffer::error &err) {
+       return -EBADMSG;
+      }
+      return 0;
+    }
+
+    int mirror_image_status_list(librados::IoCtx *ioctx,
+       const std::string &start, uint64_t max_return,
+       std::map<std::string, cls::rbd::MirrorImage> *images,
+       std::map<std::string, cls::rbd::MirrorImageStatus> *statuses) {
+      librados::ObjectReadOperation op;
+      mirror_image_status_list_start(&op, start, max_return);
+
+      bufferlist out_bl;
+      int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl);
+      if (r < 0) {
+       return r;
+      }
+
+      bufferlist::iterator iter = out_bl.begin();
+      r = mirror_image_status_list_finish(&iter, images, statuses);
+      if (r < 0) {
+       return r;
+      }
+      return 0;
+    }
+
+    void mirror_image_status_list_start(librados::ObjectReadOperation *op,
+                                       const std::string &start,
+                                       uint64_t max_return) {
+      bufferlist bl;
+      ::encode(start, bl);
+      ::encode(max_return, bl);
+      op->exec("rbd", "mirror_image_status_list", bl);
+    }
+
+    int mirror_image_status_list_finish(bufferlist::iterator *iter,
+       std::map<std::string, cls::rbd::MirrorImage> *images,
+       std::map<std::string, cls::rbd::MirrorImageStatus> *statuses) {
+      images->clear();
+      statuses->clear();
+      try {
+       ::decode(*images, *iter);
+       ::decode(*statuses, *iter);
+      } catch (const buffer::error &err) {
+       return -EBADMSG;
+      }
+      return 0;
+    }
+
+    int mirror_image_status_get_summary(librados::IoCtx *ioctx,
+       std::map<cls::rbd::MirrorImageStatusState, int> *states) {
+      librados::ObjectReadOperation op;
+      mirror_image_status_get_summary_start(&op);
+
+      bufferlist out_bl;
+      int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl);
+      if (r < 0) {
+       return r;
+      }
+
+      bufferlist::iterator iter = out_bl.begin();
+      r = mirror_image_status_get_summary_finish(&iter, states);
+      if (r < 0) {
+       return r;
+      }
+      return 0;
+    }
+
+    void mirror_image_status_get_summary_start(
+      librados::ObjectReadOperation *op) {
+      bufferlist bl;
+      op->exec("rbd", "mirror_image_status_get_summary", bl);
+    }
+
+    int mirror_image_status_get_summary_finish(bufferlist::iterator *iter,
+       std::map<cls::rbd::MirrorImageStatusState, int> *states) {
+      try {
+       ::decode(*states, *iter);
+      } catch (const buffer::error &err) {
+       return -EBADMSG;
+      }
+      return 0;
+    }
+
+    int mirror_image_status_remove_down(librados::IoCtx *ioctx) {
+      librados::ObjectWriteOperation op;
+      mirror_image_status_remove_down(&op);
+      return ioctx->operate(RBD_MIRRORING, &op);
+    }
+
+    void mirror_image_status_remove_down(librados::ObjectWriteOperation *op) {
+      bufferlist bl;
+      op->exec("rbd", "mirror_image_status_remove_down", bl);
+    }
+
   } // namespace cls_client
 } // namespace librbd
index 8bc8ee2b98a733f5fe0a827a04a0ce7e283cff1b..b3dd22eb3753b22309f91179edb34fa71ac7bcee 100644 (file)
@@ -243,6 +243,40 @@ namespace librbd {
                         const cls::rbd::MirrorImage &mirror_image);
     int mirror_image_remove(librados::IoCtx *ioctx,
                            const std::string &image_id);
+    int mirror_image_status_set(librados::IoCtx *ioctx,
+                               const std::string &global_image_id,
+                               const cls::rbd::MirrorImageStatus &status);
+    void mirror_image_status_set(librados::ObjectWriteOperation *op,
+                                const std::string &global_image_id,
+                                const cls::rbd::MirrorImageStatus &status);
+    int mirror_image_status_remove(librados::IoCtx *ioctx,
+                                  const std::string &global_image_id);
+    void mirror_image_status_remove(librados::ObjectWriteOperation *op,
+                                   const std::string &global_image_id);
+    int mirror_image_status_get(librados::IoCtx *ioctx,
+                               const std::string &global_image_id,
+                               cls::rbd::MirrorImageStatus *status);
+    void mirror_image_status_get_start(librados::ObjectReadOperation *op,
+                                      const std::string &global_image_id);
+    int mirror_image_status_get_finish(bufferlist::iterator *iter,
+                                      cls::rbd::MirrorImageStatus *status);
+    int mirror_image_status_list(librados::IoCtx *ioctx,
+       const std::string &start, uint64_t max_return,
+       std::map<std::string, cls::rbd::MirrorImage> *images,
+       std::map<std::string, cls::rbd::MirrorImageStatus> *statuses);
+    void mirror_image_status_list_start(librados::ObjectReadOperation *op,
+                                       const std::string &start,
+                                       uint64_t max_return);
+    int mirror_image_status_list_finish(bufferlist::iterator *iter,
+       std::map<std::string, cls::rbd::MirrorImage> *images,
+       std::map<std::string, cls::rbd::MirrorImageStatus> *statuses);
+    int mirror_image_status_get_summary(librados::IoCtx *ioctx,
+       std::map<cls::rbd::MirrorImageStatusState, int> *states);
+    void mirror_image_status_get_summary_start(librados::ObjectReadOperation *op);
+    int mirror_image_status_get_summary_finish(bufferlist::iterator *iter,
+       std::map<cls::rbd::MirrorImageStatusState, int> *states);
+    int mirror_image_status_remove_down(librados::IoCtx *ioctx);
+    void mirror_image_status_remove_down(librados::ObjectWriteOperation *op);
 
   } // namespace cls_client
 } // namespace librbd
index 3f68522468abc4ab08b866218ea968c470f5e431..5891e566a2a5038c2d92a0e18d2d727dcf7d2ee2 100644 (file)
@@ -105,6 +105,11 @@ bool MirrorImage::operator==(const MirrorImage &rhs) const {
   return global_image_id == rhs.global_image_id && state == rhs.state;
 }
 
+bool MirrorImage::operator<(const MirrorImage &rhs) const {
+  return global_image_id < rhs.global_image_id ||
+       (global_image_id == rhs.global_image_id  && state < rhs.state);
+}
+
 std::ostream& operator<<(std::ostream& os, const MirrorImageState& mirror_state) {
   switch (mirror_state) {
   case MIRROR_IMAGE_STATE_DISABLING:
@@ -127,5 +132,84 @@ std::ostream& operator<<(std::ostream& os, const MirrorImage& mirror_image) {
   return os;
 }
 
+void MirrorImageStatus::encode(bufferlist &bl) const {
+  ENCODE_START(1, 1, bl);
+  ::encode(state, bl);
+  ::encode(description, bl);
+  ::encode(last_update, bl);
+  ::encode(up, bl);
+  ENCODE_FINISH(bl);
+}
+
+void MirrorImageStatus::decode(bufferlist::iterator &it) {
+  DECODE_START(1, it);
+  ::decode(state, it);
+  ::decode(description, it);
+  ::decode(last_update, it);
+  ::decode(up, it);
+  DECODE_FINISH(it);
+}
+
+void MirrorImageStatus::dump(Formatter *f) const {
+  f->dump_string("state", state_to_string());
+  f->dump_string("description", description);
+  f->dump_stream("last_update") << last_update;
+}
+
+std::string MirrorImageStatus::state_to_string() const {
+  std::stringstream ss;
+  ss << (up ? "up+" : "down+") << state;
+  return ss.str();
+}
+
+void MirrorImageStatus::generate_test_instances(
+  std::list<MirrorImageStatus*> &o) {
+  o.push_back(new MirrorImageStatus());
+  o.push_back(new MirrorImageStatus(MIRROR_IMAGE_STATUS_STATE_REPLAYING));
+  o.push_back(new MirrorImageStatus(MIRROR_IMAGE_STATUS_STATE_ERROR, "error"));
+}
+
+bool MirrorImageStatus::operator==(const MirrorImageStatus &rhs) const {
+  return state == rhs.state && description == rhs.description && up == rhs.up;
+}
+
+std::ostream& operator<<(std::ostream& os, const MirrorImageStatusState& state) {
+  switch (state) {
+  case MIRROR_IMAGE_STATUS_STATE_UNKNOWN:
+    os << "unknown";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_ERROR:
+    os << "error";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_SYNCING:
+    os << "syncing";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY:
+    os << "starting_replay";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_REPLAYING:
+    os << "replaying";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY:
+    os << "stopping_replay";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STOPPED:
+    os << "stopped";
+    break;
+  default:
+    os << "unknown (" << static_cast<uint32_t>(state) << ")";
+    break;
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const MirrorImageStatus& status) {
+  os << "["
+     << "state=" << status.state_to_string() << ", "
+     << "description=" << status.description << ", "
+     << "last_update=" << status.last_update << "]";
+  return os;
+}
+
 } // namespace rbd
 } // namespace cls
index e3189146bd98004883dd9137dacaa1b4ac1ba55c..c8780f06820d5eecc42633391661d32ae15ba25e 100644 (file)
@@ -7,6 +7,7 @@
 #include "include/int_types.h"
 #include "include/buffer.h"
 #include "include/encoding.h"
+#include "include/utime.h"
 #include <iosfwd>
 #include <string>
 
@@ -73,6 +74,7 @@ struct MirrorImage {
   static void generate_test_instances(std::list<MirrorImage*> &o);
 
   bool operator==(const MirrorImage &rhs) const;
+  bool operator<(const MirrorImage &rhs) const;
 };
 
 std::ostream& operator<<(std::ostream& os, const MirrorImageState& mirror_state);
@@ -80,6 +82,56 @@ std::ostream& operator<<(std::ostream& os, const MirrorImage& mirror_image);
 
 WRITE_CLASS_ENCODER(MirrorImage);
 
+enum MirrorImageStatusState {
+  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,
+};
+
+inline void encode(const MirrorImageStatusState &state, bufferlist& bl,
+                  uint64_t features=0)
+{
+  ::encode(static_cast<uint8_t>(state), bl);
+}
+
+inline void decode(MirrorImageStatusState &state, bufferlist::iterator& it)
+{
+  uint8_t int_state;
+  ::decode(int_state, it);
+  state = static_cast<MirrorImageStatusState>(int_state);
+}
+
+struct MirrorImageStatus {
+  MirrorImageStatus() {}
+  MirrorImageStatus(MirrorImageStatusState state,
+                   const std::string &description = "")
+    : state(state), description(description) {}
+
+  MirrorImageStatusState state = MIRROR_IMAGE_STATUS_STATE_UNKNOWN;
+  std::string description;
+  utime_t last_update;
+  bool up = false;
+
+  void encode(bufferlist &bl) const;
+  void decode(bufferlist::iterator &it);
+  void dump(Formatter *f) const;
+
+  std::string state_to_string() const;
+
+  static void generate_test_instances(std::list<MirrorImageStatus*> &o);
+
+  bool operator==(const MirrorImageStatus &rhs) const;
+};
+
+std::ostream& operator<<(std::ostream& os, const MirrorImageStatus& status);
+std::ostream& operator<<(std::ostream& os, const MirrorImageStatusState& state);
+
+WRITE_CLASS_ENCODER(MirrorImageStatus);
+
 } // namespace rbd
 } // namespace cls