]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/rbd: add namespace_create/remove/list API methods
authorJason Dillaman <dillaman@redhat.com>
Fri, 15 Jun 2018 13:20:12 +0000 (09:20 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 18 Jun 2018 17:51:46 +0000 (13:51 -0400)
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/include/rbd_types.h
src/test/cls_rbd/test_cls_rbd.cc

index f71e5867d8ec9a53f265e610b6a5592b45f9881e..497580fa814fea46c5b48c8eec931810b38bc09c 100644 (file)
@@ -6167,6 +6167,148 @@ int trash_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
   return r;
 }
 
+namespace nspace {
+
+const std::string NAME_KEY_PREFIX("name_");
+
+std::string key_for_name(const std::string& name) {
+  return NAME_KEY_PREFIX + name;
+}
+
+std::string name_from_key(const std::string &key) {
+  return key.substr(NAME_KEY_PREFIX.size());
+}
+
+} // namespace nspace
+
+/**
+ * Add a namespace to the namespace directory.
+ *
+ * Input:
+ * @param name the name of the namespace
+ *
+ * Output:
+ * @returns -EEXIST if the namespace is already exists
+ * @returns 0 on success, negative error code on failure
+ */
+int namespace_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  std::string name;
+  try {
+    auto iter = in->cbegin();
+    decode(name, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  std::string key(nspace::key_for_name(name));
+  bufferlist value;
+  int r = cls_cxx_map_get_val(hctx, key, &value);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  } else if (r == 0) {
+    return -EEXIST;
+  }
+
+  r = cls_cxx_map_set_val(hctx, key, &value);
+  if (r < 0) {
+    CLS_ERR("failed to set omap key: %s", key.c_str());
+    return r;
+  }
+
+  return 0;
+}
+
+/**
+ * Add a namespace to the namespace directory.
+ *
+ * Input:
+ * @param name the name of the namespace
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int namespace_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  std::string name;
+  try {
+    auto iter = in->cbegin();
+    decode(name, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  std::string key(nspace::key_for_name(name));
+  bufferlist bl;
+  int r = cls_cxx_map_get_val(hctx, key, &bl);
+  if (r < 0) {
+    return r;
+  }
+
+  r = cls_cxx_map_remove_key(hctx, key);
+  if (r < 0) {
+    return r;
+  }
+
+  return 0;
+}
+
+/**
+ * Returns the list of namespaces in the rbd_namespace object
+ *
+ * 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 data list of namespace names
+ * @returns 0 on success, negative error code on failure
+ */
+int namespace_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  string start_after;
+  uint64_t max_return;
+  try {
+    auto iter = in->cbegin();
+    decode(start_after, iter);
+    decode(max_return, iter);
+  } catch (const buffer::error &err) {
+    return -EINVAL;
+  }
+
+  std::list<std::string> data;
+  std::string last_read = nspace::key_for_name(start_after);
+  bool more = true;
+
+  CLS_LOG(20, "namespace_list");
+  while (data.size() < max_return) {
+    std::map<std::string, bufferlist> raw_data;
+    int max_read = std::min<int32_t>(RBD_MAX_KEYS_READ,
+                                     max_return - data.size());
+    int r = cls_cxx_map_get_vals(hctx, last_read, nspace::NAME_KEY_PREFIX,
+                                 max_read, &raw_data, &more);
+    if (r < 0) {
+      CLS_ERR("failed to read the vals off of disk: %s",
+              cpp_strerror(r).c_str());
+      return r;
+    }
+
+    for (auto& it : raw_data) {
+      data.push_back(nspace::name_from_key(it.first));
+    }
+
+    if (raw_data.empty() || !more) {
+      break;
+    }
+
+    last_read = raw_data.rbegin()->first;
+  }
+
+  encode(data, *out);
+  return 0;
+}
+
 CLS_INIT(rbd)
 {
   CLS_LOG(20, "Loaded rbd class!");
@@ -6277,6 +6419,9 @@ CLS_INIT(rbd)
   cls_method_handle_t h_trash_remove;
   cls_method_handle_t h_trash_list;
   cls_method_handle_t h_trash_get;
+  cls_method_handle_t h_namespace_add;
+  cls_method_handle_t h_namespace_remove;
+  cls_method_handle_t h_namespace_list;
 
   cls_register("rbd", &h_class);
   cls_register_cxx_method(h_class, "create",
@@ -6604,5 +6749,13 @@ CLS_INIT(rbd)
                           CLS_METHOD_RD,
                           trash_get, &h_trash_get);
 
-  return;
+  /* rbd_namespace object methods */
+  cls_register_cxx_method(h_class, "namespace_add",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          namespace_add, &h_namespace_add);
+  cls_register_cxx_method(h_class, "namespace_remove",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          namespace_remove, &h_namespace_remove);
+  cls_register_cxx_method(h_class, "namespace_list", CLS_METHOD_RD,
+                          namespace_list, &h_namespace_list);
 }
index fc831ff4136d731f369e64d4dc9613ecb2cad678..daad92d561a6d66ce9ba4771f8ebd68af8dd308e 100644 (file)
@@ -2500,5 +2500,77 @@ namespace librbd {
       return trash_get_finish(&it, trash_spec);
     }
 
