From 4437c136b419f4f023aa05cfb5f3cc86c622a18b Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 18 Jun 2018 18:36:11 -0400 Subject: [PATCH] rbd: add namespace create/remove/ls actions Signed-off-by: Jason Dillaman --- qa/workunits/rbd/cli_generic.sh | 21 ++++ src/test/cli/rbd/help.t | 48 ++++++++ src/tools/rbd/ArgumentTypes.cc | 28 +++++ src/tools/rbd/ArgumentTypes.h | 5 + src/tools/rbd/CMakeLists.txt | 1 + src/tools/rbd/Utils.cc | 15 +++ src/tools/rbd/Utils.h | 2 + src/tools/rbd/action/Namespace.cc | 179 ++++++++++++++++++++++++++++++ 8 files changed, 299 insertions(+) create mode 100644 src/tools/rbd/action/Namespace.cc diff --git a/qa/workunits/rbd/cli_generic.sh b/qa/workunits/rbd/cli_generic.sh index b1c54db4e58b4..219186015055c 100755 --- a/qa/workunits/rbd/cli_generic.sh +++ b/qa/workunits/rbd/cli_generic.sh @@ -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 diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 387c03e8913a7..efc9e2ffc6d71 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -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. @@ -1303,6 +1306,51 @@ --pretty-format pretty formatting (json and xml) --verbose be verbose + rbd help namespace create + usage: rbd namespace create [--pool ] [--namespace ] + + + Create an RBD image namespace. + + Positional arguments + pool name + namespace name + + Optional arguments + -p [ --pool ] arg pool name + --namespace arg namespace name + + rbd help namespace list + usage: rbd namespace list [--pool ] [--namespace ] + [--format ] [--pretty-format] + + + List RBD image namespaces. + + Positional arguments + pool 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 ] [--namespace ] + + + Remove an RBD image namespace. + + Positional arguments + pool 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 ] [--image ] [--snap ] [--no-progress] diff --git a/src/tools/rbd/ArgumentTypes.cc b/src/tools/rbd/ArgumentTypes.cc index 1ccabc431017a..1dfe6205851b1 100644 --- a/src/tools/rbd/ArgumentTypes.cc +++ b/src/tools/rbd/ArgumentTypes.cc @@ -92,6 +92,27 @@ void add_pool_option(po::options_description *opt, (name.c_str(), po::value(), 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(), 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(), "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) { diff --git a/src/tools/rbd/ArgumentTypes.h b/src/tools/rbd/ArgumentTypes.h index 887ae78166127..f9e44d588893c 100644 --- a/src/tools/rbd/ArgumentTypes.h +++ b/src/tools/rbd/ArgumentTypes.h @@ -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, diff --git a/src/tools/rbd/CMakeLists.txt b/src/tools/rbd/CMakeLists.txt index 45d5d33768fe2..17154505ef64e 100644 --- a/src/tools/rbd/CMakeLists.txt +++ b/src/tools/rbd/CMakeLists.txt @@ -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 diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index c34346a707b91..d368d5ab11bac 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -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(); + } 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, diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index b1b606397a4c5..02aa3ce91f12c 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -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 index 0000000000000..92224c08942f6 --- /dev/null +++ b/src/tools/rbd/action/Namespace.cc @@ -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 +#include +#include + +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 &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 &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 &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 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 -- 2.39.5