From: Victor Denisov Date: Tue, 28 Jun 2016 03:37:05 +0000 (-0700) Subject: rbd: Add images to consistency groups cli X-Git-Tag: ses5-milestone5~162^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3c70a7611e19e7635f9c1c4755a65990b4c39dc3;p=ceph.git rbd: Add images to consistency groups cli Signed-off-by: Victor Denisov --- diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 175294eac33..875110a9d0b 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -21,6 +21,9 @@ flatten Fill clone with parent data (make it independent). group create Create a consistency group. + group image add Add an image to a consistency group. + group image list List images in a consistency group. + group image remove Remove an image from a consistency group. group list (group ls) List rbd consistency groups. group remove (group rm) Delete a consistency group. image-meta get Image metadata get the value associated with @@ -420,6 +423,65 @@ -p [ --pool ] arg pool name --group arg group name + rbd help group image add + usage: rbd group image add [--group-pool ] [--group ] + [--image-pool ] [--image ] + [--pool ] + + + Add an image to a consistency group. + + Positional arguments + group specification + (example: [/]) + image specification + (example: [/]) + + Optional arguments + --group-pool arg group pool name + --group arg group name + --image-pool arg image pool name + --image arg image name + -p [ --pool ] arg pool name unless overridden + + rbd help group image list + usage: rbd group image list [--format ] [--pretty-format] + [--pool ] [--group ] + + + List images in a consistency group. + + Positional arguments + group specification + (example: [/]) + + Optional arguments + --format arg output format [plain, json, or xml] + --pretty-format pretty formatting (json and xml) + -p [ --pool ] arg pool name + --group arg group name + + rbd help group image remove + usage: rbd group image remove [--group-pool ] [--group ] + [--image-pool ] [--image ] + [--pool ] + + + Remove an image from a consistency group. + + Positional arguments + group specification + (example: [/]) + image specification + (example: [/]) + + Optional arguments + --group-pool arg group pool name + --group arg group name + --image-pool arg image pool name + --image arg image name + -p [ --pool ] arg pool name unless overridden + rbd help group list usage: rbd group list [--pool ] [--format ] [--pretty-format] diff --git a/src/tools/rbd/ArgumentTypes.cc b/src/tools/rbd/ArgumentTypes.cc index 1e80bb69429..910aef041fa 100644 --- a/src/tools/rbd/ArgumentTypes.cc +++ b/src/tools/rbd/ArgumentTypes.cc @@ -56,6 +56,15 @@ std::string get_description_prefix(ArgumentModifier modifier) { } } +void add_special_pool_option(po::options_description *opt, + std::string prefix) { + std::string name = prefix + "-" + POOL_NAME; + std::string description = prefix + " pool name"; + + opt->add_options() + (name.c_str(), po::value(), description.c_str()); +} + void add_pool_option(po::options_description *opt, ArgumentModifier modifier, const std::string &desc_suffix) { diff --git a/src/tools/rbd/ArgumentTypes.h b/src/tools/rbd/ArgumentTypes.h index c311625c91b..016a91bf5ea 100644 --- a/src/tools/rbd/ArgumentTypes.h +++ b/src/tools/rbd/ArgumentTypes.h @@ -117,6 +117,9 @@ std::string get_name_prefix(ArgumentModifier modifier); std::string get_description_prefix(ArgumentModifier modifier); +void add_special_pool_option(boost::program_options::options_description *opt, + std::string prefix); + void add_pool_option(boost::program_options::options_description *opt, ArgumentModifier modifier, const std::string &desc_suffix = ""); diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index 89b437e0c02..b9ad35f9bec 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -178,6 +178,101 @@ std::string get_pool_name(const po::variables_map &vm, return pool_name; } +int get_special_pool_group_names(const po::variables_map &vm, + size_t *arg_index, + std::string *group_pool_name, + std::string *group_name) { + if (nullptr == group_pool_name) return -EINVAL; + if (nullptr == group_name) return -EINVAL; + std::string pool_key = at::POOL_NAME; + + std::string group_pool_key = "group-" + at::POOL_NAME; + std::string group_key = at::GROUP_NAME; + + if (vm.count(group_pool_key)) { + *group_pool_name = vm[group_pool_key].as(); + } + + if (vm.count(group_key)) { + *group_name = vm[group_key].as(); + } + + int r; + if (group_name->empty()) { + std::string spec = utils::get_positional_argument(vm, (*arg_index)++); + if (!spec.empty()) { + r = utils::extract_group_spec(spec, group_pool_name, group_name); + if (r < 0) { + return r; + } + } + } + + if (group_pool_name->empty()) { + *group_pool_name = vm[pool_key].as(); + } + + if (group_pool_name->empty()) { + *group_pool_name = at::DEFAULT_POOL_NAME; + } + + if (group_name->empty()) { + std::cerr << "rbd: consistency group name was not specified" << std::endl; + return -EINVAL; + } + + return 0; +} + +int get_special_pool_image_names(const po::variables_map &vm, + size_t *arg_index, + std::string *image_pool_name, + std::string *image_name) { + if (nullptr == image_pool_name) return -EINVAL; + if (nullptr == image_name) return -EINVAL; + + std::string pool_key = at::POOL_NAME; + + std::string image_pool_key = "image-" + at::POOL_NAME; + std::string image_key = at::IMAGE_NAME; + + if (vm.count(image_pool_key)) { + *image_pool_name = vm[image_pool_key].as(); + } + + if (vm.count(image_key)) { + *image_name = vm[image_key].as(); + } + + int r; + if (image_name->empty()) { + std::string spec = utils::get_positional_argument(vm, (*arg_index)++); + if (!spec.empty()) { + r = utils::extract_spec(spec, image_pool_name, + image_name, nullptr, + utils::SPEC_VALIDATION_NONE); + if (r < 0) { + return r; + } + } + } + + if (image_pool_name->empty()) { + *image_pool_name = vm[pool_key].as(); + } + + if (image_pool_name->empty()) { + *image_pool_name = at::DEFAULT_POOL_NAME; + } + + if (image_name->empty()) { + std::cerr << "rbd: image name was not specified" << std::endl; + return -EINVAL; + } + + return 0; +} + int get_pool_group_names(const po::variables_map &vm, at::ArgumentModifier mod, size_t *spec_arg_index, diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index 453e2ce8b2b..e19a5b3b91c 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -50,6 +50,10 @@ int extract_spec(const std::string &spec, std::string *pool_name, std::string *image_name, std::string *snap_name, SpecValidation spec_validation); +int extract_group_spec(const std::string &spec, + std::string *pool_name, + std::string *group_name); + std::string get_positional_argument( const boost::program_options::variables_map &vm, size_t index); @@ -63,6 +67,16 @@ int get_pool_image_snapshot_names( SnapshotPresence snapshot_presence, SpecValidation spec_validation, bool image_required = true); +int get_special_pool_group_names(const boost::program_options::variables_map &vm, + size_t *arg_index, + std::string *group_pool_name, + std::string *group_name); + +int get_special_pool_image_names(const boost::program_options::variables_map &vm, + size_t *arg_index, + std::string *image_pool_name, + std::string *image_name); + int get_pool_group_names(const boost::program_options::variables_map &vm, argument_types::ArgumentModifier mod, size_t *spec_arg_index, diff --git a/src/tools/rbd/action/Group.cc b/src/tools/rbd/action/Group.cc index ce01c0efa4e..3ad38e5fb5a 100644 --- a/src/tools/rbd/action/Group.cc +++ b/src/tools/rbd/action/Group.cc @@ -6,6 +6,8 @@ #include "tools/rbd/ArgumentTypes.h" #include "tools/rbd/Shell.h" #include "tools/rbd/Utils.h" +#include "include/rbd_types.h" +#include "cls/rbd/cls_rbd_types.h" #include "common/errno.h" #include "common/Formatter.h" @@ -119,6 +121,176 @@ int execute_remove(const po::variables_map &vm) { return 0; } +int execute_add(const po::variables_map &vm) { + size_t arg_index = 0; + // Parse group data. + std::string group_name; + std::string group_pool_name; + + int r = utils::get_special_pool_group_names(vm, &arg_index, + &group_pool_name, + &group_name); + if (r < 0) { + std::cerr << "rbd: image add error: " << cpp_strerror(r) << std::endl; + return r; + } + + std::string image_name; + std::string image_pool_name; + + r = utils::get_special_pool_image_names(vm, &arg_index, + &image_pool_name, + &image_name); + + if (r < 0) { + std::cerr << "rbd: image add error: " << cpp_strerror(r) << std::endl; + return r; + } + + librados::Rados rados; + + librados::IoCtx cg_io_ctx; + r = utils::init(group_pool_name, &rados, &cg_io_ctx); + if (r < 0) { + return r; + } + + librados::IoCtx image_io_ctx; + r = utils::init(image_pool_name, &rados, &image_io_ctx); + if (r < 0) { + return r; + } + + librbd::RBD rbd; + r = rbd.group_image_add(cg_io_ctx, group_name.c_str(), + image_io_ctx, image_name.c_str()); + if (r < 0) { + std::cerr << "rbd: add image error: " << cpp_strerror(r) << std::endl; + return r; + } + + return 0; +} + +int execute_remove_image(const po::variables_map &vm) { + size_t arg_index = 0; + + std::string group_name; + std::string group_pool_name; + + int r = utils::get_special_pool_group_names(vm, &arg_index, + &group_pool_name, + &group_name); + if (r < 0) { + std::cerr << "rbd: image remove error: " << cpp_strerror(r) << std::endl; + return r; + } + + std::string image_name; + std::string image_pool_name; + + r = utils::get_special_pool_image_names(vm, &arg_index, + &image_pool_name, + &image_name); + + if (r < 0) { + std::cerr << "rbd: image remove error: " << cpp_strerror(r) << std::endl; + return r; + } + + librados::Rados rados; + + librados::IoCtx cg_io_ctx; + r = utils::init(group_pool_name, &rados, &cg_io_ctx); + if (r < 0) { + return r; + } + + librados::IoCtx image_io_ctx; + r = utils::init(image_pool_name, &rados, &image_io_ctx); + if (r < 0) { + return r; + } + + librbd::RBD rbd; + r = rbd.group_image_remove(cg_io_ctx, group_name.c_str(), + image_io_ctx, image_name.c_str()); + if (r < 0) { + std::cerr << "rbd: remove image error: " << cpp_strerror(r) << std::endl; + return r; + } + + return 0; +} + +int execute_list_images(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 images; + + r = rbd.group_image_list(io_ctx, group_name.c_str(), images); + + if (r == -ENOENT) + r = 0; + if (r < 0) + return r; + + 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; + std::string state_string; + if (cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE == state) { + state_string = "incomplete"; + } + if (r < 0) + return r; + if (f) { + f->dump_string("image name", image_name); + f->dump_int("pool id", pool_id); + f->dump_int("state", state); + } else + std::cout << pool_id << "." << image_name << " " << state_string << std::endl; + } + if (f) { + f->close_section(); + f->flush(std::cout); + } + + 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); @@ -135,6 +307,56 @@ void get_list_arguments(po::options_description *positional, at::add_format_options(options); } +void get_add_arguments(po::options_description *positional, + po::options_description *options) { + positional->add_options() + (at::GROUP_SPEC.c_str(), + "group specification\n" + "(example: [/])"); + + at::add_special_pool_option(options, "group"); + at::add_group_option(options, at::ARGUMENT_MODIFIER_NONE); + + positional->add_options() + (at::IMAGE_SPEC.c_str(), + "image specification\n" + "(example: [/])"); + + at::add_special_pool_option(options, "image"); + at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); + + at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE, + " unless overridden"); +} + +void get_remove_image_arguments(po::options_description *positional, + po::options_description *options) { + positional->add_options() + (at::GROUP_SPEC.c_str(), + "group specification\n" + "(example: [/])"); + + at::add_special_pool_option(options, "group"); + at::add_group_option(options, at::ARGUMENT_MODIFIER_NONE); + + positional->add_options() + (at::IMAGE_SPEC.c_str(), + "image specification\n" + "(example: [/])"); + + at::add_special_pool_option(options, "image"); + at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); + + at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE, + " unless overridden"); +} + +void get_list_images_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); @@ -144,7 +366,15 @@ Shell::Action action_remove( Shell::Action action_list( {"group", "list"}, {"group", "ls"}, "List rbd consistency groups.", "", &get_list_arguments, &execute_list); - +Shell::Action action_add( + {"group", "image", "add"}, {}, "Add an image to a consistency group.", + "", &get_add_arguments, &execute_add); +Shell::Action action_remove_image( + {"group", "image", "remove"}, {}, "Remove an image from a consistency group.", + "", &get_remove_image_arguments, &execute_remove_image); +Shell::Action action_list_images( + {"group", "image", "list"}, {}, "List images in a consistency group.", + "", &get_list_images_arguments, &execute_list_images); } // namespace snap } // namespace action } // namespace rbd diff --git a/src/tools/rbd/action/Info.cc b/src/tools/rbd/action/Info.cc index 65635e9b2a2..e06324b9d4c 100644 --- a/src/tools/rbd/action/Info.cc +++ b/src/tools/rbd/action/Info.cc @@ -5,6 +5,7 @@ #include "tools/rbd/Shell.h" #include "tools/rbd/Utils.h" #include "include/types.h" +#include "include/stringify.h" #include "common/errno.h" #include "common/Formatter.h" #include @@ -116,6 +117,16 @@ static int do_show_info(const char *imgname, librbd::Image& image, strncpy(prefix, info.block_name_prefix, RBD_MAX_BLOCK_NAME_SIZE); prefix[RBD_MAX_BLOCK_NAME_SIZE] = '\0'; + librbd::group_spec_t group_spec; + r = image.get_group(&group_spec); + if (r < 0) { + return r; + } + + std::string group_string = ""; + if (-1 != group_spec.pool) + group_string = stringify(group_spec.pool) + "." + group_spec.name; + if (f) { f->open_object_section("image"); f->dump_string("name", imgname); @@ -136,7 +147,7 @@ static int do_show_info(const char *imgname, librbd::Image& image, << "\tblock_name_prefix: " << prefix << std::endl << "\tformat: " << (old_format ? "1" : "2") - << std::endl; + << std::endl; } if (!old_format) { @@ -144,6 +155,15 @@ static int do_show_info(const char *imgname, librbd::Image& image, format_flags(f, flags); } + if (!group_string.empty()) { + if (f) { + f->dump_string("group", group_string); + } else { + std::cout << "\tconsistency group: " << group_string + << std::endl; + } + } + // snapshot info, if present if (snapname) { if (f) { diff --git a/src/tools/rbd/action/Remove.cc b/src/tools/rbd/action/Remove.cc index 01b36cbe137..9b2c4eb5bab 100644 --- a/src/tools/rbd/action/Remove.cc +++ b/src/tools/rbd/action/Remove.cc @@ -68,6 +68,23 @@ int execute(const po::variables_map &vm) { << "it crashed. Try again after closing/unmapping it or " << "waiting 30s for the crashed client to timeout." << std::endl; + } else if (r == -EMLINK) { + librbd::Image image; + int image_r = utils::open_image(io_ctx, image_name, true, &image); + librbd::group_spec_t group_spec; + if (image_r == 0) { + image_r = image.get_group(&group_spec); + } + if (image_r == 0) + std::cerr << "rbd: error: image belongs to a consistency group " + << group_spec.pool << "." << group_spec.name; + else + std::cerr << "rbd: error: image belongs to a consistency group"; + + std::cerr << std::endl + << "Remove the image from the consistency group and try again." + << std::endl; + image.close(); } else { std::cerr << "rbd: delete error: " << cpp_strerror(r) << std::endl; }