]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: initial support for friendly mirror site names
authorJason Dillaman <dillaman@redhat.com>
Wed, 11 Sep 2019 17:16:02 +0000 (13:16 -0400)
committerJason Dillaman <dillaman@redhat.com>
Tue, 17 Sep 2019 16:34:31 +0000 (12:34 -0400)
The site name applies to the cluster and stores the friendly name
in the MONs config-key store.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
12 files changed:
src/include/rados/librados.hpp
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/include/rbd_types.h
src/librados/librados_cxx.cc
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/librados_test_stub/LibradosTestStub.cc
src/test/librbd/test_mirroring.cc
src/test/pybind/test_rbd.py

index 5f463a4ca051f6a6e3e85441d8fa6e2dc7f078ea..00c180633820ad65ddfc938350af87ec5d695f75 100644 (file)
@@ -1323,6 +1323,7 @@ inline namespace v14_2_0 {
     Rados();
     explicit Rados(IoCtx& ioctx);
     ~Rados();
+    static void from_rados_t(rados_t cluster, Rados &rados);
 
     int init(const char * const id);
     int init2(const char * const name, const char * const clustername,
index 1fa30dda750d80c9e94fdc3e8a11cbe32ca31be1..78d358ddc86bfdf4d7f1173d5c79478f0d23fc2c 100644 (file)
@@ -431,10 +431,16 @@ CEPH_RBD_API void rbd_migration_status_cleanup(
     rbd_image_migration_status_t *status);
 
 /* pool mirroring */
+CEPH_RBD_API int rbd_mirror_site_name_get(rados_t cluster,
+                                          char *name, size_t *max_len);
+CEPH_RBD_API int rbd_mirror_site_name_set(rados_t cluster,
+                                          const char *name);
+
 CEPH_RBD_API int rbd_mirror_mode_get(rados_ioctx_t io_ctx,
                                      rbd_mirror_mode_t *mirror_mode);
 CEPH_RBD_API int rbd_mirror_mode_set(rados_ioctx_t io_ctx,
                                      rbd_mirror_mode_t mirror_mode);
+
 CEPH_RBD_API int rbd_mirror_peer_add(rados_ioctx_t io_ctx,
                                      char *uuid, size_t uuid_max_length,
                                      const char *cluster_name,
index 4aaffd116f6f3f63d96c5a273bb92681d006a1c6..d1d2667bd1043678df84d2eb9caa8de2ac1bfd0f 100644 (file)
@@ -263,8 +263,13 @@ public:
                        image_migration_status_t *status, size_t status_size);
 
   // RBD pool mirroring support functions
+  int mirror_site_name_get(librados::Rados& rados, std::string* site_name);
+  int mirror_site_name_set(librados::Rados& rados,
+                           const std::string& site_name);
+
   int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
   int mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
+
   int mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
                       const std::string &cluster_name,
                       const std::string &client_name);
index 4401a36c8ba9c6fcf53b1769834cb94ca72d6b64..2b6243af9e191159669eb040e0d2f74eea2400f8 100644 (file)
  * MON config-key prefix for storing optional remote cluster connectivity
  * parameters
  */
-#define RBD_MIRROR_PEER_CONFIG_KEY_PREFIX "rbd/mirror/peer/"
+#define RBD_MIRROR_CONFIG_KEY_PREFIX "rbd/mirror/"
+#define RBD_MIRROR_SITE_NAME_CONFIG_KEY RBD_MIRROR_CONFIG_KEY_PREFIX "site_name"
+#define RBD_MIRROR_PEER_CONFIG_KEY_PREFIX RBD_MIRROR_CONFIG_KEY_PREFIX "peer/"
 
 struct rbd_info {
        ceph_le64 max_id;
index 198de2f96ba4b96482e7e217fcb3c1ea146b635b..c938ce00c21fecc508f823c0ae43607aff4f50c0 100644 (file)
@@ -2270,6 +2270,16 @@ librados::Rados::~Rados()
   shutdown();
 }
 
+void librados::Rados::from_rados_t(rados_t cluster, Rados &rados) {
+  if (rados.client) {
+    rados.client->put();
+  }
+  rados.client = static_cast<RadosClient*>(cluster);
+  if (rados.client) {
+    rados.client->get();
+  }
+}
+
 int librados::Rados::init(const char * const id)
 {
   return rados_create((rados_t *)&client, id);
index 2e91b584dc4305973a8b6afe13f529fe8e1ea9dd..985c591b39acc700229ec7e8123effa5bb3e343e 100644 (file)
@@ -23,6 +23,7 @@
 #include "librbd/mirror/PromoteRequest.h"
 #include "librbd/mirror/Types.h"
 #include "librbd/MirroringWatcher.h"
+#include <boost/algorithm/string/trim.hpp>
 #include <boost/scope_exit.hpp>
 #include "json_spirit/json_spirit.h"
 
@@ -35,6 +36,56 @@ namespace api {
 
 namespace {
 
+int get_config_key(librados::Rados& rados, const std::string& key,
+                   std::string* value) {
+  std::string cmd =
+    "{"
+      "\"prefix\": \"config-key get\", "
+      "\"key\": \"" + key + "\""
+    "}";
+
+  bufferlist in_bl;
+  bufferlist out_bl;
+
+  int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+  if (r == -EINVAL) {
+    return -EOPNOTSUPP;
+  } else if (r < 0 && r != -ENOENT) {
+    return r;
+  }
+
+  *value = out_bl.to_str();
+  return 0;
+}
+
+int set_config_key(librados::Rados& rados, const std::string& key,
+                   const std::string& value) {
+  std::string cmd;
+  if (value.empty()) {
+    cmd = "{"
+            "\"prefix\": \"config-key rm\", "
+            "\"key\": \"" + key + "\""
+          "}";
+  } else {
+    cmd = "{"
+            "\"prefix\": \"config-key set\", "
+            "\"key\": \"" + key + "\", "
+            "\"val\": \"" + value + "\""
+          "}";
+  }
+  bufferlist in_bl;
+  bufferlist out_bl;
+
+  int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+  if (r == -EINVAL) {
+    return -EOPNOTSUPP;
+  } else if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
 std::string get_peer_config_key_name(int64_t pool_id,
                                      const std::string& peer_uuid) {
   return RBD_MIRROR_PEER_CONFIG_KEY_PREFIX + stringify(pool_id) + "/" +
@@ -44,16 +95,10 @@ std::string get_peer_config_key_name(int64_t pool_id,
 int remove_peer_config_key(librados::IoCtx& io_ctx,
                            const std::string& peer_uuid) {
   int64_t pool_id = io_ctx.get_id();
-  std::string cmd =
-    "{"
-      "\"prefix\": \"config-key rm\", "
-      "\"key\": \"" + get_peer_config_key_name(pool_id, peer_uuid) + "\""
-    "}";
+  auto key = get_peer_config_key_name(pool_id, peer_uuid);
 
-  bufferlist in_bl;
-  bufferlist out_bl;
   librados::Rados rados(io_ctx);
-  int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+  int r = set_config_key(rados, key, "");
   if (r < 0 && r != -ENOENT && r != -EPERM) {
     return r;
   }
@@ -540,6 +585,51 @@ int Mirror<I>::image_get_instance_id(I *ictx, std::string *instance_id) {
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::site_name_get(librados::Rados& rados, std::string* name) {
+  CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
+  ldout(cct, 20) << dendl;
+
+  int r = get_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
+  if (r == -EOPNOTSUPP) {
+    return r;
+  } else if (r == -ENOENT || name->empty()) {
+    // default to the cluster fsid
+    r = rados.cluster_fsid(name);
+    if (r < 0) {
+      lderr(cct) << "failed to retrieve cluster fsid: " << cpp_strerror(r)
+                 << dendl;
+    }
+    return r;
+  } else if (r < 0) {
+    lderr(cct) << "failed to retrieve site name: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  }
+
+  return 0;
+}
+
+template <typename I>
+int Mirror<I>::site_name_set(librados::Rados& rados, const std::string& name) {
+  CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
+
+  std::string site_name{name};
+  boost::algorithm::trim(site_name);
+  ldout(cct, 20) << "site_name=" << site_name << dendl;
+
+  int r = set_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
+  if (r == -EOPNOTSUPP) {
+    return r;
+  } else if (r < 0 && r != -ENOENT) {
+    lderr(cct) << "failed to update site name: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  }
+
+  return 0;
+}
+
 template <typename I>
 int Mirror<I>::mode_get(librados::IoCtx& io_ctx,
                         rbd_mirror_mode_t *mirror_mode) {
@@ -887,18 +977,12 @@ int Mirror<I>::peer_get_attributes(librados::IoCtx& io_ctx,
   ldout(cct, 20) << "uuid=" << uuid << dendl;
 
   attributes->clear();
-  std::string cmd =
-    "{"
-      "\"prefix\": \"config-key get\", "
-      "\"key\": \"" + get_peer_config_key_name(io_ctx.get_id(), uuid) + "\""
-    "}";
-
-  bufferlist in_bl;
-  bufferlist out_bl;
 
   librados::Rados rados(io_ctx);
-  int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
-  if (r == -ENOENT || out_bl.length() == 0) {
+  std::string value;
+  int r = get_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
+                         &value);
+  if (r == -ENOENT || value.empty()) {
     return -ENOENT;
   } else if (r < 0) {
     lderr(cct) << "failed to retrieve peer attributes: " << cpp_strerror(r)
@@ -908,7 +992,7 @@ int Mirror<I>::peer_get_attributes(librados::IoCtx& io_ctx,
 
   bool json_valid = false;
   json_spirit::mValue json_root;
-  if(json_spirit::read(out_bl.to_str(), json_root)) {
+  if(json_spirit::read(value, json_root)) {
     try {
       auto& json_obj = json_root.get_obj();
       for (auto& pairs : json_obj) {
@@ -959,18 +1043,10 @@ int Mirror<I>::peer_set_attributes(librados::IoCtx& io_ctx,
   }
   ss << "}";
 
-  std::string cmd =
-    "{"
-      "\"prefix\": \"config-key set\", "
-      "\"key\": \"" + get_peer_config_key_name(io_ctx.get_id(), uuid) + "\", "
-      "\"val\": \"" + ss.str() + "\""
-    "}";
-  bufferlist in_bl;
-  bufferlist out_bl;
-
   librados::Rados rados(io_ctx);
-  r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
-  if (r < 0) {
+  r = set_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
+                     ss.str());
+  if (r < 0 && r != -ENOENT) {
     lderr(cct) << "failed to update peer attributes: " << cpp_strerror(r)
                << dendl;
     return r;
index 78a40849e7fd82179e2fba7c904bff2a010cd0f4..0544a0547c5822f2181e71c7ddbb658ab27716ae 100644 (file)
@@ -23,6 +23,9 @@ struct Mirror {
   typedef std::map<std::string, mirror_image_status_t> IdToMirrorImageStatus;
   typedef std::map<mirror_image_status_state_t, int> MirrorImageStatusStates;
 
+  static int site_name_get(librados::Rados& rados, std::string* name);
+  static int site_name_set(librados::Rados& rados, const std::string& name);
+
   static int mode_get(librados::IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
   static int mode_set(librados::IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
 
index 3cc45bac04f6171fd116dbb9bf5e7d7333e95b63..84d0984ef1b6d9202a54082a988cc62e7f364157 100644 (file)
@@ -868,6 +868,16 @@ namespace librbd {
     return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
   }
 
+  int RBD::mirror_site_name_get(librados::Rados& rados,
+                                std::string* site_name) {
+    return librbd::api::Mirror<>::site_name_get(rados, site_name);
+  }
+
+  int RBD::mirror_site_name_set(librados::Rados& rados,
+                                const std::string& site_name) {
+    return librbd::api::Mirror<>::site_name_set(rados, site_name);
+  }
+
   int RBD::mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode) {
     return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
   }
@@ -2718,6 +2728,34 @@ extern "C" int rbd_image_options_is_empty(rbd_image_options_t opts)
 }
 
 /* pool mirroring */
+extern "C" int rbd_mirror_site_name_get(rados_t cluster, char *name,
+                                        size_t *max_len) {
+  librados::Rados rados;
+  librados::Rados::from_rados_t(cluster, rados);
+
+  std::string site_name;
+  int r = librbd::api::Mirror<>::site_name_get(rados, &site_name);
+  if (r < 0) {
+    return r;
+  }
+
+  auto total_len = site_name.size() + 1;
+  if (*max_len < total_len) {
+    *max_len = total_len;
+    return -ERANGE;
+  }
+  *max_len = total_len;
+
+  strcpy(name, site_name.c_str());
+  return 0;
+}
+
+extern "C" int rbd_mirror_site_name_set(rados_t cluster, const char *name) {
+  librados::Rados rados;
+  librados::Rados::from_rados_t(cluster, rados);
+  return librbd::api::Mirror<>::site_name_set(rados, name);
+}
+
 extern "C" int rbd_mirror_mode_get(rados_ioctx_t p,
                                    rbd_mirror_mode_t *mirror_mode) {
   librados::IoCtx io_ctx;
index ee24d19b4b083c53d8f4bbd88e943b540607a0a0..02fa9d6a2c97147ad3bbe3c524188c1eaad623ae 100644 (file)
@@ -97,6 +97,7 @@ cdef extern from "rbd/librbd.h" nogil:
         RBD_MAX_BLOCK_NAME_SIZE
         RBD_MAX_IMAGE_NAME_SIZE
 
+    ctypedef void* rados_t
     ctypedef void* rados_ioctx_t
     ctypedef void* rbd_image_t
     ctypedef void* rbd_image_options_t
@@ -340,8 +341,12 @@ cdef extern from "rbd/librbd.h" nogil:
                              size_t status_size)
     void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
 
+    int rbd_mirror_site_name_get(rados_t cluster, char *name, size_t *max_len)
+    int rbd_mirror_site_name_set(rados_t cluster, const char *name)
+
     int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
     int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
+
     int rbd_mirror_peer_add(rados_ioctx_t io, char *uuid,
                             size_t uuid_max_length, const char *cluster_name,
                             const char *client_name)
@@ -892,6 +897,9 @@ cdef make_ex(ret, msg, exception_map=errno_to_exception):
         return OSError(msg, errno=ret)
 
 
+cdef rados_t convert_rados(rados.Rados rados) except? NULL:
+    return <rados_t>rados.cluster
+
 cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
     return <rados_ioctx_t>ioctx.io
 
@@ -1684,6 +1692,50 @@ class RBD(object):
 
         return status
 
+    def mirror_site_name_get(self, rados):
+        """
+        Get the local cluster's friendly site name
+
+        :param rados: cluster connection
+        :type rados: :class: rados.Rados
+        :returns: str - local site name
+        """
+        cdef:
+            rados_t _rados = convert_rados(rados)
+            char *_site_name = NULL
+            size_t _max_size = 512
+        try:
+            while True:
+                _site_name = <char *>realloc_chk(_site_name, _max_size)
+                with nogil:
+                    ret = rbd_mirror_site_name_get(_rados, _site_name,
+                                                   &_max_size)
+                if ret >= 0:
+                    break
+                elif ret != -errno.ERANGE:
+                    raise make_ex(ret, 'error getting site name')
+            return decode_cstr(_site_name)
+        finally:
+            free(_site_name)
+
+    def mirror_site_name_set(self, rados, site_name):
+        """
+        Set the local cluster's friendly site name
+
+        :param rados: cluster connection
+        :type rados: :class: rados.Rados
+        :param site_name: friendly site name
+        :type str:
+        """
+        site_name = cstr(site_name, 'site_name')
+        cdef:
+            rados_t _rados = convert_rados(rados)
+            char *_site_name = site_name
+        with nogil:
+            ret = rbd_mirror_site_name_set(_rados, _site_name)
+        if ret != 0:
+            raise make_ex(ret, 'error setting mirror site name')
+
     def mirror_mode_get(self, ioctx):
         """
         Get pool mirror mode.
index 71b27b92a22c1471776e847b11418a98b09ce243..c2f73a4d4913fc3e2139d6b93832f0fcc4b9634d 100644 (file)
@@ -991,6 +991,19 @@ Rados::~Rados() {
   shutdown();
 }
 
+void Rados::from_rados_t(rados_t p, Rados &rados) {
+  if (rados.client != nullptr) {
+    reinterpret_cast<TestRadosClient*>(rados.client)->put();
+    rados.client = nullptr;
+  }
+
+  auto impl = reinterpret_cast<TestRadosClient*>(p);
+  if (impl) {
+    impl->get();
+    rados.client = reinterpret_cast<RadosClient*>(impl);
+  }
+}
+
 AioCompletion *Rados::aio_create_completion(void *cb_arg,
                                             callback_t cb_complete,
                                             callback_t cb_safe) {
index 65c1e979d0689e888d1b232947910116c8d4146a..a31b11e00b0aebfd7384c16d1a81a7129ad5e8ba 100644 (file)
@@ -950,3 +950,21 @@ TEST_F(TestMirroring, AioGetStatus) {
     ASSERT_EQ(0, status.last_update);
   }
 }
+
+TEST_F(TestMirroring, SiteName) {
+  REQUIRE(!is_librados_test_stub(_rados));
+
+  const std::string expected_site_name("us-east-1a");
+  ASSERT_EQ(0, m_rbd.mirror_site_name_set(_rados, expected_site_name));
+
+  std::string site_name;
+  ASSERT_EQ(0, m_rbd.mirror_site_name_get(_rados, &site_name));
+  ASSERT_EQ(expected_site_name, site_name);
+
+  ASSERT_EQ(0, m_rbd.mirror_site_name_set(_rados, ""));
+
+  std::string fsid;
+  ASSERT_EQ(0, _rados.cluster_fsid(&fsid));
+  ASSERT_EQ(0, m_rbd.mirror_site_name_get(_rados, &site_name));
+  ASSERT_EQ(fsid, site_name);
+}
index 86a7a99b4df0c7ac886e7f772f970ecc98a67d4d..c5f3ed109c97184d80804f77037a9d145d7e6750 100644 (file)
@@ -1789,6 +1789,12 @@ class TestMirroring(object):
         remove_image()
         self.rbd.mirror_mode_set(ioctx, self.initial_mirror_mode)
 
+    def test_site_name(self):
+        site_name = "us-west-1"
+        self.rbd.mirror_site_name_set(rados, site_name)
+        eq(site_name, self.rbd.mirror_site_name_get(rados))
+        self.rbd.mirror_site_name_set(rados, "")
+        eq(rados.get_fsid(), self.rbd.mirror_site_name_get(rados))
 
     def test_mirror_peer(self):
         eq([], list(self.rbd.mirror_peer_list(ioctx)))