]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/tools/rbd/action/Snap.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / tools / rbd / action / Snap.cc
index 59312ff226dfa2a5649841956c5cec20c133cef6..70cf62dab0cc406000ed2205c54c0db5bc26447e 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)
+int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::Rados& rados)
 {
   std::vector<librbd::snap_info_t> snaps;
   TextTable t;
   int r;
 
   r = image.snap_list(snaps);
-  if (r < 0)
+  if (r < 0) {
+    std::cerr << "rbd: unable to list snapshots" << std::endl;
     return r;
+  }
+
+  if (!all_snaps) {
+    snaps.erase(remove_if(snaps.begin(),
+                          snaps.end(),
+                          boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
+                snaps.end());
+  }
 
   if (f) {
     f->open_array_section("snapshots");
   } else {
-    t.define_column("SNAPID", TextTable::RIGHT, TextTable::RIGHT);
+    t.define_column("SNAPID", TextTable::LEFT, TextTable::RIGHT);
     t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
-    t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
-    t.define_column("TIMESTAMP", TextTable::LEFT, TextTable::LEFT);
+    t.define_column("SIZE", TextTable::LEFT, TextTable::RIGHT);
+    t.define_column("PROTECTED", TextTable::LEFT, TextTable::LEFT);
+    t.define_column("TIMESTAMP", TextTable::LEFT, TextTable::RIGHT);
+    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;
+    bool snap_protected = false;
     image.snap_get_timestamp(s->id, &timestamp);
     string tt_str = "";
     if(timestamp.tv_sec != 0) {
       time_t tt = timestamp.tv_sec;
       tt_str = ctime(&tt);
-      tt_str = tt_str.substr(0, tt_str.length() - 1);  
+      tt_str = tt_str.substr(0, tt_str.length() - 1);
+    }
+
+    librbd::snap_namespace_type_t snap_namespace;
+    r = image.snap_get_namespace_type(s->id, &snap_namespace);
+    if (r < 0) {
+      std::cerr << "rbd: unable to retrieve snap namespace" << std::endl;
+      return r;
+    }
+
+    std::string snap_namespace_name = "Unknown";
+    switch (snap_namespace) {
+    case RBD_SNAP_NAMESPACE_TYPE_USER:
+      snap_namespace_name = "user";
+      break;
+    case RBD_SNAP_NAMESPACE_TYPE_GROUP:
+      snap_namespace_name = "group";
+      break;
+    case RBD_SNAP_NAMESPACE_TYPE_TRASH:
+      snap_namespace_name = "trash";
+      break;
+    }
+
+    int get_trash_res = -ENOENT;
+    std::string trash_original_name;
+    int get_group_res = -ENOENT;
+    librbd::snap_group_namespace_t group_snap;
+    if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_GROUP) {
+      get_group_res = image.snap_get_group_namespace(s->id, &group_snap,
+                                                     sizeof(group_snap));
+    } else if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_TRASH) {
+      get_trash_res = image.snap_get_trash_namespace(
+        s->id, &trash_original_name);
+    }
+
+    std::string protected_str = "";
+    if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_USER) {
+      r = image.snap_is_protected(s->name.c_str(), &snap_protected);
+      if (r < 0) {
+        std::cerr << "rbd: unable to retrieve snap protection" << std::endl;
+        return r;
+      }
     }
 
     if (f) {
+      protected_str = snap_protected ? "true" : "false";
       f->open_object_section("snapshot");
       f->dump_unsigned("id", s->id);
       f->dump_string("name", s->name);
       f->dump_unsigned("size", s->size);
+      f->dump_string("protected", protected_str);
       f->dump_string("timestamp", tt_str);
+      if (all_snaps) {
+       f->open_object_section("namespace");
+        f->dump_string("type", snap_namespace_name);
+       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);
+       } else if (get_trash_res == 0) {
+          f->dump_string("original_name", trash_original_name);
+        }
+       f->close_section();
+      }
       f->close_section();
     } else {
-      t << s->id << s->name << stringify(byte_u_t(s->size)) << tt_str
-        << TextTable::endrow;
+      protected_str = snap_protected ? "yes" : "";
+      t << s->id << s->name << stringify(byte_u_t(s->size)) << protected_str << tt_str;
+
+      if (all_snaps) {
+       ostringstream oss;
+        oss << snap_namespace_name;
+
+        if (get_group_res == 0) {
+         std::string pool_name = pool_map[group_snap.group_pool];
+         oss << " (" << pool_name << "/"
+                     << group_snap.group_name << "@"
+                     << group_snap.group_snap_name << ")";
+        } else if (get_trash_res == 0) {
+          oss << " (" << trash_original_name << ")";
+        }
+
+       t << oss.str();
+      }
+      t << TextTable::endrow;
     }
   }
 
