]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: add namespace create/remove/list API methods
authorJason Dillaman <dillaman@redhat.com>
Fri, 15 Jun 2018 13:20:55 +0000 (09:20 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 18 Jun 2018 22:43:39 +0000 (18:43 -0400)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/CMakeLists.txt
src/librbd/api/Namespace.cc [new file with mode: 0644]
src/librbd/api/Namespace.h [new file with mode: 0644]
src/librbd/librbd.cc
src/test/librbd/test_librbd.cc

index ee86d8aad23011fe3b82cc3f34396f05bed955de..811bccb7ea825239ac34a5037b895df9db7ad704 100644 (file)
@@ -978,6 +978,13 @@ CEPH_RBD_API int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
                                              size_t group_snap_info_size,
                                              size_t num_entries);
 
+CEPH_RBD_API int rbd_namespace_create(rados_ioctx_t io,
+                                      const char *namespace_name);
+CEPH_RBD_API int rbd_namespace_remove(rados_ioctx_t io,
+                                      const char *namespace_name);
+CEPH_RBD_API int rbd_namespace_list(rados_ioctx_t io, char *namespace_names,
+                                    size_t *size);
+
 #ifdef __cplusplus
 }
 #endif
index bbfb7b1e36b7f3270a5d213f735f95d3f6a56bda..5db6f44a37aa63e6511e8e05df6a36c98c42985a 100644 (file)
@@ -239,6 +239,10 @@ public:
                       std::vector<group_snap_info_t> *snaps,
                       size_t group_snap_info_size);
 
+  int namespace_create(IoCtx& ioctx, const char *namespace_name);
+  int namespace_remove(IoCtx& ioctx, const char *namespace_name);
+  int namespace_list(IoCtx& io_ctx, std::vector<std::string>* namespace_names);
+
 private:
   /* We don't allow assignment or copying */
   RBD(const RBD& rhs);
