]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: CLI to retrieve rbd mirror state for a pool / specific image
authorMykola Golub <mgolub@mirantis.com>
Tue, 5 Apr 2016 11:42:09 +0000 (14:42 +0300)
committerAbhishek Varshney <abhishek.varshney@flipkart.com>
Mon, 2 May 2016 06:35:58 +0000 (12:05 +0530)
Fixes: #15144
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
(cherry picked from commit fe5207278d884464c05d6808245a0c4df03c441c)

src/test/cli/rbd/help.t
src/tools/rbd/Utils.cc
src/tools/rbd/Utils.h
src/tools/rbd/action/MirrorImage.cc
src/tools/rbd/action/MirrorPool.cc

index f68a486616f243ebebb6c0487c94eb7de8d310a2..5d7a4b48b50f58d84ecadfc07b6e1cc9fa0eb631 100644 (file)
@@ -48,6 +48,7 @@
       mirror image enable         Enable RBD mirroring for an image.
       mirror image promote        Promote an image to primary for RBD mirroring.
       mirror image resync         Force resync to primary image for RBD mirroring.
+      mirror image status         Show RDB mirroring status for an image.
       mirror pool disable         Disable RBD mirroring by default within a pool.
       mirror pool enable          Enable RBD mirroring by default within a pool.
       mirror pool info            Show information about the pool mirroring
@@ -55,6 +56,7 @@
       mirror pool peer add        Add a mirroring peer to a pool.
       mirror pool peer remove     Remove a mirroring peer from a pool.
       mirror pool peer set        Update mirroring peer settings.
+      mirror pool status          Show status for all mirrored images in the pool.
       nbd list (nbd ls)           List the nbd devices already used.
       nbd map                     Map image to a nbd device.
       nbd unmap                   Unmap a nbd device.
     -p [ --pool ] arg    pool name
     --image arg          image name
   
+  rbd help mirror image status
+  usage: rbd mirror image status [--pool <pool>] [--image <image>] 
+                                 [--format <format>] [--pretty-format] 
+                                 <image-spec> 
+  
+  Show RDB mirroring status for an image.
+  
+  Positional arguments
+    <image-spec>         image specification
+                         (example: [<pool-name>/]<image-name>)
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --image arg          image name
+    --format arg         output format [plain, json, or xml]
+    --pretty-format      pretty formatting (json and xml)
+  
   rbd help mirror pool disable
   usage: rbd mirror pool disable [--pool <pool>] 
                                  <pool-name> 
   Optional arguments
     -p [ --pool ] arg    pool name
   
+  rbd help mirror pool status
+  usage: rbd mirror pool status [--pool <pool>] [--format <format>] 
+                                [--pretty-format] [--verbose] 
+                                <pool-name> 
+  
+  Show status for all mirrored images in the pool.
+  
+  Positional arguments
+    <pool-name>          pool name
+  
+  Optional arguments
+    -p [ --pool ] arg    pool name
+    --format arg         output format [plain, json, or xml]
+    --pretty-format      pretty formatting (json and xml)
+    --verbose            be verbose
+  
   rbd help nbd list
   usage: rbd nbd list 
   
index f06e85773f0803d10a190d2d850d7c4e6304a513..bc67f5dfa28991a19f2c2beae504983bcfe44a5f 100644 (file)
@@ -657,8 +657,8 @@ std::string image_id(librbd::Image& image) {
   return string(prefix + strlen(RBD_DATA_PREFIX));
 }
 
-std::string mirror_image_state(rbd_mirror_image_state_t mirror_image_state) {
-  switch (mirror_image_state) {
+std::string mirror_image_state(librbd::mirror_image_state_t state) {
+  switch (state) {
     case RBD_MIRROR_IMAGE_DISABLING:
       return "disabling";
     case RBD_MIRROR_IMAGE_ENABLED:
@@ -670,5 +670,50 @@ std::string mirror_image_state(rbd_mirror_image_state_t mirror_image_state) {
   }
 }
 
+std::string mirror_image_status_state(librbd::mirror_image_status_state_t state) {
+  switch (state) {
+  case MIRROR_IMAGE_STATUS_STATE_UNKNOWN:
+    return "unknown";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_ERROR:
+    return "error";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_SYNCING:
+    return "syncing";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY:
+    return "starting_replay";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_REPLAYING:
+    return "replaying";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY:
+    return "stopping_replay";
+    break;
+  case MIRROR_IMAGE_STATUS_STATE_STOPPED:
+    return "stopped";
+    break;
+  default:
+    return "unknown (" + stringify(static_cast<uint32_t>(state)) + ")";
+    break;
+  }
+}
+
+std::string mirror_image_status_state(librbd::mirror_image_status_t status) {
+  return (status.up ? "up+" : "down+") +
+    mirror_image_status_state(status.state);
+}
+
+std::string timestr(time_t t) {
+  struct tm tm;
+
+  localtime_r(&t, &tm);
+
+  char buf[32];
+  strftime(buf, sizeof(buf), "%F %T", &tm);
+
+  return buf;
+}
+
 } // namespace utils
 } // namespace rbd
index 10ec2d21ab58d4353481dcd521db2c0e4ecfc83b..cad18d93dcd31a387e0fec0de3e39b66fdcf9441 100644 (file)
@@ -108,7 +108,11 @@ int snap_set(librbd::Image &image, const std::string &snap_name);
 
 std::string image_id(librbd::Image& image);
 
-std::string mirror_image_state(rbd_mirror_image_state_t mirror_image_state);
+std::string mirror_image_state(librbd::mirror_image_state_t mirror_image_state);
+std::string mirror_image_status_state(librbd::mirror_image_status_state_t state);
+std::string mirror_image_status_state(librbd::mirror_image_status_t status);
+
+std::string timestr(time_t t);
 
 } // namespace utils
 } // namespace rbd
