From e57c4d8f0832abcf431029b04da43e043a479d19 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Tue, 5 Apr 2016 14:42:09 +0300 Subject: [PATCH] rbd: CLI to retrieve rbd mirror state for a pool / specific image Fixes: #15144 Signed-off-by: Mykola Golub (cherry picked from commit fe5207278d884464c05d6808245a0c4df03c441c) --- src/test/cli/rbd/help.t | 35 +++++++ src/tools/rbd/Utils.cc | 49 +++++++++- src/tools/rbd/Utils.h | 6 +- src/tools/rbd/action/MirrorImage.cc | 82 ++++++++++++++++ src/tools/rbd/action/MirrorPool.cc | 147 ++++++++++++++++++++++++++++ 5 files changed, 316 insertions(+), 3 deletions(-) diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index f68a486616f24..5d7a4b48b50f5 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -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. @@ -824,6 +826,23 @@ -p [ --pool ] arg pool name --image arg image name + rbd help mirror image status + usage: rbd mirror image status [--pool ] [--image ] + [--format ] [--pretty-format] + + + Show RDB mirroring status for an image. + + Positional arguments + image specification + (example: [/]) + + 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 ] @@ -910,6 +929,22 @@ Optional arguments -p [ --pool ] arg pool name + rbd help mirror pool status + usage: rbd mirror pool status [--pool ] [--format ] + [--pretty-format] [--verbose] + + + Show status for all mirrored images in the pool. + + Positional arguments + 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 diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index f06e85773f080..bc67f5dfa2899 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -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(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 diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index 10ec2d21ab58d..cad18d93dcd31 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -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 diff --git a/src/tools/rbd/action/MirrorImage.cc b/src/tools/rbd/action/MirrorImage.cc index f61c628cdf485..6311c0eac60c0 100644 --- a/src/tools/rbd/action/MirrorImage.cc +++ b/src/tools/rbd/action/MirrorImage.cc @@ -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 diff --git a/src/tools/rbd/action/MirrorPool.cc b/src/tools/rbd/action/MirrorPool.cc index 8ba055ed7f552..94f21b9238e71 100644 --- a/src/tools/rbd/action/MirrorPool.cc +++ b/src/tools/rbd/action/MirrorPool.cc @@ -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(); + + std::string config_path; + if (vm.count(at::CONFIG_PATH)) { + config_path = vm[at::CONFIG_PATH].as(); + } + + 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 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 mirror_images; + map 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 -- 2.39.5