tools/rbd/action/BenchWrite.cc \
tools/rbd/action/Children.cc \
tools/rbd/action/Clone.cc \
+ tools/rbd/action/Group.cc \
tools/rbd/action/Copy.cc \
tools/rbd/action/Create.cc \
tools/rbd/action/Diff.cc \
(name.c_str(), po::value<std::string>(), description.c_str());
}
+void add_group_option(po::options_description *opt,
+ ArgumentModifier modifier,
+ const std::string &desc_suffix) {
+ std::string name = GROUP_NAME;
+ std::string description = "group name";
+ switch (modifier) {
+ case ARGUMENT_MODIFIER_NONE:
+ break;
+ case ARGUMENT_MODIFIER_SOURCE:
+ description = "source " + description;
+ break;
+ case ARGUMENT_MODIFIER_DEST:
+ name = DEST_GROUP_NAME;
+ description = "destination " + description;
+ break;
+ }
+ description += desc_suffix;
+
+ // TODO add validator
+ opt->add_options()
+ (name.c_str(), po::value<std::string>(), description.c_str());
+}
+
void add_snap_option(po::options_description *opt,
ArgumentModifier modifier) {
add_image_option(opt, modifier);
}
+void add_group_spec_options(po::options_description *pos,
+ po::options_description *opt,
+ ArgumentModifier modifier) {
+ pos->add_options()
+ ((get_name_prefix(modifier) + GROUP_SPEC).c_str(),
+ (get_description_prefix(modifier) + "group specification\n" +
+ "(example: [<pool-name>/]<group-name>)").c_str());
+ add_pool_option(opt, modifier);
+ add_group_option(opt, modifier);
+}
+
void add_snap_spec_options(po::options_description *pos,
po::options_description *opt,
ArgumentModifier modifier) {
static const std::string POSITIONAL_COMMAND_SPEC("positional-command-spec");
static const std::string POSITIONAL_ARGUMENTS("positional-arguments");
static const std::string IMAGE_SPEC("image-spec");
+static const std::string GROUP_SPEC("group-spec");
static const std::string SNAPSHOT_SPEC("snap-spec");
static const std::string IMAGE_OR_SNAPSHOT_SPEC("image-or-snap-spec");
static const std::string JOURNAL_SPEC("journal-spec");
static const std::string DEST_POOL_NAME("dest-pool");
static const std::string IMAGE_NAME("image");
static const std::string DEST_IMAGE_NAME("dest");
+static const std::string GROUP_NAME("group");
+static const std::string DEST_GROUP_NAME("dest-group");
static const std::string SNAPSHOT_NAME("snap");
static const std::string DEST_SNAPSHOT_NAME("dest-snap");
static const std::string JOURNAL_NAME("journal");
ArgumentModifier modifier,
const std::string &desc_suffix = "");
+void add_group_option(boost::program_options::options_description *opt,
+ ArgumentModifier modifier,
+ const std::string &desc_suffix = "");
+
void add_snap_option(boost::program_options::options_description *opt,
ArgumentModifier modifier);
boost::program_options::options_description *opt,
ArgumentModifier modifier);
+void add_group_spec_options(boost::program_options::options_description *pos,
+ boost::program_options::options_description *opt,
+ ArgumentModifier modifier);
+
void add_snap_spec_options(boost::program_options::options_description *pos,
boost::program_options::options_description *opt,
ArgumentModifier modifier);
return 0;
}
+int extract_group_spec(const std::string &spec,
+ std::string *pool_name,
+ std::string *group_name) {
+ boost::regex pattern;
+ pattern = "^(?:([^/]+)/)?(.+)?$";
+
+ boost::smatch match;
+ if (!boost::regex_match(spec, match, pattern)) {
+ std::cerr << "rbd: invalid spec '" << spec << "'" << std::endl;
+ return -EINVAL;
+ }
+
+ if (pool_name != nullptr && match[1].matched) {
+ *pool_name = match[1];
+ }
+ if (group_name != nullptr) {
+ *group_name = match[2];
+ }
+
+ return 0;
+}
+
std::string get_positional_argument(const po::variables_map &vm, size_t index) {
if (vm.count(at::POSITIONAL_ARGUMENTS) == 0) {
return "";
return pool_name;
}
+int get_pool_group_names(const po::variables_map &vm,
+ at::ArgumentModifier mod,
+ size_t *spec_arg_index,
+ std::string *pool_name,
+ std::string *group_name) {
+ std::string pool_key = (mod == at::ARGUMENT_MODIFIER_DEST ?
+ at::DEST_POOL_NAME : at::POOL_NAME);
+ std::string group_key = (mod == at::ARGUMENT_MODIFIER_DEST ?
+ at::DEST_GROUP_NAME : at::GROUP_NAME);
+
+ if (vm.count(pool_key) && pool_name != nullptr) {
+ *pool_name = vm[pool_key].as<std::string>();
+ }
+ if (vm.count(group_key) && group_name != nullptr) {
+ *group_name = vm[group_key].as<std::string>();
+ }
+
+ int r;
+ if (group_name != nullptr && spec_arg_index != nullptr &&
+ group_name->empty()) {
+ std::string spec = get_positional_argument(vm, (*spec_arg_index)++);
+ if (!spec.empty()) {
+ r = extract_group_spec(spec, pool_name, group_name);
+ if (r < 0) {
+ return r;
+ }
+ }
+ }
+
+ if (pool_name->empty()) {
+ *pool_name = at::DEFAULT_POOL_NAME;
+ }
+
+ if (group_name != nullptr && group_name->empty()) {
+ std::string prefix = at::get_description_prefix(mod);
+ std::cerr << "rbd: "
+ << (mod == at::ARGUMENT_MODIFIER_DEST ? prefix : std::string())
+ << "group name was not specified" << std::endl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int get_pool_image_snapshot_names(const po::variables_map &vm,
at::ArgumentModifier mod,
size_t *spec_arg_index,
SnapshotPresence snapshot_presence, SpecValidation spec_validation,
bool image_required = true);
+int get_pool_group_names(const boost::program_options::variables_map &vm,
+ argument_types::ArgumentModifier mod,
+ size_t *spec_arg_index,
+ std::string *pool_name,
+ std::string *group_name);
+
int get_pool_journal_names(
const boost::program_options::variables_map &vm,
argument_types::ArgumentModifier mod, size_t *spec_arg_index,
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <iostream>
+
+#include "tools/rbd/ArgumentTypes.h"
+#include "tools/rbd/Shell.h"
+#include "tools/rbd/Utils.h"
+#include "common/errno.h"
+#include "common/Formatter.h"
+
+namespace rbd {
+namespace action {
+namespace consgrp {
+
+namespace at = argument_types;
+namespace po = boost::program_options;
+
+int execute_create(const po::variables_map &vm) {
+ size_t arg_index = 0;
+
+ std::string group_name;
+ std::string pool_name;
+
+ int r = utils::get_pool_group_names(vm, at::ARGUMENT_MODIFIER_NONE,
+ &arg_index, &pool_name, &group_name);
+ 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;
+ r = rbd.group_create(io_ctx, group_name.c_str());
+ if (r < 0) {
+ std::cerr << "rbd: create error: " << cpp_strerror(r) << std::endl;
+ return r;
+ }
+
+ return 0;
+}
+
+int execute_list(const po::variables_map &vm) {
+
+ 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;
+ }
+ Formatter *f = formatter.get();
+
+ 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.group_list(io_ctx, names);
+
+ if (r == -ENOENT)
+ r = 0;
+ if (r < 0)
+ return r;
+
+ if (f)
+ f->open_array_section("consistency_groups");
+ for (auto i : names) {
+ if (f)
+ f->dump_string("name", i);
+ else
+ std::cout << i << std::endl;
+ }
+ if (f) {
+ f->close_section();
+ f->flush(std::cout);
+ }
+
+ return 0;
+}
+
+int execute_remove(const po::variables_map &vm) {
+ size_t arg_index = 0;
+
+ std::string group_name;
+ std::string pool_name;
+
+ int r = utils::get_pool_group_names(vm, at::ARGUMENT_MODIFIER_NONE,
+ &arg_index, &pool_name, &group_name);
+ 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;
+
+ r = rbd.group_remove(io_ctx, group_name.c_str());
+ if (r < 0) {
+ std::cerr << "rbd: remove error: " << cpp_strerror(r) << std::endl;
+ return r;
+ }
+
+ return 0;
+}
+
+void get_create_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+}
+
+void get_remove_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+}
+
+void get_list_arguments(po::options_description *positional,
+ po::options_description *options) {
+ add_pool_option(options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_format_options(options);
+}
+
+Shell::Action action_create(
+ {"group", "create"}, {}, "Create a consistency group.",
+ "", &get_create_arguments, &execute_create);
+Shell::Action action_remove(
+ {"group", "remove"}, {"group", "rm"}, "Delete a consistency group.",
+ "", &get_remove_arguments, &execute_remove);
+Shell::Action action_list(
+ {"group", "list"}, {"group", "ls"}, "List rbd consistency groups.",
+ "", &get_list_arguments, &execute_list);
+
+} // namespace snap
+} // namespace action
+} // namespace rbd