]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: Add group snapshot command
authorVictor Denisov <denisovenator@gmail.com>
Thu, 29 Sep 2016 03:07:45 +0000 (20:07 -0700)
committerJason Dillaman <dillaman@redhat.com>
Thu, 11 Jan 2018 15:38:23 +0000 (10:38 -0500)
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
src/tools/rbd/ArgumentTypes.h
src/tools/rbd/action/Group.cc
src/tools/rbd/action/Info.cc
src/tools/rbd/action/Snap.cc

index 1f7da09764342ee351fb55146ae3547dbe883b13..1837637f94d2f1c2f7f4d3904be0ff2bafc41cf6 100644 (file)
@@ -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 = "");
index 40ebd4d99277c992f3ec2c03a5558ab07792b619..c96bcdd48e4f3c5ffc7f59d3db64c6c98c75b6f7 100644 (file)
@@ -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<std::string>();
+  }
+
+  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<std::string>();
+  }
+
+  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<librbd::group_snap_spec_t> 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: <snapshot-name>)");
+
+  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: <snapshot-name>)");
+
+  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
index d415c9a5859603e7c0e501b301aa626bf5cf7f4e..f0fc383da3c885090b61cb1ffd4e83814f88d9ed 100644 (file)
@@ -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);
index 2513cebd8210ae6c8553c51e29c1b0c1c45f56ce..b4f00e58bd30d34260cab85ca746d2ae7cf4a448 100644 (file)
 #include "common/TextTable.h"
 #include <iostream>
 #include <boost/program_options.hpp>
+#include <boost/bind.hpp>
 
 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<librbd::snap_info_t> 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<std::pair<int64_t, std::string>> pool_list;
+  rados.pool_list2(pool_list);
+  std::map<int64_t, std::string> pool_map(pool_list.begin(), pool_list.end());
+
   for (std::vector<librbd::snap_info_t>::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<bool>();
+  r = do_list_snaps(image, formatter.get(), all_snaps, rados);
   if (r < 0) {
     cerr << "rbd: failed to list snapshots: " << cpp_strerror(r)
          << std::endl;