@@ -87,7 +181,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();
@@ -123,28 +217,46 @@ int do_purge_snaps(librbd::Image& image, bool no_progress)
   } else if (0 == snaps.size()) {
     return 0;
   } else {
-    for (size_t i = 0; i < snaps.size(); ++i) {
-      r = image.snap_is_protected(snaps[i].name.c_str(), &is_protected);
+    list<std::string> protect;
+    snaps.erase(remove_if(snaps.begin(),
+                          snaps.end(),
+                          boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
+                snaps.end());
+    for (auto it = snaps.begin(); it != snaps.end();) {
+      r = image.snap_is_protected(it->name.c_str(), &is_protected);
       if (r < 0) {
         pc.fail();
         return r;
       } else if (is_protected == true) {
-        pc.fail();
-        std::cerr << "\r" << "rbd: snapshot '" << snaps[i].name.c_str()
-                  << "' is protected from removal." << std::endl;
-        return -EBUSY;
+        protect.push_back(it->name.c_str());
+        snaps.erase(it);
+      } else {
+        ++it;
       }
     }
+
+    if (!protect.empty()) {
+      std::cout << "rbd: error removing snapshot(s) '" << protect << "', which "
+                << (1 == protect.size() ? "is" : "are")
+                << " protected - these must be unprotected with "
+                << "`rbd snap unprotect`."
+                << std::endl;
+    }
     for (size_t i = 0; i < snaps.size(); ++i) {
       r = image.snap_remove(snaps[i].name.c_str());
       if (r < 0) {
         pc.fail();
         return r;
       }
-      pc.update_progress(i + 1, snaps.size());
+      pc.update_progress(i + 1, snaps.size() + protect.size());
+    }
+
+    if (!protect.empty()) {
+      pc.fail();
+    } else if (snaps.size() > 0) {
+      pc.finish();
     }
 
-    pc.finish();
     return 0;
   }
 }
@@ -172,21 +284,23 @@ int do_set_limit(librbd::Image& image, uint64_t limit)
   return image.snap_set_limit(limit);
 }
 
-int do_clear_limit(librbd::Image& image)
-{
-  return image.snap_set_limit(UINT64_MAX);
-}
-
 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);
+
+  std::string name = ALL_NAME + ",a";
+
+  options->add_options()
+    (name.c_str(), po::bool_switch(), "list snapshots from all namespaces");
 }
 
