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
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
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:
}
}
+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
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
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.", "",
{"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
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.", "",
{"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