]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/rbd: expand MirrorPeer to annotate bidirectional relationships
authorJason Dillaman <dillaman@redhat.com>
Thu, 12 Sep 2019 18:45:56 +0000 (14:45 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 8 Oct 2019 15:16:46 +0000 (11:16 -0400)
The legacy MirrorPeer format is a RX direction and still requires
a client name for connecting to the remote peer. The cluster name
has been renamed internally to site name to match the new bootstrap
helper. The TX mode peers will be automatically created by remote
rbd-mirror instances that ping the local cluster.

Signed-off-by: Jason Dillaman <dillaman@redhat.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
src/librbd/api/Mirror.cc
src/test/cls_rbd/test_cls_rbd.cc

index 47815dd19d15d3f8f86cea2b1ff2fe0db3bd6661..7963479ec59a382388a72a87ec52e4a32934d8a3 100644 (file)
@@ -4732,20 +4732,192 @@ int read_peer(cls_method_context_t hctx, const std::string &id,
   return 0;
 }
 
-int write_peer(cls_method_context_t hctx, const std::string &id,
-               const cls::rbd::MirrorPeer &peer) {
+int write_peer(cls_method_context_t hctx, const cls::rbd::MirrorPeer &peer) {
   bufferlist bl;
   encode(peer, bl);
 
-  int r = cls_cxx_map_set_val(hctx, peer_key(id), &bl);
+  int r = cls_cxx_map_set_val(hctx, peer_key(peer.uuid), &bl);
   if (r < 0) {
-    CLS_ERR("error writing peer '%s': %s", id.c_str(),
+    CLS_ERR("error writing peer '%s': %s", peer.uuid.c_str(),
             cpp_strerror(r).c_str());
     return r;
   }
   return 0;
 }
 
+int check_mirroring_enabled(cls_method_context_t hctx) {
+  uint32_t mirror_mode_decode;
+  int r = read_key(hctx, mirror::MODE, &mirror_mode_decode);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  } else if (r == -ENOENT ||
+             mirror_mode_decode == cls::rbd::MIRROR_MODE_DISABLED) {
+    CLS_ERR("mirroring must be enabled on the pool");
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+int peer_ping(cls_method_context_t hctx, const std::string& site_name,
+              const std::string& fsid) {
+  int r = check_mirroring_enabled(hctx);
+  if (r < 0) {
+    return r;
+  }
+
+  if (site_name.empty() || fsid.empty()) {
+    return -EINVAL;
+  }
+
+  std::vector<cls::rbd::MirrorPeer> peers;
+  r = read_peers(hctx, &peers);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  }
+
+
+  cls::rbd::MirrorPeer mirror_peer;
+  auto site_it = std::find_if(peers.begin(), peers.end(),
+                              [&site_name](auto& peer) {
+      return (peer.site_name == site_name);
+    });
+
+  auto fsid_it = peers.end();
+  if (site_it == peers.end() ||
+      (!site_it->fsid.empty() && site_it->fsid != fsid)) {
+    // search for existing peer w/ same fsid
+    fsid_it = std::find_if(peers.begin(), peers.end(),
+                           [&fsid](auto& peer) {
+        return (peer.fsid == fsid);
+      });
+  }
+
+  auto it = peers.end();
+  if (site_it != peers.end() && fsid_it != peers.end()) {
+    // implies two peers -- match by fsid but don't update site name
+    it = fsid_it;
+  } else if (fsid_it != peers.end()) {
+    // implies site name has been updated in remote
+    fsid_it->site_name = site_name;
+    it = fsid_it;
+  } else if (site_it != peers.end()) {
+    // implies empty fsid in peer
+    site_it->fsid = fsid;
+    it = site_it;
+  } else {
+    CLS_LOG(10, "auto-generating new TX-only peer: %s", site_name.c_str());
+
+    uuid_d uuid_gen;
+    while (true) {
+      uuid_gen.generate_random();
+      mirror_peer.uuid = uuid_gen.to_string();
+
+      bufferlist bl;
+      r = cls_cxx_map_get_val(hctx, peer_key(mirror_peer.uuid), &bl);
+      if (r == -ENOENT) {
+        break;
+      } else if (r < 0) {
+        CLS_ERR("failed to retrieve mirror peer: %s", cpp_strerror(r).c_str());
+        return r;
+      }
+    }
+
+    mirror_peer.mirror_peer_direction = cls::rbd::MIRROR_PEER_DIRECTION_TX;
+    mirror_peer.site_name = site_name;
+    mirror_peer.fsid = fsid;
+  }
+
+  if (it != peers.end()) {
+    mirror_peer = *it;
+
+    if (mirror_peer.mirror_peer_direction ==
+          cls::rbd::MIRROR_PEER_DIRECTION_RX) {
+      CLS_LOG(10, "switching to RX/TX peer: %s", site_name.c_str());
+      mirror_peer.mirror_peer_direction = cls::rbd::MIRROR_PEER_DIRECTION_RX_TX;
+    }
+  }
+
+  mirror_peer.last_seen = ceph_clock_now();
+
+  if (!mirror_peer.is_valid()) {
+    CLS_ERR("attempting to update invalid peer: %s", site_name.c_str());
+    return -EINVAL;
+  }
+
+  r = write_peer(hctx, mirror_peer);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
+int peer_add(cls_method_context_t hctx, cls::rbd::MirrorPeer mirror_peer) {
+  int r = check_mirroring_enabled(hctx);
+  if (r < 0) {
+    return r;
+  }
+
+  if (!mirror_peer.is_valid()) {
+    CLS_ERR("mirror peer is not valid");
+    return -EINVAL;
+  }
+
+  std::string mirror_uuid;
+  r = uuid_get(hctx, &mirror_uuid);
+  if (r < 0) {
+    CLS_ERR("error retrieving mirroring uuid: %s", cpp_strerror(r).c_str());
+    return r;
+  } else if (mirror_peer.uuid == mirror_uuid) {
+    CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
+            mirror_uuid.c_str());
+    return -EINVAL;
+  } else if (mirror_peer.mirror_peer_direction ==
+               cls::rbd::MIRROR_PEER_DIRECTION_TX) {
+    CLS_ERR("peer uuid '%s' cannot use TX-only direction",
+            mirror_peer.uuid.c_str());
+    return -EINVAL;
+  }
+
+  std::vector<cls::rbd::MirrorPeer> peers;
+  r = read_peers(hctx, &peers);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  }
+
+  for (auto const &peer : peers) {
+    if (peer.uuid == mirror_peer.uuid) {
+      CLS_ERR("peer uuid '%s' already exists",
+              peer.uuid.c_str());
+      return -ESTALE;
+    } else if (peer.site_name == mirror_peer.site_name) {
+      CLS_ERR("peer site name '%s' already exists",
+              peer.site_name.c_str());
+      return -EEXIST;
+    } else if (!mirror_peer.fsid.empty() && peer.fsid == mirror_peer.fsid) {
+      CLS_ERR("peer fsid '%s' already exists",
+              peer.fsid.c_str());
+      return -EEXIST;
+    }
+  }
+
+  r = write_peer(hctx, mirror_peer);
+  if (r < 0) {
+    return r;
+  }
+  return 0;
+}
+
+int peer_remove(cls_method_context_t hctx, const std::string& uuid) {
+  int r = cls_cxx_map_remove_key(hctx, peer_key(uuid));
+  if (r < 0 && r != -ENOENT) {
+    CLS_ERR("error removing peer: %s", cpp_strerror(r).c_str());
+    return r;
+  }
+  return 0;
+}
+
 int image_get(cls_method_context_t hctx, const string &image_id,
              cls::rbd::MirrorImage *mirror_image) {
   bufferlist bl;
@@ -5481,6 +5653,45 @@ int mirror_mode_set(cls_method_context_t hctx, bufferlist *in,
   return 0;
 }
 
+/**
+ * Input:
+ * @param unique peer site name (std::string)
+ * @param fsid (std::string)
+ * @param direction (MirrorPeerDirection) -- future use
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_peer_ping(cls_method_context_t hctx, bufferlist *in,
+                     bufferlist *out) {
+  std::string site_name;
+  std::string fsid;
+  cls::rbd::MirrorPeerDirection mirror_peer_direction;
+  try {
+    auto it = in->cbegin();
+    decode(site_name, it);
+    decode(fsid, it);
+
+    uint8_t direction;
+    decode(direction, it);
+    mirror_peer_direction = static_cast<cls::rbd::MirrorPeerDirection>(
+      direction);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  if (mirror_peer_direction != cls::rbd::MIRROR_PEER_DIRECTION_TX) {
+    return -EINVAL;
+  }
+
+  int r = mirror::peer_ping(hctx, site_name, fsid);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
 /**
  * Input:
  * none
@@ -5518,56 +5729,11 @@ int mirror_peer_add(cls_method_context_t hctx, bufferlist *in,
     return -EINVAL;
   }
 
-  uint32_t mirror_mode_decode;
-  int r = read_key(hctx, mirror::MODE, &mirror_mode_decode);
-  if (r < 0 && r != -ENOENT) {
-    return r;
-  } else if (r == -ENOENT ||
-             mirror_mode_decode == cls::rbd::MIRROR_MODE_DISABLED) {
-    CLS_ERR("mirroring must be enabled on the pool");
-    return -EINVAL;
-  } else if (!mirror_peer.is_valid()) {
-    CLS_ERR("mirror peer is not valid");
-    return -EINVAL;
-  }
-
-  std::string mirror_uuid;
-  r = mirror::uuid_get(hctx, &mirror_uuid);
+  int r = mirror::peer_add(hctx, mirror_peer);
   if (r < 0) {
-    CLS_ERR("error retrieving mirroring uuid: %s", cpp_strerror(r).c_str());
-    return r;
-  } else if (mirror_peer.uuid == mirror_uuid) {
-    CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
-            mirror_uuid.c_str());
-    return -EINVAL;
-  }
-
-  std::vector<cls::rbd::MirrorPeer> peers;
-  r = mirror::read_peers(hctx, &peers);
-  if (r < 0 && r != -ENOENT) {
     return r;
   }
 
-  for (auto const &peer : peers) {
-    if (peer.uuid == mirror_peer.uuid) {
-      CLS_ERR("peer uuid '%s' already exists",
-              peer.uuid.c_str());
-      return -ESTALE;
-    } else if (peer.cluster_name == mirror_peer.cluster_name) {
-      CLS_ERR("peer cluster name '%s' already exists",
-              peer.cluster_name.c_str());
-      return -EEXIST;
-    }
-  }
-
-  bufferlist bl;
-  encode(mirror_peer, bl);
-  r = cls_cxx_map_set_val(hctx, mirror::peer_key(mirror_peer.uuid),
-                          &bl);
-  if (r < 0) {
-    CLS_ERR("error adding peer: %s", cpp_strerror(r).c_str());
-    return r;
-  }
   return 0;
 }
 
@@ -5588,9 +5754,8 @@ int mirror_peer_remove(cls_method_context_t hctx, bufferlist *in,
     return -EINVAL;
   }
 
-  int r = cls_cxx_map_remove_key(hctx, mirror::peer_key(uuid));
-  if (r < 0 && r != -ENOENT) {
-    CLS_ERR("error removing peer: %s", cpp_strerror(r).c_str());
+  int r = mirror::peer_remove(hctx, uuid);
+  if (r < 0) {
     return r;
   }
   return 0;
@@ -5623,7 +5788,7 @@ int mirror_peer_set_client(cls_method_context_t hctx, bufferlist *in,
   }
 
   peer.client_name = client_name;
-  r = mirror::write_peer(hctx, uuid, peer);
+  r = mirror::write_peer(hctx, peer);
   if (r < 0) {
     return r;
   }
@@ -5633,7 +5798,7 @@ int mirror_peer_set_client(cls_method_context_t hctx, bufferlist *in,
 /**
  * Input:
  * @param uuid (std::string)
- * @param cluster_name (std::string)
+ * @param site_name (std::string)
  *
  * Output:
  * @returns 0 on success, negative error code on failure
@@ -5641,23 +5806,36 @@ int mirror_peer_set_client(cls_method_context_t hctx, bufferlist *in,
 int mirror_peer_set_cluster(cls_method_context_t hctx, bufferlist *in,
                             bufferlist *out) {
   std::string uuid;
-  std::string cluster_name;
+  std::string site_name;
   try {
     auto it = in->cbegin();
     decode(uuid, it);
-    decode(cluster_name, it);
+    decode(site_name, it);
   } catch (const buffer::error &err) {
     return -EINVAL;
   }
 
-  cls::rbd::MirrorPeer peer;
-  int r = mirror::read_peer(hctx, uuid, &peer);
-  if (r < 0) {
+  cls::rbd::MirrorPeer* peer = nullptr;
+  std::vector<cls::rbd::MirrorPeer> peers;
+  int r = mirror::read_peers(hctx, &peers);
+  if (r < 0 && r != -ENOENT) {
     return r;
   }
 
-  peer.cluster_name = cluster_name;
-  r = mirror::write_peer(hctx, uuid, peer);
+  for (auto& p : peers) {
+    if (p.uuid == uuid) {
+      peer = &p;
+    } else if (p.site_name == site_name) {
+      return -EEXIST;
+    }
+  }
+
+  if (peer == nullptr) {
+    return -ENOENT;
+  }
+
+  peer->site_name = site_name;
+  r = mirror::write_peer(hctx, *peer);
   if (r < 0) {
     return r;
   }
@@ -7574,6 +7752,7 @@ CLS_INIT(rbd)
   cls_method_handle_t h_mirror_uuid_set;
   cls_method_handle_t h_mirror_mode_get;
   cls_method_handle_t h_mirror_mode_set;
+  cls_method_handle_t h_mirror_peer_ping;
   cls_method_handle_t h_mirror_peer_list;
   cls_method_handle_t h_mirror_peer_add;
   cls_method_handle_t h_mirror_peer_remove;
@@ -7866,6 +8045,9 @@ CLS_INIT(rbd)
   cls_register_cxx_method(h_class, "mirror_mode_set",
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           mirror_mode_set, &h_mirror_mode_set);
+  cls_register_cxx_method(h_class, "mirror_peer_ping",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          mirror_peer_ping, &h_mirror_peer_ping);
   cls_register_cxx_method(h_class, "mirror_peer_list", CLS_METHOD_RD,
                           mirror_peer_list, &h_mirror_peer_list);
   cls_register_cxx_method(h_class, "mirror_peer_add",
index 9aa2b24a1a9d1faf101a0722d0ee7e06e55cd477..1dc1e7c7f2a61690988d7b68aa2b1443ba6f1e42 100644 (file)
@@ -1830,22 +1830,52 @@ int mirror_peer_list(librados::IoCtx *ioctx,
   return 0;
 }
 
-int mirror_peer_add(librados::IoCtx *ioctx, const std::string &uuid,
-                    const std::string &cluster_name,
-                    const std::string &client_name) {
-  cls::rbd::MirrorPeer peer(uuid, cluster_name, client_name);
+int mirror_peer_ping(librados::IoCtx *ioctx,
+                     const std::string& site_name,
+                     const std::string& fsid) {
+  librados::ObjectWriteOperation op;
+  mirror_peer_ping(&op, site_name, fsid);
+
+  int r = ioctx->operate(RBD_MIRRORING, &op);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
+void mirror_peer_ping(librados::ObjectWriteOperation *op,
+                      const std::string& site_name,
+                      const std::string& fsid) {
   bufferlist in_bl;
-  encode(peer, in_bl);
+  encode(site_name, in_bl);
+  encode(fsid, in_bl);
+  encode(static_cast<uint8_t>(cls::rbd::MIRROR_PEER_DIRECTION_TX), in_bl);
 
-  bufferlist out_bl;
-  int r = ioctx->exec(RBD_MIRRORING, "rbd", "mirror_peer_add", in_bl,
-                      out_bl);
+  op->exec("rbd", "mirror_peer_ping", in_bl);
+}
+
+int mirror_peer_add(librados::IoCtx *ioctx,
+                    const cls::rbd::MirrorPeer& mirror_peer) {
+  librados::ObjectWriteOperation op;
+  mirror_peer_add(&op, mirror_peer);
+
+  int r = ioctx->operate(RBD_MIRRORING, &op);
   if (r < 0) {
     return r;
   }
+
   return 0;
 }
 
+void mirror_peer_add(librados::ObjectWriteOperation *op,
+                     const cls::rbd::MirrorPeer& mirror_peer) {
+  bufferlist in_bl;
+  encode(mirror_peer, in_bl);
+
+  op->exec("rbd", "mirror_peer_add", in_bl);
+}
+
 int mirror_peer_remove(librados::IoCtx *ioctx,
                        const std::string &uuid) {
   bufferlist in_bl;
index ed0c9c2678fce5e8a72e6d9d75a38e2ec04bbb09..9ab63141d04f1c7ad6ed4bd7d7b086a45b4bc4bc 100644 (file)
@@ -381,11 +381,19 @@ int mirror_mode_get(librados::IoCtx *ioctx,
                     cls::rbd::MirrorMode *mirror_mode);
 int mirror_mode_set(librados::IoCtx *ioctx,
                     cls::rbd::MirrorMode mirror_mode);
+
+int mirror_peer_ping(librados::IoCtx *ioctx,
+                     const std::string& site_name,
+                     const std::string& fsid);
+void mirror_peer_ping(librados::ObjectWriteOperation *op,
+                      const std::string& site_name,
+                      const std::string& fsid);
 int mirror_peer_list(librados::IoCtx *ioctx,
                      std::vector<cls::rbd::MirrorPeer> *peers);
-int mirror_peer_add(librados::IoCtx *ioctx, const std::string &uuid,
-                    const std::string &cluster_name,
-                    const std::string &client_name);
+int mirror_peer_add(librados::IoCtx *ioctx,
+                    const cls::rbd::MirrorPeer& mirror_peer);
+void mirror_peer_add(librados::ObjectWriteOperation *op,
+                     const cls::rbd::MirrorPeer& mirror_peer);
 int mirror_peer_remove(librados::IoCtx *ioctx,
                        const std::string &uuid);
 int mirror_peer_set_client(librados::IoCtx *ioctx,
@@ -394,6 +402,7 @@ int mirror_peer_set_client(librados::IoCtx *ioctx,
 int mirror_peer_set_cluster(librados::IoCtx *ioctx,
                             const std::string &uuid,
                             const std::string &cluster_name);
+
 void mirror_image_list_start(librados::ObjectReadOperation *op,
                              const std::string &start, uint64_t max_return);
 int mirror_image_list_finish(bufferlist::const_iterator *it,
index 4a432aabec78884bfa6b8ce0abe2aaefa2c3c973..4d492050ecdf8468152247e876a3f8ac24a1ea60 100644 (file)
@@ -8,41 +8,85 @@
 namespace cls {
 namespace rbd {
 
+std::ostream& operator<<(std::ostream& os,
+                         MirrorPeerDirection mirror_peer_direction) {
+  switch (mirror_peer_direction) {
+  case MIRROR_PEER_DIRECTION_RX:
+    os << "RX";
+    break;
+  case MIRROR_PEER_DIRECTION_TX:
+    os << "TX";
+    break;
+  case MIRROR_PEER_DIRECTION_RX_TX:
+    os << "RX/TX";
+    break;
+  default:
+    os << "unknown";
+    break;
+  }
+  return os;
+}
+
 void MirrorPeer::encode(bufferlist &bl) const {
-  ENCODE_START(1, 1, bl);
+  ENCODE_START(2, 1, bl);
   encode(uuid, bl);
-  encode(cluster_name, bl);
+  encode(site_name, bl);
   encode(client_name, bl);
   int64_t pool_id = -1;
   encode(pool_id, bl);
+
+  // v2
+  encode(static_cast<uint8_t>(mirror_peer_direction), bl);
+  encode(fsid, bl);
+  encode(last_seen, bl);
   ENCODE_FINISH(bl);
 }
 
 void MirrorPeer::decode(bufferlist::const_iterator &it) {
-  DECODE_START(1, it);
+  DECODE_START(2, it);
   decode(uuid, it);
-  decode(cluster_name, it);
+  decode(site_name, it);
   decode(client_name, it);
   int64_t pool_id;
   decode(pool_id, it);
+
+  if (struct_v >= 2) {
+    uint8_t mpd;
+    decode(mpd, it);
+    mirror_peer_direction = static_cast<MirrorPeerDirection>(mpd);
+    decode(fsid, it);
+    decode(last_seen, it);
+  }
+
   DECODE_FINISH(it);
 }
 
 void MirrorPeer::dump(Formatter *f) const {
   f->dump_string("uuid", uuid);
-  f->dump_string("cluster_name", cluster_name);
+  f->dump_stream("direction") << mirror_peer_direction;
+  f->dump_string("site_name", site_name);
+  f->dump_string("fsid", fsid);
   f->dump_string("client_name", client_name);
+  f->dump_stream("last_seen") << last_seen;
 }
 
 void MirrorPeer::generate_test_instances(std::list<MirrorPeer*> &o) {
   o.push_back(new MirrorPeer());
-  o.push_back(new MirrorPeer("uuid-123", "cluster name", "client name"));
+  o.push_back(new MirrorPeer("uuid-123", MIRROR_PEER_DIRECTION_RX, "site A",
+                             "client name", ""));
+  o.push_back(new MirrorPeer("uuid-234", MIRROR_PEER_DIRECTION_TX, "site B",
+                             "", "fsid"));
+  o.push_back(new MirrorPeer("uuid-345", MIRROR_PEER_DIRECTION_RX_TX, "site C",
+                             "client name", "fsid"));
 }
 
 bool MirrorPeer::operator==(const MirrorPeer &rhs) const {
   return (uuid == rhs.uuid &&
-          cluster_name == rhs.cluster_name &&
-          client_name == rhs.client_name);
+          mirror_peer_direction == rhs.mirror_peer_direction &&
+          site_name == rhs.site_name &&
+          client_name == rhs.client_name &&
+          fsid == rhs.fsid &&
+          last_seen == rhs.last_seen);
 }
 
 std::ostream& operator<<(std::ostream& os, const MirrorMode& mirror_mode) {
@@ -66,8 +110,11 @@ std::ostream& operator<<(std::ostream& os, const MirrorMode& mirror_mode) {
 std::ostream& operator<<(std::ostream& os, const MirrorPeer& peer) {
   os << "["
      << "uuid=" << peer.uuid << ", "
-     << "cluster_name=" << peer.cluster_name << ", "
-     << "client_name=" << peer.client_name
+     << "direction=" << peer.mirror_peer_direction << ", "
+     << "site_name=" << peer.site_name << ", "
+     << "client_name=" << peer.client_name << ", "
+     << "fsid=" << peer.fsid << ", "
+     << "last_seen=" << peer.last_seen
      << "]";
   return os;
 }
index 66bfa98fbbc0aba3efc875eeb645e15e7e272d4b..9022bb54eec70cee8d6e62eb4c988db93e233c68 100644 (file)
@@ -68,20 +68,49 @@ inline void decode(GroupImageLinkState &state, bufferlist::const_iterator& it)
   state = static_cast<GroupImageLinkState>(int_state);
 }
 
+enum MirrorPeerDirection {
+  MIRROR_PEER_DIRECTION_RX    = 0,
+  MIRROR_PEER_DIRECTION_TX    = 1,
+  MIRROR_PEER_DIRECTION_RX_TX = 2
+};
+
+std::ostream& operator<<(std::ostream& os,
+                         MirrorPeerDirection mirror_peer_direction);
+
 struct MirrorPeer {
   MirrorPeer() {
   }
-  MirrorPeer(const std::string &uuid, const std::string &cluster_name,
-             const std::string &client_name)
-    : uuid(uuid), cluster_name(cluster_name), client_name(client_name) {
+  MirrorPeer(const std::string &uuid,
+             MirrorPeerDirection mirror_peer_direction,
+             const std::string& site_name,
+             const std::string& client_name,
+             const std::string& fsid)
+    : uuid(uuid), mirror_peer_direction(mirror_peer_direction),
+      site_name(site_name), client_name(client_name), fsid(fsid) {
   }
 
   std::string uuid;
-  std::string cluster_name;
-  std::string client_name;
+
+  MirrorPeerDirection mirror_peer_direction = MIRROR_PEER_DIRECTION_RX_TX;
+  std::string site_name;
+  std::string client_name;  // RX property
+  std::string fsid;
+  utime_t last_seen;
 
   inline bool is_valid() const {
-    return (!uuid.empty() && !cluster_name.empty() && !client_name.empty());
+    switch (mirror_peer_direction) {
+    case MIRROR_PEER_DIRECTION_TX:
+      break;
+    case MIRROR_PEER_DIRECTION_RX:
+    case MIRROR_PEER_DIRECTION_RX_TX:
+      if (client_name.empty()) {
+        return false;
+      }
+      break;
+    default:
+      return false;
+    }
+    return (!uuid.empty() && !site_name.empty());
   }
 
   void encode(bufferlist &bl) const;
@@ -91,6 +120,9 @@ struct MirrorPeer {
   static void generate_test_instances(std::list<MirrorPeer*> &o);
 
   bool operator==(const MirrorPeer &rhs) const;
+  bool operator!=(const MirrorPeer &rhs) const {
+    return (!(*this == rhs));
+  }
 };
 
 std::ostream& operator<<(std::ostream& os, const MirrorMode& mirror_mode);
index 4e2b370457041fbdbab090841a3347a53082ab74..412d6a0a5d68df58e9ce1e058499a49c1b736a49 100644 (file)
@@ -1231,8 +1231,10 @@ int Mirror<I>::peer_add(librados::IoCtx& io_ctx, std::string *uuid,
     uuid_gen.generate_random();
 
     *uuid = uuid_gen.to_string();
-    r = cls_client::mirror_peer_add(&io_ctx, *uuid, cluster_name,
-                                    client_name);
+    r = cls_client::mirror_peer_add(
+      &io_ctx,
+      {*uuid, cls::rbd::MIRROR_PEER_DIRECTION_RX, cluster_name, client_name,
+       ""});
     if (r == -ESTALE) {
       ldout(cct, 5) << "duplicate UUID detected, retrying" << dendl;
     } else if (r < 0) {
@@ -1283,7 +1285,7 @@ int Mirror<I>::peer_list(librados::IoCtx& io_ctx,
   for (auto &mirror_peer : mirror_peers) {
     mirror_peer_t peer;
     peer.uuid = mirror_peer.uuid;
-    peer.cluster_name = mirror_peer.cluster_name;
+    peer.cluster_name = mirror_peer.site_name;
     peer.client_name = mirror_peer.client_name;
     peers->push_back(peer);
   }
index 9a4adccc964d168d75da66c7e8ef63620d24541d..e1f3834656a3ed4e7a4ff026ad5a1bc3fb4b3794 100644 (file)
@@ -26,6 +26,9 @@
 
 using namespace std;
 using namespace librbd::cls_client;
+using cls::rbd::MIRROR_PEER_DIRECTION_RX;
+using cls::rbd::MIRROR_PEER_DIRECTION_TX;
+using cls::rbd::MIRROR_PEER_DIRECTION_RX_TX;
 using ::librbd::ParentImageInfo;
 using ceph::encode;
 using ceph::decode;
@@ -1596,7 +1599,9 @@ TEST_F(TestClsRbd, mirror) {
 
   std::string uuid;
   ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
-  ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, "uuid1", "cluster1", "client"));
+  ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_RX,
+                                              "siteA", "client", "fsid"}));
+  ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "siteA", "fsid"));
 
   cls::rbd::MirrorMode mirror_mode;
   ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
@@ -1618,43 +1623,91 @@ TEST_F(TestClsRbd, mirror) {
   ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
   ASSERT_EQ(cls::rbd::MIRROR_MODE_POOL, mirror_mode);
 
-  ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, "mirror-uuid", "cluster1", "client"));
-  ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid1", "cluster1", "client"));
-  ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid2", "cluster2", "admin"));
-  ASSERT_EQ(-ESTALE, mirror_peer_add(&ioctx, "uuid2", "cluster3", "foo"));
-  ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, "uuid3", "cluster1", "foo"));
-  ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid3", "cluster3", "admin", 123));
-  ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, "uuid4", "cluster3", "admin"));
-  ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, "uuid4", "cluster3", "admin", 123));
-  ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid4", "cluster3", "admin", 234));
+  ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"mirror-uuid",
+                                              MIRROR_PEER_DIRECTION_RX, "siteA",
+                                              "client", ""}));
+  ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_TX,
+                                              "siteA", "client", "fsid"}));
+  ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_RX,
+                                        "siteA", "client", "fsidA"}));
+  ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid2", MIRROR_PEER_DIRECTION_RX,
+                                        "siteB", "admin", ""}));
+  ASSERT_EQ(-ESTALE, mirror_peer_add(&ioctx, {"uuid2", MIRROR_PEER_DIRECTION_RX,
+                                              "siteC", "foo", ""}));
+  ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
+                                              "siteA", "foo", ""}));
+  ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
+                                              "siteC", "client", "fsidA"}));
+  ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
+                                        "siteC", "admin", ""}));
+  ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid4", MIRROR_PEER_DIRECTION_RX,
+                                        "siteD", "admin", ""}));
 
   ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
   std::vector<cls::rbd::MirrorPeer> expected_peers = {
-    {"uuid1", "cluster1", "client", -1},
-    {"uuid2", "cluster2", "admin", -1},
-    {"uuid3", "cluster3", "admin", 123},
-    {"uuid4", "cluster3", "admin", 234}};
+    {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "client", "fsidA"},
+    {"uuid2", MIRROR_PEER_DIRECTION_RX, "siteB", "admin", ""},
+    {"uuid3", MIRROR_PEER_DIRECTION_RX, "siteC", "admin", ""},
+    {"uuid4", MIRROR_PEER_DIRECTION_RX, "siteD", "admin", ""}};
   ASSERT_EQ(expected_peers, peers);
 
   ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid5"));
   ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid4"));
   ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid2"));
 
+  ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
+  expected_peers = {
+    {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "client", "fsidA"},
+    {"uuid3", MIRROR_PEER_DIRECTION_RX, "siteC", "admin", ""}};
+  ASSERT_EQ(expected_peers, peers);
+
   ASSERT_EQ(-ENOENT, mirror_peer_set_client(&ioctx, "uuid4", "new client"));
   ASSERT_EQ(0, mirror_peer_set_client(&ioctx, "uuid1", "new client"));
 
-  ASSERT_EQ(-ENOENT, mirror_peer_set_cluster(&ioctx, "uuid4", "new cluster"));
-  ASSERT_EQ(0, mirror_peer_set_cluster(&ioctx, "uuid3", "new cluster"));
+  ASSERT_EQ(-ENOENT, mirror_peer_set_cluster(&ioctx, "uuid4", "new site"));
+  ASSERT_EQ(0, mirror_peer_set_cluster(&ioctx, "uuid3", "new site"));
 
   ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
   expected_peers = {
-    {"uuid1", "cluster1", "new client", -1},
-    {"uuid3", "new cluster", "admin", 123}};
+    {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "new client", "fsidA"},
+    {"uuid3", MIRROR_PEER_DIRECTION_RX, "new site", "admin", ""}};
   ASSERT_EQ(expected_peers, peers);
-  ASSERT_EQ(-EBUSY, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_DISABLED));
 
-  ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid3"));
   ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid1"));
+
+  ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
+  expected_peers = {
+    {"uuid3", MIRROR_PEER_DIRECTION_RX, "new site", "admin", ""}};
+  ASSERT_EQ(expected_peers, peers);
+
+  ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "", "fsid"));
+  ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "new site", ""));
+  ASSERT_EQ(0, mirror_peer_ping(&ioctx, "new site", "fsid"));
+
+  ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
+  ASSERT_EQ(1U, peers.size());
+  ASSERT_LT(utime_t{}, peers[0].last_seen);
+  expected_peers = {
+    {"uuid3", MIRROR_PEER_DIRECTION_RX_TX, "new site", "admin", "fsid"}};
+  expected_peers[0].last_seen = peers[0].last_seen;
+  ASSERT_EQ(expected_peers, peers);
+  ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid3"));
+
+  ASSERT_EQ(0, mirror_peer_ping(&ioctx, "siteA", "fsid"));
+
+  ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
+  ASSERT_EQ(1U, peers.size());
+  ASSERT_FALSE(peers[0].uuid.empty());
+  ASSERT_LT(utime_t{}, peers[0].last_seen);
+  expected_peers = {
+    {peers[0].uuid, MIRROR_PEER_DIRECTION_TX, "siteA", "", "fsid"}};
+  expected_peers[0].last_seen = peers[0].last_seen;
+  ASSERT_EQ(expected_peers, peers);
+
+  ASSERT_EQ(-EBUSY, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_DISABLED));
+  ASSERT_EQ(0, mirror_peer_remove(&ioctx, peers[0].uuid));
+
+  ASSERT_EQ(0, mirror_peer_remove(&ioctx, "DNE"));
   ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
   expected_peers = {};
   ASSERT_EQ(expected_peers, peers);