-int execute_list(const po::variables_map &vm) {
+int execute_list(const po::variables_map &vm,
+                 const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   std::string image_id;
@@ -195,32 +309,20 @@ int execute_list(const po::variables_map &vm) {
     image_id = vm[at::IMAGE_ID].as<std::string>();
   }
 
-  bool has_image_spec = utils::check_if_image_spec_present(
-      vm, at::ARGUMENT_MODIFIER_NONE, arg_index);
+  int r = utils::get_pool_image_snapshot_names(
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, image_id.empty(),
+    utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
+  if (r < 0) {
+    return r;
+  }
 
-  if (!image_id.empty() && has_image_spec) {
+  if (!image_id.empty() && !image_name.empty()) {
     std::cerr << "rbd: trying to access image using both name and id. "
               << std::endl;
     return -EINVAL;
   }
 
-  int r;
-  if (image_id.empty()) {
-    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);
-  } else {
-    r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                       &arg_index, &pool_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);
   if (r < 0) {
@@ -230,13 +332,14 @@ int execute_list(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, image_id, "", true,
-                                 &rados, &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name,
+                                 image_id, "", true, &rados, &io_ctx, &image);
   if (r < 0) {
     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;
@@ -250,14 +353,17 @@ void get_create_arguments(po::options_description *positional,
   at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
 }
 
-int execute_create(const po::variables_map &vm) {
+int execute_create(const po::variables_map &vm,
+                   const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   int r = utils::get_pool_image_snapshot_names(
-    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
-    &snap_name, utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_SNAP);
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
+    utils::SPEC_VALIDATION_SNAP);
   if (r < 0) {
     return r;
   }
@@ -265,8 +371,8 @@ int execute_create(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                 &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
     return r;
   }
@@ -283,55 +389,61 @@ int execute_create(const po::variables_map &vm) {
 void get_remove_arguments(po::options_description *positional,
                           po::options_description *options) {
   at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
-  at::add_no_progress_option(options);
   at::add_image_id_option(options);
+  at::add_snap_id_option(options);
+  at::add_no_progress_option(options);
 
   options->add_options()
     ("force", po::bool_switch(), "flatten children and unprotect snapshot if needed.");
 }
 
-int execute_remove(const po::variables_map &vm) {
+int execute_remove(const po::variables_map &vm,
+                   const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   std::string image_id;
+  uint64_t snap_id = CEPH_NOSNAP;
   bool force = vm["force"].as<bool>();
+  bool no_progress = vm[at::NO_PROGRESS].as<bool>();
 
   if (vm.count(at::IMAGE_ID)) {
     image_id = vm[at::IMAGE_ID].as<std::string>();
   }
-
-  bool has_image_spec = utils::check_if_image_spec_present(
-      vm, at::ARGUMENT_MODIFIER_NONE, arg_index);
-
-  if (!image_id.empty() && has_image_spec) {
-    std::cerr << "rbd: trying to access image using both name and id. "
-              << std::endl;
-    return -EINVAL;
+  if (vm.count(at::SNAPSHOT_ID)) {
+    snap_id = vm[at::SNAPSHOT_ID].as<uint64_t>();
   }
 
-  int r;
-  if (image_id.empty()) {
-    r = utils::get_pool_image_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                             &arg_index, &pool_name,
-                                             &image_name, &snap_name,
-                                             utils::SNAPSHOT_PRESENCE_REQUIRED,
-                                             utils::SPEC_VALIDATION_NONE);
-  } else {
-    r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                       &arg_index, &pool_name, &snap_name,
-                                       utils::SNAPSHOT_PRESENCE_REQUIRED,
-                                       utils::SPEC_VALIDATION_NONE);
-  }
+  int r = utils::get_pool_image_snapshot_names(
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, image_id.empty(),
+    (snap_id == CEPH_NOSNAP ? utils::SNAPSHOT_PRESENCE_REQUIRED :
+                              utils::SNAPSHOT_PRESENCE_PERMITTED),
+    utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
 
+  if (!image_id.empty() && !image_name.empty()) {
+    std::cerr << "rbd: trying to access image using both name and id."
+              << std::endl;
+    return -EINVAL;
+  } else if (!snap_name.empty() && snap_id != CEPH_NOSNAP) {
+    std::cerr << "rbd: trying to access snapshot using both name and id."
+              << std::endl;
+    return -EINVAL;
+  } else if ((force || no_progress) && snap_id != CEPH_NOSNAP) {
+    std::cerr << "rbd: force and no-progress options not permitted when "
+              << "removing by id." << std::endl;
+    return -EINVAL;
+  }
+
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init(pool_name, &rados, &io_ctx);
+  r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
   if (r < 0) {
     return r;
   }
@@ -346,11 +458,18 @@ int execute_remove(const po::variables_map &vm) {
     return r;
   }
 
-  r = do_remove_snap(image, snap_name.c_str(), force, vm[at::NO_PROGRESS].as<bool>());
+  if (!snap_name.empty()) {
+    r = do_remove_snap(image, snap_name.c_str(), force, no_progress);
+  } else {
+    r = image.snap_remove_by_id(snap_id);
+  }
+
   if (r < 0) {
     if (r == -EBUSY) {
-      std::cerr << "rbd: snapshot '" << snap_name << "' "
-                << "is protected from removal." << std::endl;
+      std::cerr << "rbd: snapshot "
+                << (snap_name.empty() ? std::string("id ") + stringify(snap_id) :
+                                        std::string("'") + snap_name + "'")
+                << " is protected from removal." << std::endl;
     } else {
       std::cerr << "rbd: failed to remove snapshot: " << cpp_strerror(r)
                 << std::endl;
@@ -367,9 +486,11 @@ void get_purge_arguments(po::options_description *positional,
   at::add_no_progress_option(options);
 }
 
-int execute_purge(const po::variables_map &vm) {
+int execute_purge(const po::variables_map &vm,
+                  const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   std::string image_id;
@@ -378,36 +499,24 @@ int execute_purge(const po::variables_map &vm) {
     image_id = vm[at::IMAGE_ID].as<std::string>();
   }
 
-  bool has_image_spec = utils::check_if_image_spec_present(
-      vm, at::ARGUMENT_MODIFIER_NONE, arg_index);
+  int r = utils::get_pool_image_snapshot_names(
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, image_id.empty(),
+    utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
+  if (r < 0) {
+    return r;
+  }
 
-  if (!image_id.empty() && has_image_spec) {
+  if (!image_id.empty() && !image_name.empty()) {
     std::cerr << "rbd: trying to access image using both name and id. "
               << std::endl;
     return -EINVAL;
   }
 
-  int r;
-  if (image_id.empty()) {
-    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);
-  } else {
-    r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                       &arg_index, &pool_name, &snap_name,
-                                       utils::SNAPSHOT_PRESENCE_NONE,
-                                       utils::SPEC_VALIDATION_NONE);
-  }
-  if (r < 0) {
-    return r;
-  }
-
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init(pool_name, &rados, &io_ctx);
+  r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
   if (r < 0) {
     return r;
   }
@@ -439,14 +548,17 @@ void get_rollback_arguments(po::options_description *positional,
   at::add_no_progress_option(options);
 }
 
-int execute_rollback(const po::variables_map &vm) {
+int execute_rollback(const po::variables_map &vm,
+                     const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   int r = utils::get_pool_image_snapshot_names(
-    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
-    &snap_name, utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_NONE);
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
+    utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
@@ -454,8 +566,8 @@ int execute_rollback(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                 &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
     return r;
   }
@@ -474,14 +586,17 @@ void get_protect_arguments(po::options_description *positional,
   at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
 }
 
-int execute_protect(const po::variables_map &vm) {
+int execute_protect(const po::variables_map &vm,
+                    const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   int r = utils::get_pool_image_snapshot_names(
-    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
-    &snap_name, utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_NONE);
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
+    utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
@@ -489,8 +604,8 @@ int execute_protect(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                 &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
     return r;
   }
@@ -521,9 +636,11 @@ void get_unprotect_arguments(po::options_description *positional,
   at::add_image_id_option(options);
 }
 
-int execute_unprotect(const po::variables_map &vm) {
+int execute_unprotect(const po::variables_map &vm,
+                      const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   std::string image_id;
@@ -532,36 +649,24 @@ int execute_unprotect(const po::variables_map &vm) {
     image_id = vm[at::IMAGE_ID].as<std::string>();
   }
 
-  bool has_image_spec = utils::check_if_image_spec_present(
-      vm, at::ARGUMENT_MODIFIER_NONE, arg_index);
+  int r = utils::get_pool_image_snapshot_names(
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, image_id.empty(),
+    utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_NONE);
+  if (r < 0) {
+    return r;
+  }
 
-  if (!image_id.empty() && has_image_spec) {
+  if (!image_id.empty() && !image_name.empty()) {
     std::cerr << "rbd: trying to access image using both name and id. "
               << std::endl;
     return -EINVAL;
   }
 
-  int r;
-  if (image_id.empty()) {
-    r = utils::get_pool_image_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                             &arg_index, &pool_name,
-                                             &image_name, &snap_name,
-                                             utils::SNAPSHOT_PRESENCE_REQUIRED,
-                                             utils::SPEC_VALIDATION_NONE);
-  } else {
-    r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
-                                       &arg_index, &pool_name, &snap_name,
-                                       utils::SNAPSHOT_PRESENCE_REQUIRED,
-                                       utils::SPEC_VALIDATION_NONE);
-  }
-  if (r < 0) {
-    return r;
-  }
-
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init(pool_name, &rados, &io_ctx);
+  r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
   if (r < 0) {
     return r;
   }
@@ -602,16 +707,19 @@ void get_set_limit_arguments(po::options_description *pos,
   at::add_limit_option(opt);
 }
 
-int execute_set_limit(const po::variables_map &vm) {
+int execute_set_limit(const po::variables_map &vm,
+                      const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
   uint64_t limit;
 
   int 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);
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
+    utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
@@ -626,8 +734,8 @@ int execute_set_limit(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
       return r;
   }
@@ -646,15 +754,18 @@ void get_clear_limit_arguments(po::options_description *pos,
   at::add_image_spec_options(pos, opt, at::ARGUMENT_MODIFIER_NONE);
 }
 
-int execute_clear_limit(const po::variables_map &vm) {
+int execute_clear_limit(const po::variables_map &vm,
+                        const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string snap_name;
 
   int 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);
+    vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
+    utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
@@ -662,13 +773,13 @@ int execute_clear_limit(const po::variables_map &vm) {
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
       return r;
   }
 
-  r = do_clear_limit(image);
+  r = do_set_limit(image, UINT64_MAX);
   if (r < 0) {
     std::cerr << "rbd: clearing snapshot limit failed: " << cpp_strerror(r)
              << std::endl;
@@ -683,26 +794,29 @@ void get_rename_arguments(po::options_description *positional,
   at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
 }
 
-int execute_rename(const po::variables_map &vm) {
+int execute_rename(const po::variables_map &vm,
+                   const std::vector<std::string> &ceph_global_init_args) {
   size_t arg_index = 0;
   std::string pool_name;
+  std::string namespace_name;
   std::string image_name;
   std::string src_snap_name;
   int r = utils::get_pool_image_snapshot_names(
-    vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &image_name,
-    &src_snap_name, utils::SNAPSHOT_PRESENCE_REQUIRED,
+    vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &namespace_name,
+    &image_name, &src_snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
     utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return -r;
   }
 
   std::string dest_pool_name(pool_name);
+  std::string dest_namespace_name(namespace_name);
   std::string dest_image_name;
   std::string dest_snap_name;
   r = utils::get_pool_image_snapshot_names(
     vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &dest_pool_name,
-    &dest_image_name, &dest_snap_name, utils::SNAPSHOT_PRESENCE_REQUIRED,
-    utils::SPEC_VALIDATION_SNAP);
+    &dest_namespace_name, &dest_image_name, &dest_snap_name, true,
+    utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_SNAP);
   if (r < 0) {
     return -r;
   }
@@ -711,17 +825,21 @@ int execute_rename(const po::variables_map &vm) {
     std::cerr << "rbd: source and destination pool must be the same"
               << std::endl;
     return -EINVAL;
+  } else if (namespace_name != dest_namespace_name) {
+    std::cerr << "rbd: source and destination namespace must be the same"
+              << std::endl;
+    return -EINVAL;
   } else if (image_name != dest_image_name) {
     std::cerr << "rbd: source and destination image name must be the same"
               << std::endl;
     return -EINVAL;
   }
-  
+
   librados::Rados rados;
   librados::IoCtx io_ctx;
   librbd::Image image;
-  r = utils::init_and_open_image(pool_name, image_name, "", "", false, &rados,
-                                 &io_ctx, &image);
+  r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+                                 false, &rados, &io_ctx, &image);
   if (r < 0) {
     return r;
   }
@@ -745,7 +863,7 @@ Shell::Action action_remove(
   {"snap", "remove"}, {"snap", "rm"}, "Delete a snapshot.", "",
   &get_remove_arguments, &execute_remove);
 Shell::Action action_purge(
-  {"snap", "purge"}, {}, "Delete all snapshots.", "",
+  {"snap", "purge"}, {}, "Delete all unprotected snapshots.", "",
   &get_purge_arguments, &execute_purge);
 Shell::Action action_rollback(
   {"snap", "rollback"}, {"snap", "revert"}, "Rollback image to snapshot.", "",