From 50ca45fc95f8ef59ef5a6b4904730571fef2cfff Mon Sep 17 00:00:00 2001 From: Victor Denisov Date: Wed, 28 Sep 2016 20:07:45 -0700 Subject: [PATCH] rbd: Add group snapshot command Signed-off-by: Victor Denisov --- src/tools/rbd/ArgumentTypes.h | 3 + src/tools/rbd/action/Group.cc | 215 ++++++++++++++++++++++++++++++++-- src/tools/rbd/action/Info.cc | 4 +- src/tools/rbd/action/Snap.cc | 78 +++++++++++- 4 files changed, 286 insertions(+), 14 deletions(-) diff --git a/src/tools/rbd/ArgumentTypes.h b/src/tools/rbd/ArgumentTypes.h index 1f7da097643..1837637f94d 100644 --- a/src/tools/rbd/ArgumentTypes.h +++ b/src/tools/rbd/ArgumentTypes.h @@ -129,6 +129,9 @@ std::string get_description_prefix(ArgumentModifier modifier); void add_special_pool_option(boost::program_options::options_description *opt, std::string prefix); +void add_all_option(boost::program_options::options_description *opt, + std::string description); + void add_pool_option(boost::program_options::options_description *opt, ArgumentModifier modifier, const std::string &desc_suffix = ""); diff --git a/src/tools/rbd/action/Group.cc b/src/tools/rbd/action/Group.cc index 40ebd4d9927..c96bcdd48e4 100644 --- a/src/tools/rbd/action/Group.cc +++ b/src/tools/rbd/action/Group.cc @@ -10,6 +10,7 @@ #include "cls/rbd/cls_rbd_types.h" #include "common/errno.h" #include "common/Formatter.h" +#include "common/TextTable.h" namespace rbd { namespace action { @@ -287,20 +288,19 @@ int execute_list_images(const po::variables_map &vm) { if (f) f->open_array_section("consistency_groups"); - for (auto i : images) { - std::string image_name = i.name; - int64_t pool_id = i.pool; - int state = i.state; + for (auto image : images) { + std::string image_name = image.name; + int state = image.state; std::string state_string; - if (cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE == state) { + if (GROUP_IMAGE_STATE_INCOMPLETE == state) { state_string = "incomplete"; } if (f) { f->dump_string("image name", image_name); - f->dump_int("pool id", pool_id); + f->dump_int("pool", image.pool); f->dump_int("state", state); } else - std::cout << pool_id << "." << image_name << " " << state_string << std::endl; + std::cout << image.pool << "/" << image_name << " " << state_string << std::endl; } if (f) { @@ -311,6 +311,172 @@ int execute_list_images(const po::variables_map &vm) { return 0; } +int execute_group_snap_create(const po::variables_map &vm) { + size_t arg_index = 0; + + std::string group_name; + std::string pool_name; + std::string snap_name; + + int r = utils::get_pool_group_names(vm, at::ARGUMENT_MODIFIER_NONE, + &arg_index, &pool_name, &group_name); + if (r < 0) { + return r; + } + + if (vm.count(at::SNAPSHOT_NAME)) { + snap_name = vm[at::SNAPSHOT_NAME].as(); + } + + if (snap_name.empty()) { + snap_name = utils::get_positional_argument(vm, arg_index++); + } + + if (snap_name.empty()) { + std::cerr << "rbd: " + << "snapshot name was not specified" << std::endl; + return -EINVAL; + } + + librados::IoCtx io_ctx; + librados::Rados rados; + + r = utils::init(pool_name, &rados, &io_ctx); + if (r < 0) { + return r; + } + + librbd::RBD rbd; + r = rbd.group_snap_create(io_ctx, group_name.c_str(), snap_name.c_str()); + if (r < 0) { + return r; + } + + return 0; +} + +int execute_group_snap_remove(const po::variables_map &vm) { + size_t arg_index = 0; + + std::string group_name; + std::string pool_name; + std::string snap_name; + + int r = utils::get_pool_group_names(vm, at::ARGUMENT_MODIFIER_NONE, + &arg_index, &pool_name, &group_name); + if (r < 0) { + return r; + } + + if (vm.count(at::SNAPSHOT_NAME)) { + snap_name = vm[at::SNAPSHOT_NAME].as(); + } + + if (snap_name.empty()) { + snap_name = utils::get_positional_argument(vm, arg_index++); + } + + if (snap_name.empty()) { + std::cerr << "rbd: " + << "snapshot name was not specified" << std::endl; + return -EINVAL; + } + + librados::IoCtx io_ctx; + librados::Rados rados; + + r = utils::init(pool_name, &rados, &io_ctx); + if (r < 0) { + return r; + } + + librbd::RBD rbd; + r = rbd.group_snap_remove(io_ctx, group_name.c_str(), snap_name.c_str()); + + return r; +} + +int execute_group_snap_list(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; + } + + if (group_name.empty()) { + std::cerr << "rbd: " + << "consistency group name was not specified" << std::endl; + return -EINVAL; + } + + at::Format::Formatter formatter; + 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 snaps; + + r = rbd.group_snap_list(io_ctx, group_name.c_str(), &snaps); + + if (r == -ENOENT) { + r = 0; + } + if (r < 0) { + return r; + } + + TextTable t; + if (f) { + f->open_array_section("consistency_group_snaps"); + } else { + t.define_column("NAME", TextTable::LEFT, TextTable::LEFT); + t.define_column("STATUS", TextTable::RIGHT, TextTable::RIGHT); + } + + for (auto i : snaps) { + std::string snap_name = i.name; + int state = i.state; + std::string state_string; + if (GROUP_SNAP_STATE_PENDING == state) { + state_string = "pending"; + } else { + state_string = "ok"; + } + if (r < 0) { + return r; + } + if (f) { + f->dump_string("snap name", snap_name); + f->dump_int("state", state); + } else { + t << snap_name << state_string << TextTable::endrow; + } + } + + if (f) { + f->close_section(); + f->flush(std::cout); + } else { + std::cout << t; + } + 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); @@ -378,6 +544,32 @@ void get_list_images_arguments(po::options_description *positional, at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); } +void get_group_snap_create_arguments(po::options_description *positional, + po::options_description *options) { + at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); + + positional->add_options() + (at::SNAPSHOT_NAME.c_str(), "snapshot name\n(example: )"); + + at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); +} + +void get_group_snap_remove_arguments(po::options_description *positional, + po::options_description *options) { + at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); + + positional->add_options() + (at::SNAPSHOT_NAME.c_str(), "snapshot name\n(example: )"); + + at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); +} + +void get_group_snap_list_arguments(po::options_description *positional, + po::options_description *options) { + at::add_format_options(options); + at::add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); +} + Shell::Action action_create( {"group", "create"}, {}, "Create a consistency group.", "", &get_create_arguments, &execute_create); @@ -396,6 +588,15 @@ Shell::Action action_remove_image( Shell::Action action_list_images( {"group", "image", "list"}, {}, "List images in a consistency group.", "", &get_list_images_arguments, &execute_list_images); +Shell::Action action_group_snap_create( + {"group", "snap", "create"}, {}, "Make a snapshot of a group.", + "", &get_group_snap_create_arguments, &execute_group_snap_create); +Shell::Action action_group_snap_remove( + {"group", "snap", "remove"}, {}, "Remove a snapshot from a group.", + "", &get_group_snap_remove_arguments, &execute_group_snap_remove); +Shell::Action action_group_snap_list( + {"group", "snap", "list"}, {}, "List snapshots of a consistency group.", + "", &get_group_snap_list_arguments, &execute_group_snap_list); } // namespace group } // namespace action } // namespace rbd diff --git a/src/tools/rbd/action/Info.cc b/src/tools/rbd/action/Info.cc index d415c9a5859..f0fc383da3c 100644 --- a/src/tools/rbd/action/Info.cc +++ b/src/tools/rbd/action/Info.cc @@ -137,8 +137,8 @@ static int do_show_info(librados::IoCtx &io_ctx, librbd::Image& image, } std::string group_string = ""; - if (-1 != group_spec.pool) - group_string = stringify(group_spec.pool) + "." + group_spec.name; + if (RBD_GROUP_INVALID_POOL != group_spec.pool) + group_string = group_spec.pool + "/" + group_spec.name; struct timespec create_timestamp; image.get_create_timestamp(&create_timestamp); diff --git a/src/tools/rbd/action/Snap.cc b/src/tools/rbd/action/Snap.cc index 2513cebd821..b4f00e58bd3 100644 --- a/src/tools/rbd/action/Snap.cc +++ b/src/tools/rbd/action/Snap.cc @@ -11,15 +11,29 @@ #include "common/TextTable.h" #include #include +#include namespace rbd { namespace action { namespace snap { +static const std::string ALL_NAME("all"); + namespace at = argument_types; namespace po = boost::program_options; -int do_list_snaps(librbd::Image& image, Formatter *f) +static bool is_not_user_snap_namespace(librbd::Image* image, + const librbd::snap_info_t &snap_info) +{ + librbd::snap_namespace_type_t namespace_type; + int r = image->snap_get_namespace_type(snap_info.id, &namespace_type); + if (r < 0) { + return false; + } + return namespace_type != SNAP_NAMESPACE_TYPE_USER; +} + +int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::Rados& rados) { std::vector snaps; TextTable t; @@ -29,6 +43,13 @@ int do_list_snaps(librbd::Image& image, Formatter *f) if (r < 0) return r; + if (!all_snaps) { + snaps.erase(remove_if(snaps.begin(), + snaps.end(), + boost::bind(is_not_user_snap_namespace, &image, _1)), + snaps.end()); + } + if (f) { f->open_array_section("snapshots"); } else { @@ -36,8 +57,15 @@ int do_list_snaps(librbd::Image& image, Formatter *f) t.define_column("NAME", TextTable::LEFT, TextTable::LEFT); t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT); t.define_column("TIMESTAMP", TextTable::LEFT, TextTable::LEFT); + if (all_snaps) { + t.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT); + } } + std::list> pool_list; + rados.pool_list2(pool_list); + std::map pool_map(pool_list.begin(), pool_list.end()); + for (std::vector::iterator s = snaps.begin(); s != snaps.end(); ++s) { struct timespec timestamp; @@ -48,6 +76,8 @@ int do_list_snaps(librbd::Image& image, Formatter *f) tt_str = ctime(&tt); tt_str = tt_str.substr(0, tt_str.length() - 1); } + librbd::group_snap_t group_snap; + int get_group_res = image.snap_get_group(s->id, &group_snap); if (f) { f->open_object_section("snapshot"); @@ -55,10 +85,33 @@ int do_list_snaps(librbd::Image& image, Formatter *f) f->dump_string("name", s->name); f->dump_unsigned("size", s->size); f->dump_string("timestamp", tt_str); + if (all_snaps) { + f->open_object_section("namespace"); + if (get_group_res == 0) { + std::string pool_name = pool_map[group_snap.group_pool]; + f->dump_string("pool", pool_name); + f->dump_string("group", group_snap.group_name); + f->dump_string("group snap", group_snap.group_snap_name); + } + f->close_section(); + } f->close_section(); } else { - t << s->id << s->name << stringify(prettybyte_t(s->size)) << tt_str - << TextTable::endrow; + std::string namespace_string; + if (all_snaps && (get_group_res == 0)) { + ostringstream oss; + std::string pool_name = pool_map[group_snap.group_pool]; + oss << "group snapshot - " << pool_name << "/" << + group_snap.group_name << "@" << + group_snap.group_snap_name; + + namespace_string = oss.str(); + } + t << s->id << s->name << stringify(prettybyte_t(s->size)) << tt_str; + if (all_snaps) { + t << namespace_string; + } + t << TextTable::endrow; } } @@ -87,7 +140,7 @@ int do_remove_snap(librbd::Image& image, const char *snapname, bool force, uint32_t flags = force? RBD_SNAP_REMOVE_FORCE : 0; int r = 0; utils::ProgressContext pc("Removing snap", no_progress); - + r = image.snap_remove2(snapname, flags, pc); if (r < 0) { pc.fail(); @@ -177,11 +230,19 @@ int do_clear_limit(librbd::Image& image) return image.snap_set_limit(UINT64_MAX); } +void add_all_option(po::options_description *opt, std::string description) { + std::string name = ALL_NAME + ",a"; + + opt->add_options() + (name.c_str(), po::bool_switch(), description.c_str()); +} + void get_list_arguments(po::options_description *positional, po::options_description *options) { at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); at::add_image_id_option(options); at::add_format_options(options); + add_all_option(options, "list snapshots from all namespaces"); } int execute_list(const po::variables_map &vm) { @@ -220,6 +281,12 @@ int execute_list(const po::variables_map &vm) { if (r < 0) { return r; } + r = utils::get_pool_image_snapshot_names( + vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name, + &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE); + if (r < 0) { + return r; + } at::Format::Formatter formatter; r = utils::get_formatter(vm, &formatter); @@ -236,7 +303,8 @@ int execute_list(const po::variables_map &vm) { return r; } - r = do_list_snaps(image, formatter.get()); + bool all_snaps = vm[ALL_NAME].as(); + r = do_list_snaps(image, formatter.get(), all_snaps, rados); if (r < 0) { cerr << "rbd: failed to list snapshots: " << cpp_strerror(r) << std::endl; -- 2.39.5