]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add namespace create/remove/ls actions
authorJason Dillaman <dillaman@redhat.com>
Mon, 18 Jun 2018 22:36:11 +0000 (18:36 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 18 Jun 2018 22:43:40 +0000 (18:43 -0400)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
qa/workunits/rbd/cli_generic.sh
src/test/cli/rbd/help.t
src/tools/rbd/ArgumentTypes.cc
src/tools/rbd/ArgumentTypes.h
src/tools/rbd/CMakeLists.txt
src/tools/rbd/Utils.cc
src/tools/rbd/Utils.h
src/tools/rbd/action/Namespace.cc [new file with mode: 0644]

index b1c54db4e58b4efff6d8066ccb6800d81dcecd3a..219186015055c2cdb64f1ccec8cf55fb5587526a 100755 (executable)
@@ -611,6 +611,26 @@ test_thick_provision() {
     rbd ls | grep test1 | wc -l | grep '^0$'
 }
 
+test_namespace() {
+    echo "testing namespace..."
+    remove_images
+
+    rbd namespace ls | wc -l | grep '^0$'
+    rbd namespace create rbd test1
+    rbd namespace create --pool rbd test2
+    rbd namespace create --namespace test3
+    rbd namespace create rbd test3 || true
+
+    rbd namespace list | grep 'test' | wc -l | grep '^3$'
+
+    rbd namespace remove --pool rbd missing || true
+    rbd namespace remove --pool rbd test1
+    rbd namespace remove --namespace test3
+
+    rbd namespace list | grep 'test' | wc -l | grep '^1$'
+    rbd namespace remove rbd test2
+}
+
 test_pool_image_args
 test_rename
 test_ls
@@ -628,5 +648,6 @@ test_purge
 test_deep_copy_clone
 test_clone_v2
 test_thick_provision
+test_namespace
 
 echo OK
index 387c03e8913a7a4b91f4f383e72d53a4049e9822..efc9e2ffc6d719eb4cc2fbb9545ecca8861c6445 100644 (file)
@@ -82,6 +82,9 @@
                                           pool.
       mirror pool status                  Show status for all mirrored images in
                                           the pool.
+      namespace create                    Create an RBD image namespace.
+      namespace list (namespace ls)       List RBD image namespaces.
+      namespace remove (namespace rm)     Remove an RBD image namespace.
       object-map check                    Verify the object map is correct.
       object-map rebuild                  Rebuild an invalid object map.
       pool init                           Initialize pool for use by RBD.
     --pretty-format      pretty formatting (json and xml)
     --verbose            be verbose
   
+  rbd help namespace create
+  usage: rbd namespace create [--pool <pool>] [--namespace <namespace>] 
+                              <pool-name> <namespace-name> 
+  
+  Create an RBD image namespace.
+  
+  Positional arguments
+    <pool-name>          pool name
+    <namespace-name>     namespace name
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --namespace arg      namespace name
+  
+  rbd help namespace list
+  usage: rbd namespace list [--pool <pool>] [--namespace <namespace>] 
+                            [--format <format>] [--pretty-format] 
+                            <pool-name> <namespace-name> 
+  
+  List RBD image namespaces.
+  
+  Positional arguments
+    <pool-name>          pool name
+    <namespace-name>     namespace name
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --namespace arg      namespace name
+    --format arg         output format (plain, json, or xml) [default: plain]
+    --pretty-format      pretty formatting (json and xml)
+  
+  rbd help namespace remove
+  usage: rbd namespace remove [--pool <pool>] [--namespace <namespace>] 
+                              <pool-name> <namespace-name> 
+  
+  Remove an RBD image namespace.
+  
+  Positional arguments
+    <pool-name>          pool name
+    <namespace-name>     namespace name
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --namespace arg      namespace name
+  
   rbd help object-map check
   usage: rbd object-map check [--pool <pool>] [--image <image>] [--snap <snap>] 
                               [--no-progress] 
index 1ccabc431017adf389b0fa1a91cc504b472e5bbb..1dfe6205851b18f868d3fad3a8dde2a9980069c3 100644 (file)
@@ -92,6 +92,27 @@ void add_pool_option(po::options_description *opt,
     (name.c_str(), po::value<std::string>(), description.c_str());
 }
 
+void add_namespace_option(boost::program_options::options_description *opt,
+                          ArgumentModifier modifier) {
+  std::string name = NAMESPACE_NAME;
+  std::string description = "namespace name";
+  switch (modifier) {
+  case ARGUMENT_MODIFIER_NONE:
+    break;
+  case ARGUMENT_MODIFIER_SOURCE:
+    description = "source " + description;
+    break;
+  case ARGUMENT_MODIFIER_DEST:
+    name = DEST_POOL_NAME;
+    description = "destination " + description;
+    break;
+  }
+
+  // TODO add validator
+  opt->add_options()
+    (name.c_str(), po::value<std::string>(), description.c_str());
+}
+
 void add_image_option(po::options_description *opt,
                       ArgumentModifier modifier,
                       const std::string &desc_suffix) {
@@ -207,6 +228,13 @@ void add_pool_options(boost::program_options::options_description *pos,
     ((POOL_NAME + ",p").c_str(), po::value<std::string>(), "pool name");
 }
 
+void add_namespace_options(boost::program_options::options_description *pos,
+                           boost::program_options::options_description *opt) {
+  pos->add_options()
+    ("namespace-name", "namespace name");
+  add_namespace_option(opt, ARGUMENT_MODIFIER_NONE);
+}
+
 void add_image_spec_options(po::options_description *pos,
                             po::options_description *opt,
                             ArgumentModifier modifier) {
index 887ae78166127f2a95a29315f226a5ed4204167a..f9e44d588893cfe85ddca6f9658763090dfd1d50 100644 (file)
@@ -60,6 +60,7 @@ static const std::string DEST_JOURNAL_NAME("dest-journal");
 static const std::string PATH("path");
 static const std::string FROM_SNAPSHOT_NAME("from-snap");
 static const std::string WHOLE_OBJECT("whole-object");
+static const std::string NAMESPACE_NAME("namespace");
 
 static const std::string IMAGE_FORMAT("image-format");
 static const std::string IMAGE_NEW_FORMAT("new-format");
@@ -137,6 +138,8 @@ void add_all_option(boost::program_options::options_description *opt,
 void add_pool_option(boost::program_options::options_description *opt,
                      ArgumentModifier modifier,
                      const std::string &desc_suffix = "");
+void add_namespace_option(boost::program_options::options_description *opt,
+                          ArgumentModifier modifier);
 
 void add_image_option(boost::program_options::options_description *opt,
                       ArgumentModifier modifier,
@@ -159,6 +162,8 @@ void add_journal_option(boost::program_options::options_description *opt,
 
 void add_pool_options(boost::program_options::options_description *pos,
                       boost::program_options::options_description *opt);
+void add_namespace_options(boost::program_options::options_description *pos,
+                           boost::program_options::options_description *opt);
 
 void add_image_spec_options(boost::program_options::options_description *pos,
                             boost::program_options::options_description *opt,
index 45d5d33768fe2b1c8a74814860e4f943c82d22f8..17154505ef64e4809a5b4d2007adb8114e3b1ea9 100644 (file)
@@ -28,6 +28,7 @@ set(rbd_srcs
   action/MergeDiff.cc
   action/MirrorPool.cc
   action/MirrorImage.cc
+  action/Namespace.cc
   action/Nbd.cc
   action/ObjectMap.cc
   action/Pool.cc
index c34346a707b91046602617e6b3ed100dc0b1db09..d368d5ab11bac229ab4b91df3d96d18f494a293a 100644 (file)
@@ -212,6 +212,21 @@ std::string get_pool_name(const po::variables_map &vm, size_t *arg_index) {
   return pool_name;
 }
 
+std::string get_namespace_name(const boost::program_options::variables_map &vm,
+                               size_t *arg_index) {
+  std::string namespace_name;
+  if (vm.count(at::NAMESPACE_NAME)) {
+    namespace_name = vm[at::NAMESPACE_NAME].as<std::string>();
+  } else {
+    namespace_name = get_positional_argument(vm, *arg_index);
+    if (!namespace_name.empty()) {
+       ++(*arg_index);
+    }
+  }
+
+  return namespace_name;
+}
+
 int get_special_pool_group_names(const po::variables_map &vm,
                                 size_t *arg_index,
                                 std::string *group_pool_name,
index b1b606397a4c5b73d4ff16da7aea115a7f3a20ec..02aa3ce91f12c683a525cb594e58b2c3fa61e981 100644 (file)
@@ -109,6 +109,8 @@ std::string get_positional_argument(
 std::string get_default_pool_name();
 std::string get_pool_name(const boost::program_options::variables_map &vm,
                           size_t *arg_index);
+std::string get_namespace_name(const boost::program_options::variables_map &vm,
+                               size_t *arg_index);
 
 int get_pool_image_snapshot_names(
     const boost::program_options::variables_map &vm,
diff --git a/src/tools/rbd/action/Namespace.cc b/src/tools/rbd/action/Namespace.cc
new file mode 100644 (file)
index 0000000..92224c0
--- /dev/null
@@ -0,0 +1,179 @@
+
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "tools/rbd/ArgumentTypes.h"
+#include "tools/rbd/Shell.h"
+#include "tools/rbd/Utils.h"
+#include "common/errno.h"
+#include "include/stringify.h"
+#include "common/Formatter.h"
+#include "common/TextTable.h"
+#include <algorithm>
+#include <iostream>
+#include <boost/program_options.hpp>
+
+namespace rbd {
+namespace action {
+namespace ns {
+
+namespace at = argument_types;
+namespace po = boost::program_options;
+
+void get_create_arguments(po::options_description *positional,
+                          po::options_description *options) {
+  at::add_pool_options(positional, options);
+  at::add_namespace_options(positional, options);
+}
+
+int execute_create(const po::variables_map &vm,
+                   const std::vector<std::string> &ceph_global_init_args) {
+  size_t arg_index = 0;
+  std::string pool_name = utils::get_pool_name(vm, &arg_index);
+
+  std::string namespace_name = utils::get_namespace_name(vm, &arg_index);
+  if (namespace_name.empty()) {
+    std::cerr << "rbd: namespace name was not specified" << std::endl;
+    return -EINVAL;
+  }
+
+  librados::Rados rados;
+  librados::IoCtx io_ctx;
+  int r = utils::init(pool_name, &rados, &io_ctx);
+  if (r < 0) {
+    return r;
+  }
+
+  librbd::RBD rbd;
+  r = rbd.namespace_create(io_ctx, namespace_name.c_str());
+  if (r < 0) {
+    std::cerr << "rbd: failed to created namespace: " << cpp_strerror(r)
+              << std::endl;
+    return r;
+  }
+
+  return 0;
+}
+
+void get_remove_arguments(po::options_description *positional,
+                          po::options_description *options) {
+  at::add_pool_options(positional, options);
+  at::add_namespace_options(positional, options);
+}
+
+int execute_remove(const po::variables_map &vm,
+                   const std::vector<std::string> &ceph_global_init_args) {
+  size_t arg_index = 0;
+  std::string pool_name = utils::get_pool_name(vm, &arg_index);
+
+  std::string namespace_name = utils::get_namespace_name(vm, &arg_index);
+  if (namespace_name.empty()) {
+    std::cerr << "rbd: namespace name was not specified" << std::endl;
+    return -EINVAL;
+  }
+
+  librados::Rados rados;
+  librados::IoCtx io_ctx;
+  int r = utils::init(pool_name, &rados, &io_ctx);
+  if (r < 0) {
+    return r;
+  }
+
+  librbd::RBD rbd;
+  r = rbd.namespace_remove(io_ctx, namespace_name.c_str());
+  if (r == -EBUSY) {
+    std::cerr << "rbd: namespace contains images which must be deleted first."
+              << std::endl;
+    return r;
+  } else if (r == -ENOENT) {
+    std::cerr << "rbd: namespace does not exist." << std::endl;
+    return r;
+  } else if (r < 0) {
+    std::cerr << "rbd: failed to remove namespace: " << cpp_strerror(r)
+              << std::endl;
+    return r;
+  }
+
+  return 0;
+}
+
+void get_list_arguments(po::options_description *positional,
+                        po::options_description *options) {
+  at::add_pool_options(positional, options);
+  at::add_namespace_options(positional, options);
+  at::add_format_options(options);
+}
+
+int execute_list(const po::variables_map &vm,
+                 const std::vector<std::string> &ceph_global_init_args) {
+  size_t arg_index = 0;
+  std::string pool_name = utils::get_pool_name(vm, &arg_index);
+
+  at::Format::Formatter formatter;
+  int r = utils::get_formatter(vm, &formatter);
+  if (r < 0) {
+    return r;
+  }
+
+  librados::Rados rados;
+  librados::IoCtx io_ctx;
+  r = utils::init(pool_name, &rados, &io_ctx);
+  if (r < 0) {
+    return r;
+  }
+
+  librbd::RBD rbd;
+  std::vector<std::string> names;
+  r = rbd.namespace_list(io_ctx, &names);
+  if (r < 0 && r != -ENOENT) {
+    std::cerr << "rbd: failed to list namespaces: " << cpp_strerror(r)
+              << std::endl;
+    return r;
+  }
+
+  std::sort(names.begin(), names.end());
+
+  TextTable tbl;
+  if (formatter) {
+    formatter->open_array_section("namespaces");
+  } else {
+    tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
+  }
+
+  for (auto& name : names) {
+    if (formatter) {
+      formatter->open_object_section("namespace");
+      formatter->dump_string("name", name);
+      formatter->close_section();
+    } else {
+      tbl << name << TextTable::endrow;
+    }
+  }
+
+  if (formatter) {
+    formatter->close_section();
+    formatter->flush(std::cout);
+  } else if (!names.empty()) {
+    std::cout << tbl;
+  }
+
+  return 0;
+}
+
+Shell::Action action_move(
+  {"namespace", "create"}, {},
+   "Create an RBD image namespace.", "",
+  &get_create_arguments, &execute_create);
+
+Shell::Action action_remove(
+  {"namespace", "remove"}, {"namespace", "rm"},
+   "Remove an RBD image namespace.", "",
+  &get_remove_arguments, &execute_remove);
+
+Shell::Action action_list(
+  {"namespace", "list"}, {"namespace", "ls"}, "List RBD image namespaces.", "",
+  &get_list_arguments, &execute_list);
+
+} // namespace ns
+} // namespace action
+} // namespace rbd