]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: Add images to consistency groups cli 10034/head
authorVictor Denisov <denisovenator@gmail.com>
Tue, 28 Jun 2016 03:37:05 +0000 (20:37 -0700)
committerVictor Denisov <denisovenator@gmail.com>
Sat, 6 Aug 2016 02:09:28 +0000 (19:09 -0700)
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
src/test/cli/rbd/help.t
src/tools/rbd/ArgumentTypes.cc
src/tools/rbd/ArgumentTypes.h
src/tools/rbd/Utils.cc
src/tools/rbd/Utils.h
src/tools/rbd/action/Group.cc
src/tools/rbd/action/Info.cc
src/tools/rbd/action/Remove.cc

index 175294eac3331acce94f8e3930ce82f43851d140..875110a9d0b61207d53471fa482a219db8ffb3ce 100644 (file)
@@ -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
     -p [ --pool ] arg    pool name
     --group arg          group name
   
+  rbd help group image add
+  usage: rbd group image add [--group-pool <group-pool>] [--group <group>] 
+                             [--image-pool <image-pool>] [--image <image>] 
+                             [--pool <pool>] 
+                             <group-spec> <image-spec> 
+  
+  Add an image to a consistency group.
+  
+  Positional arguments
+    <group-spec>         group specification
+                         (example: [<pool-name>/]<group-name>)
+    <image-spec>         image specification
+                         (example: [<pool-name>/]<image-name>)
+  
+  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 <format>] [--pretty-format] 
+                              [--pool <pool>] [--group <group>] 
+                              <group-spec> 
+  
+  List images in a consistency group.
+  
+  Positional arguments
+    <group-spec>         group specification
+                         (example: [<pool-name>/]<group-name>)
+  
+  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-pool>] [--group <group>] 
+                                [--image-pool <image-pool>] [--image <image>] 
+                                [--pool <pool>] 
+                                <group-spec> <image-spec> 
+  
+  Remove an image from a consistency group.
+  
+  Positional arguments
+    <group-spec>         group specification
+                         (example: [<pool-name>/]<group-name>)
+    <image-spec>         image specification
+                         (example: [<pool-name>/]<image-name>)
+  
+  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 <pool>] [--format <format>] [--pretty-format] 
   
index 1e80bb69429fceb4b41353efc09a2db1e591bdb7..910aef041fa18e0d703559d641e79f103de04e60 100644 (file)
@@ -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<std::string>(), description.c_str());
+}
+
 void add_pool_option(po::options_description *opt,
                      ArgumentModifier modifier,
                      const std::string &desc_suffix) {
index c311625c91b5c4ff993c984c95f2feb03bf3bf08..016a91bf5ea3825b80a5185ce2bca6d664ed1c3f 100644 (file)
@@ -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 = "");
index 89b437e0c02194e5153a5e26aed72ff732b20d04..b9ad35f9bece4e81777dfe69715c82e7e4f7ce21 100644 (file)
@@ -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<std::string>();
+  }
+
+  if (vm.count(group_key)) {
+    *group_name = vm[group_key].as<std::string>();
+  }
+
+  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<std::string>();
+  }
+
+  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<std::string>();
+  }
+
+  if (vm.count(image_key)) {
+    *image_name = vm[image_key].as<std::string>();
+  }
+
+  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<std::string>();
+  }
+
+  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,
index 453e2ce8b2b6d4073ac9f1ac2450eb2f356ddc8e..e19a5b3b91cd92d077c39c4709d70f97f0f68ac9 100644 (file)
@@ -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,
index ce01c0efa4e306ce8e697fd4f7393c71d8a6bb3f..3ad38e5fb5aa511b350bf7661af1ad9bc27cf884 100644 (file)
@@ -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<librbd::group_image_status_t> 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: [<pool-name>/]<group-name>)");
+
+  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: [<pool-name>/]<image-name>)");
+
+  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: [<pool-name>/]<group-name>)");
+
+  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: [<pool-name>/]<image-name>)");
+
+  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
index 65635e9b2a25bdfb35553c1bc302959f3eb19c89..e06324b9d4c2ccbb5700bd5bf5bc9bb9f0b81b37 100644 (file)
@@ -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 <iostream>
@@ -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) {
index 01b36cbe1376eee28ae70114e5bc2280b75d2c21..9b2c4eb5babd353965d1c3b96ca6e180c028ac9c 100644 (file)
@@ -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;
     }