index f61c628cdf4856bee9339340558f5553fbed7ec4..6311c0eac60c00f4f69d226a368fb6f6695b3164 100644 (file)
@@ -187,6 +187,84 @@ int execute_resync(const po::variables_map &vm) {
   return 0;
 }
 
+void get_status_arguments(po::options_description *positional,
+                         po::options_description *options) {
+  at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+  at::add_format_options(options);
+}
+
+int execute_status(const po::variables_map &vm) {
+  at::Format::Formatter formatter;
+  int r = utils::get_formatter(vm, &formatter);
+  if (r < 0) {
+    return r;
+  }
+
+  size_t arg_index = 0;
+  std::string pool_name;
+  std::string image_name;
+  std::string snap_name;
+  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;
+  }
+
+  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);
+  if (r < 0) {
+    return r;
+  }
+
+  librbd::mirror_image_info_t mirror_image;
+  r = image.mirror_image_get_info(&mirror_image, sizeof(mirror_image));
+  if (r < 0) {
+    std::cerr << "rbd: failed to get global image id for image " << image_name
+             << ": " << cpp_strerror(r) << std::endl;
+    return r;
+  }
+
+  if (mirror_image.global_id.empty()) {
+    std::cerr << "rbd: failed to get global image id for image " << image_name
+             << std::endl;
+    return -EINVAL;
+  }
+
+  librbd::mirror_image_status_t status;
+  r = image.mirror_image_get_status(&status, sizeof(status));
+  if (r < 0) {
+    std::cerr << "rbd: failed to get status for image " << image_name << ": "
+             << cpp_strerror(r) << std::endl;
+    return r;
+  }
+
+  std::string state = utils::mirror_image_status_state(status);
+  std::string last_update = utils::timestr(status.last_update);
+
+  if (formatter != nullptr) {
+    formatter->open_object_section("image");
+    formatter->dump_string("name", image_name);
+    formatter->dump_string("global_id", mirror_image.global_id);
+    formatter->dump_string("state", state);
+    formatter->dump_string("description", status.description);
+    formatter->dump_string("last_update", last_update);
+    formatter->close_section(); // image
+    formatter->flush(std::cout);
+  } else {
+    std::cout << image_name << ":\n"
+             << "  global_id:   " << mirror_image.global_id << "\n"
+             << "  state:       " << state << "\n"
+             << "  description: " << status.description << "\n"
+             << "  last_update: " << last_update << std::endl;
+  }
+
+  return 0;
+}
+
 Shell::Action action_enable(
   {"mirror", "image", "enable"}, {},
   "Enable RBD mirroring for an image.", "",
@@ -207,6 +285,10 @@ Shell::Action action_resync(
   {"mirror", "image", "resync"}, {},
   "Force resync to primary image for RBD mirroring.", "",
   &get_arguments, &execute_resync);
+Shell::Action action_status(
+  {"mirror", "image", "status"}, {},
+  "Show RDB mirroring status for an image.", "",
+  &get_status_arguments, &execute_status);
 
 } // namespace mirror_image
 } // namespace action
index 8ba055ed7f5520a905a6e969b32c2b17f00e0bcc..94f21b9238e717e57c79cf372ca5afb514cbf099 100644 (file)
@@ -374,6 +374,149 @@ int execute_info(const po::variables_map &vm) {
   return 0;
 }
 