index 88682ef9c165428fe905fdfa8d3ce0e02f631234..768902e55a606e7cbe9ca1b73b7a02d8054f658b 100644 (file)
@@ -28,6 +28,7 @@ set(librbd_internal_srcs
   api/Group.cc
   api/Image.cc
   api/Mirror.cc
+  api/Namespace.cc
   api/Snapshot.cc
   cache/ImageWriteback.cc
   cache/ObjectCacherObjectDispatch.cc
diff --git a/src/librbd/api/Namespace.cc b/src/librbd/api/Namespace.cc
new file mode 100644 (file)
index 0000000..f73ae84
--- /dev/null
@@ -0,0 +1,161 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "common/errno.h"
+#include "cls/rbd/cls_rbd_client.h"
+#include "librbd/api/Namespace.h"
+#include "librbd/ImageCtx.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::api::Namespace: " << __func__ << ": "
+
+namespace librbd {
+namespace api {
+
+template <typename I>
+int Namespace<I>::create(librados::IoCtx& io_ctx, const std::string& name)
+{
+  CephContext *cct = (CephContext *)io_ctx.cct();
+  ldout(cct, 5) << "name=" << name << dendl;
+
+  if (name.empty()) {
+    return -EINVAL;
+  }
+
+  librados::IoCtx default_ns_ctx;
+  default_ns_ctx.dup(io_ctx);
+  default_ns_ctx.set_namespace("");
+
+  int r = cls_client::namespace_add(&default_ns_ctx, name);
+  if (r < 0) {
+    lderr(cct) << "failed to add namespace: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  librados::IoCtx ns_ctx;
+  ns_ctx.dup(io_ctx);
+  ns_ctx.set_namespace(name);
+
+  r = cls_client::dir_state_set(&ns_ctx, RBD_DIRECTORY,
+                                cls::rbd::DIRECTORY_STATE_READY);
+  if (r < 0) {
+    lderr(cct) << "failed to initialize image directory: " << cpp_strerror(r)
+               << dendl;
+    goto rollback;
+  }
+
+  return 0;
+
+rollback:
+  int ret_val = cls_client::namespace_remove(&default_ns_ctx, name);
+  if (ret_val < 0) {
+    lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl;
+  }
+
+  return r;
+}
+
+template <typename I>
+int Namespace<I>::remove(librados::IoCtx& io_ctx, const std::string& name)
+{
+  CephContext *cct = (CephContext *)io_ctx.cct();
+  ldout(cct, 5) << "name=" << name << dendl;
+
+  if (name.empty()) {
+    return -EINVAL;
+  }
+
+  librados::IoCtx default_ns_ctx;
+  default_ns_ctx.dup(io_ctx);
+  default_ns_ctx.set_namespace("");
+
+  librados::IoCtx ns_ctx;
+  ns_ctx.dup(io_ctx);
+  ns_ctx.set_namespace(name);
+
+  std::map<std::string, cls::rbd::TrashImageSpec> trash_entries;
+
+  librados::ObjectWriteOperation dir_op;
+  librbd::cls_client::dir_state_set(
+    &dir_op, cls::rbd::DIRECTORY_STATE_ADD_DISABLED);
+  dir_op.remove();
+
+  int r = ns_ctx.operate(RBD_DIRECTORY, &dir_op);
+  if (r == -EBUSY) {
+    ldout(cct, 5) << "image directory not empty" << dendl;
+    goto rollback;
+  } else if (r < 0 && r != -ENOENT) {
+    lderr(cct) << "failed to disable the namespace: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  }
+
+  r = cls_client::trash_list(&ns_ctx, "", 1, &trash_entries);
+  if (r < 0 && r != -ENOENT) {
+    lderr(cct) << "failed to list trash directory: " << cpp_strerror(r)
+               << dendl;
+    return r;
+  } else if (!trash_entries.empty()) {
+    ldout(cct, 5) << "image trash not empty" << dendl;
+    goto rollback;
+  }
+
+  r = cls_client::namespace_remove(&default_ns_ctx, name);
+  if (r < 0) {
+    lderr(cct) << "failed to remove namespace: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  return 0;
+
+rollback:
+
+  r = librbd::cls_client::dir_state_set(
+    &ns_ctx, RBD_DIRECTORY, cls::rbd::DIRECTORY_STATE_READY);
+  if (r < 0) {
+    lderr(cct) << "failed to restore directory state: " << cpp_strerror(r)
+               << dendl;
+  }
+
+  return -EBUSY;
+}
+
+template <typename I>
+int Namespace<I>::list(IoCtx& io_ctx, vector<string> *names)
+{
+  CephContext *cct = (CephContext *)io_ctx.cct();
+  ldout(cct, 5) << dendl;
+
+  librados::IoCtx default_ns_ctx;
+  default_ns_ctx.dup(io_ctx);
+  default_ns_ctx.set_namespace("");
+
+  int r;
+  int max_read = 1024;
+  std::string last_read = "";
+  do {
+    std::list<std::string> name_list;
+    r = cls_client::namespace_list(&default_ns_ctx, last_read, max_read,
+                                   &name_list);
+    if (r == -ENOENT) {
+      return 0;
+    } else if (r < 0) {
+      lderr(cct) << "error listing namespaces: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    names->insert(names->end(), name_list.begin(), name_list.end());
+    if (!name_list.empty()) {
+      last_read = name_list.back();
+    }
+    r = name_list.size();
+  } while (r == max_read);
+
+  return 0;
+}
+
+} // namespace api
+} // namespace librbd
+
+template class librbd::api::Namespace<librbd::ImageCtx>;
diff --git a/src/librbd/api/Namespace.h b/src/librbd/api/Namespace.h
new file mode 100644 (file)
index 0000000..c892a3b
--- /dev/null
@@ -0,0 +1,33 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_API_NAMESPACE_H
+#define CEPH_LIBRBD_API_NAMESPACE_H
+
+#include "include/rbd/librbd.hpp"
+#include <string>
+#include <vector>
+
+namespace librados { struct IoCtx; }
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace api {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+struct Namespace {
+
+  static int create(librados::IoCtx& io_ctx, const std::string& name);
+  static int remove(librados::IoCtx& io_ctx, const std::string& name);
+  static int list(librados::IoCtx& io_ctx, std::vector<std::string>* names);
+
+};
+
+} // namespace api
+} // namespace librbd
+
+extern template class librbd::api::Namespace<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_API_NAMESPACE_H
index 7bd023d4781b21c99abe4c50a57bcaf87d084981..d46a46f713e8c40cd299305838149a49c99cfb96 100644 (file)
@@ -30,6 +30,7 @@
 #include "librbd/api/Group.h"
 #include "librbd/api/Image.h"
 #include "librbd/api/Mirror.h"
+#include "librbd/api/Namespace.h"
 #include "librbd/api/Snapshot.h"
 #include "librbd/io/AioCompletion.h"
 #include "librbd/io/ImageRequestWQ.h"
@@ -615,6 +616,19 @@ namespace librbd {
     return r;
   }
 
+  int RBD::namespace_create(IoCtx& io_ctx, const char *namespace_name) {
+    return librbd::api::Namespace<>::create(io_ctx, namespace_name);
+  }
+
+  int RBD::namespace_remove(IoCtx& io_ctx, const char *namespace_name) {
+    return librbd::api::Namespace<>::remove(io_ctx, namespace_name);
+  }
+
+  int RBD::namespace_list(IoCtx& io_ctx,
+                          std::vector<std::string>* namespace_names) {
+    return librbd::api::Namespace<>::list(io_ctx, namespace_names);
+  }
+
   int RBD::list(IoCtx& io_ctx, vector<string>& names)
   {
     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
@@ -2684,6 +2698,54 @@ extern "C" int rbd_trash_restore(rados_ioctx_t p, const char *id,
   return r;
 }
 
+extern "C" int rbd_namespace_create(rados_ioctx_t io,
+                                    const char *namespace_name) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
+
+  return librbd::api::Namespace<>::create(io_ctx, namespace_name);
+}
+
+extern "C" int rbd_namespace_remove(rados_ioctx_t io,
+                                    const char *namespace_name) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
+
+  return librbd::api::Namespace<>::remove(io_ctx, namespace_name);
+}
+
+extern "C" int rbd_namespace_list(rados_ioctx_t io, char *names, size_t *size) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
+
+  if (names == nullptr || size == nullptr) {
+    return -EINVAL;
+  }
+
+  std::vector<std::string> cpp_names;
+  int r = librbd::api::Namespace<>::list(io_ctx, &cpp_names);
+  if (r < 0) {
+    return r;
+  }
+
+  size_t expected_size = 0;
+  for (size_t i = 0; i < cpp_names.size(); i++) {
+    expected_size += cpp_names[i].size() + 1;
+  }
+  if (*size < expected_size) {
+    *size = expected_size;
+    return -ERANGE;
+  }
+
+  for (int i = 0; i < (int)cpp_names.size(); i++) {
+    const char* name = cpp_names[i].c_str();
+    strcpy(names, name);
+    names += strlen(names) + 1;
+  }
+
+  return (int)expected_size;
+}
+
 extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
                        const char *destname)
 {
index d4e17b6d54506da60822cea731320d11cc2a6871..10666fcc09923964d59e82b83cf0fb0a4c8d9bbe 100644 (file)
@@ -6623,6 +6623,57 @@ TEST_F(TestLibRBD, TestSetSnapById) {
   ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
 }
 
+TEST_F(TestLibRBD, Namespaces) {
+  rados_ioctx_t ioctx;
+  ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx));
+  rados_remove(ioctx, RBD_NAMESPACE);
+
+  ASSERT_EQ(0, rbd_namespace_create(ioctx, "name1"));
+  ASSERT_EQ(0, rbd_namespace_create(ioctx, "name2"));
+  ASSERT_EQ(0, rbd_namespace_create(ioctx, "name3"));
+  ASSERT_EQ(0, rbd_namespace_remove(ioctx, "name2"));
+
+  char names[1024];
+  size_t max_size = sizeof(names);
+  int len = rbd_namespace_list(ioctx, names, &max_size);
+
+  std::vector<std::string> cpp_names;
+  for (char* cur_name = names; cur_name < names + len; ) {
+    cpp_names.push_back(cur_name);
+    cur_name += strlen(cur_name) + 1;
+  }
+  ASSERT_EQ(2U, cpp_names.size());
+  ASSERT_EQ("name1", cpp_names[0]);
+  ASSERT_EQ("name3", cpp_names[1]);
+
+  rados_ioctx_destroy(ioctx);
+}
+
+TEST_F(TestLibRBD, NamespacesPP) {
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+  ioctx.remove(RBD_NAMESPACE);
+
+  librbd::RBD rbd;
+  ASSERT_EQ(-EINVAL, rbd.namespace_create(ioctx, ""));
+  ASSERT_EQ(-EINVAL, rbd.namespace_remove(ioctx, ""));
+
+  ASSERT_EQ(0, rbd.namespace_create(ioctx, "name1"));
+  ASSERT_EQ(-EEXIST, rbd.namespace_create(ioctx, "name1"));
+  ASSERT_EQ(0, rbd.namespace_create(ioctx, "name2"));
+  ASSERT_EQ(0, rbd.namespace_create(ioctx, "name3"));
+  ASSERT_EQ(0, rbd.namespace_remove(ioctx, "name2"));
+  ASSERT_EQ(-ENOENT, rbd.namespace_remove(ioctx, "name2"));
+
+  std::vector<std::string> names;
+  ASSERT_EQ(0, rbd.namespace_list(ioctx, &names));
+  ASSERT_EQ(2U, names.size());
+
+  ASSERT_EQ(2U, names.size());
+  ASSERT_EQ("name1", names[0]);
+  ASSERT_EQ("name3", names[1]);
+}
+
 // poorman's assert()
 namespace ceph {
   void __ceph_assert_fail(const char *assertion, const char *file, int line,