+    void namespace_add(librados::ObjectWriteOperation *op,
+                       const std::string &name)
+    {
+      bufferlist bl;
+      encode(name, bl);
+      op->exec("rbd", "namespace_add", bl);
+    }
+
+    int namespace_add(librados::IoCtx *ioctx, const std::string &name)
+    {
+      librados::ObjectWriteOperation op;
+      namespace_add(&op, name);
+
+      return ioctx->operate(RBD_NAMESPACE, &op);
+    }
+
+    void namespace_remove(librados::ObjectWriteOperation *op,
+                          const std::string &name)
+    {
+      bufferlist bl;
+      encode(name, bl);
+      op->exec("rbd", "namespace_remove", bl);
+    }
+
+    int namespace_remove(librados::IoCtx *ioctx, const std::string &name)
+    {
+      librados::ObjectWriteOperation op;
+      namespace_remove(&op, name);
+
+      return ioctx->operate(RBD_NAMESPACE, &op);
+    }
+
+    void namespace_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", "namespace_list", bl);
+    }
+
+    int namespace_list_finish(bufferlist::const_iterator *it,
+                              std::list<std::string> *entries)
+    {
+      assert(entries);
+
+      try {
+       decode(*entries, *it);
+      } catch (const buffer::error &err) {
+       return -EBADMSG;
+      }
+
+      return 0;
+    }
+
+    int namespace_list(librados::IoCtx *ioctx,
+                       const std::string &start, uint64_t max_return,
+                       std::list<std::string> *entries)
+    {
+      librados::ObjectReadOperation op;
+      namespace_list_start(&op, start, max_return);
+
+      bufferlist out_bl;
+      int r = ioctx->operate(RBD_NAMESPACE, &op, &out_bl);
+      if (r < 0) {
+       return r;
+      }
+
+      auto iter = out_bl.cbegin();
+      return namespace_list_finish(&iter, entries);
+    }
+
   } // namespace cls_client
 } // namespace librbd
index 498f47fc871b254330e9273198ae02d03f0d46db..298fc0a9e83d82f201742ec24097555844f79160 100644 (file)
@@ -519,6 +519,21 @@ namespace librbd {
     int trash_get(librados::IoCtx *ioctx, const std::string &id,
                   cls::rbd::TrashImageSpec *trash_spec);
 
+    // operations on rbd_namespace object
+    void namespace_add(librados::ObjectWriteOperation *op,
+                       const std::string &name);
+    int namespace_add(librados::IoCtx *ioctx, const std::string &name);
+    void namespace_remove(librados::ObjectWriteOperation *op,
+                          const std::string &name);
+    int namespace_remove(librados::IoCtx *ioctx, const std::string &name);
+    void namespace_list_start(librados::ObjectReadOperation *op,
+                              const std::string &start, uint64_t max_return);
+    int namespace_list_finish(bufferlist::const_iterator *it,
+                              std::list<std::string> *entries);
+    int namespace_list(librados::IoCtx *ioctx,
+                       const std::string &start, uint64_t max_return,
+                       std::list<std::string> *entries);
+
   } // namespace cls_client
 } // namespace librbd
 #endif // CEPH_LIBRBD_CLS_RBD_CLIENT_H
index df3f2480009550e0f0a36055ab09e85048e76230..b7d680c109880ae314227a489dc2bb0883fd7108 100644 (file)
@@ -41,6 +41,7 @@
 #define RBD_SUFFIX             ".rbd"
 #define RBD_DIRECTORY           "rbd_directory"
 #define RBD_INFO                "rbd_info"
+#define RBD_NAMESPACE           "rbd_namespace"
 
 /*
  * rbd_children object in each pool contains omap entries
index 0534cbeccebff9d505f8645282df12388eeb48ff..9c888c9e0e76247a01dcb1e8955dbb905cabada2 100644 (file)
@@ -2490,6 +2490,7 @@ TEST_F(TestClsRbd, group_snap_get_by_id) {
   ASSERT_EQ(snap.name, received_snap.name);
   ASSERT_EQ(snap.state, received_snap.state);
 }
+
 TEST_F(TestClsRbd, trash_methods)
 {
   librados::IoCtx ioctx;
@@ -2729,3 +2730,37 @@ TEST_F(TestClsRbd, clone_child)
   ASSERT_TRUE((op_features & RBD_OPERATION_FEATURE_CLONE_CHILD) == 0ULL);
 }
 
+TEST_F(TestClsRbd, namespace_methods)
+{
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  string name1 = "123456789";
+  string name2 = "123456780";
+
+  std::list<std::string> entries;
+  ASSERT_EQ(-ENOENT, namespace_list(&ioctx, "", 1024, &entries));
+
+  ASSERT_EQ(0, namespace_add(&ioctx, name1));
+  ASSERT_EQ(-EEXIST, namespace_add(&ioctx, name1));
+
+  ASSERT_EQ(0, namespace_remove(&ioctx, name1));
+  ASSERT_EQ(-ENOENT, namespace_remove(&ioctx, name1));
+
+  ASSERT_EQ(0, namespace_list(&ioctx, "", 1024, &entries));
+  ASSERT_TRUE(entries.empty());
+
+  ASSERT_EQ(0, namespace_add(&ioctx, name1));
+  ASSERT_EQ(0, namespace_add(&ioctx, name2));
+
+  ASSERT_EQ(0, namespace_list(&ioctx, "", 1, &entries));
+  ASSERT_EQ(1U, entries.size());
+  ASSERT_EQ(name2, entries.front());
+
+  ASSERT_EQ(0, namespace_list(&ioctx, name2, 1, &entries));
+  ASSERT_EQ(1U, entries.size());
+  ASSERT_EQ(name1, entries.front());
+
+  ASSERT_EQ(0, namespace_list(&ioctx, name1, 1, &entries));
+  ASSERT_TRUE(entries.empty());
+}