+void get_status_arguments(po::options_description *positional,
+                         po::options_description *options) {
+  at::add_pool_options(positional, options);
+  at::add_format_options(options);
+  at::add_verbose_option(options);
+}
+
+int execute_status(const po::variables_map &vm) {
+  size_t arg_index = 0;
+  std::string pool_name = utils::get_pool_name(vm, &arg_index);
+
+  at::Format::Formatter formatter;
+  int r = utils::get_formatter(vm, &formatter);
+  if (r < 0) {
+    return r;
+  }
+
+  bool verbose = vm[at::VERBOSE].as<bool>();
+
+  std::string config_path;
+  if (vm.count(at::CONFIG_PATH)) {
+    config_path = vm[at::CONFIG_PATH].as<std::string>();
+  }
+
+  librados::Rados rados;
+  librados::IoCtx io_ctx;
+  r = utils::init(pool_name, &rados, &io_ctx);
+  if (r < 0) {
+    return r;
+  }
+
+  librbd::RBD rbd;
+
+  std::map<librbd::mirror_image_status_state_t, int> states;
+  r = rbd.mirror_image_status_summary(io_ctx, &states);
+  if (r < 0) {
+    std::cerr << "rbd: failed to get status summary for mirrored images: "
+             << cpp_strerror(r) << std::endl;
+    return r;
+  }
+
+  if (formatter != nullptr) {
+    formatter->open_object_section("status");
+  }
+
+  enum Health {Ok = 0, Warning = 1, Error = 2} health = Ok;
+  const char *names[] = {"OK", "WARNING", "ERROR"};
+  int total = 0;
+
+  for (auto &it : states) {
+    auto &state = it.first;
+    if (health < Warning &&
+       (state != MIRROR_IMAGE_STATUS_STATE_REPLAYING &&
+        state != MIRROR_IMAGE_STATUS_STATE_STOPPED)) {
+      health = Warning;
+    }
+    if (health < Error &&
+       state == MIRROR_IMAGE_STATUS_STATE_ERROR) {
+      health = Error;
+    }
+    total += it.second;
+  }
+
+  if (formatter != nullptr) {
+    formatter->open_object_section("summary");
+    formatter->dump_string("health", names[health]);
+    formatter->open_object_section("states");
+    for (auto &it : states) {
+      std::string state_name = utils::mirror_image_status_state(it.first);
+      formatter->dump_int(state_name.c_str(), it.second);
+    }
+    formatter->close_section(); // states
+    formatter->close_section(); // summary
+  } else {
+    std::cout << "health: " << names[health] << std::endl;
+    std::cout << "images: " << total << " total" << std::endl;
+    for (auto &it : states) {
+      std::cout << "    " << it.second << " "
+               << utils::mirror_image_status_state(it.first) << std::endl;
+    }
+  }
+
+  int ret = 0;
+
+  if (verbose) {
+    if (formatter != nullptr) {
+      formatter->open_array_section("images");
+    }
+
+    std::string last_read = "";
+    int max_read = 1024;
+    do {
+      map<std::string, librbd::mirror_image_info_t> mirror_images;
+      map<std::string, librbd::mirror_image_status_t> statuses;
+      r = rbd.mirror_image_status_list(io_ctx, last_read, max_read,
+                                      &mirror_images, &statuses);
+      if (r < 0) {
+       std::cerr << "rbd: failed to list mirrored image directory: "
+                 << cpp_strerror(r) << std::endl;
+       return r;
+      }
+      for (auto it = mirror_images.begin(); it != mirror_images.end(); ++it) {
+       const std::string &image_name = it->first;
+       std::string &global_image_id = it->second.global_id;
+       librbd::mirror_image_status_t &status = statuses[image_name];
+       std::string state = utils::mirror_image_status_state(status);
+       std::string last_update = utils::timestr(status.last_update);
+
+       if (formatter != nullptr) {
+         formatter->open_object_section("image");
+         formatter->dump_string("name", image_name);
+         formatter->dump_string("global_id", global_image_id);
+         formatter->dump_string("state", state);
+         formatter->dump_string("description", status.description);
+         formatter->dump_string("last_update", last_update);
+         formatter->close_section(); // image
+       } else {
+         std::cout << "\n" << image_name << ":\n"
+                   << "  global_id:   " << global_image_id << "\n"
+                   << "  state:       " << state << "\n"
+                   << "  description: " << status.description << "\n"
+                   << "  last_update: " << last_update << std::endl;
+       }
+      }
+      if (!mirror_images.empty()) {
+       last_read = mirror_images.rbegin()->first;
+      }
+      r = mirror_images.size();
+    } while (r == max_read);
+
+    if (formatter != nullptr) {
+      formatter->close_section(); // images
+    }
+  }
+
+  if (formatter != nullptr) {
+    formatter->close_section(); // status
+    formatter->flush(std::cout);
+  }
+
+  return ret;
+}
+
 Shell::Action action_add(
   {"mirror", "pool", "peer", "add"}, {},
   "Add a mirroring peer to a pool.", "",
@@ -399,6 +542,10 @@ Shell::Action action_info(
   {"mirror", "pool", "info"}, {},
   "Show information about the pool mirroring configuration.", {},
   &get_info_arguments, &execute_info);
+Shell::Action action_status(
+  {"mirror", "pool", "status"}, {},
+  "Show status for all mirrored images in the pool.", {},
+  &get_status_arguments, &execute_status);
 
 } // namespace mirror_pool
 } // namespace action