return r;
}
+ std::vector<librbd::mirror_peer_site_t> mirror_peers;
+ utils::get_mirror_peer_sites(io_ctx, &mirror_peers);
+
+ std::map<std::string, std::string> peer_fsid_to_name;
+ utils::get_mirror_peer_fsid_to_names(mirror_peers, &peer_fsid_to_name);
+
librbd::mirror_image_global_status_t status;
r = image.mirror_image_get_global_status(&status, sizeof(status));
if (r < 0) {
return r;
}
+ utils::populate_unknown_mirror_image_site_statuses(mirror_peers, &status);
+
std::string instance_id;
MirrorDaemonServiceInfo daemon_service_info(io_ctx);
librbd::mirror_image_site_status_t local_status;
- utils::get_local_mirror_image_status(status, &local_status);
-
- if (local_status.up) {
+ int local_site_r = utils::get_local_mirror_image_status(
+ status, &local_status);
+ status.site_statuses.erase(
+ std::remove_if(status.site_statuses.begin(),
+ status.site_statuses.end(),
+ [](auto& status) {
+ return (status.fsid == RBD_MIRROR_IMAGE_STATUS_LOCAL_FSID);
+ }),
+ status.site_statuses.end());
+
+ if (local_site_r >= 0 && local_status.up) {
r = image.mirror_image_get_instance_id(&instance_id);
if (r == -EOPNOTSUPP) {
std::cerr << "rbd: newer release of Ceph OSDs required to map image "
}
}
- std::string state = utils::mirror_image_site_status_state(local_status);
- std::string last_update = (
- local_status.last_update == 0 ?
- "" : utils::timestr(local_status.last_update));
-
if (formatter != nullptr) {
formatter->open_object_section("image");
formatter->dump_string("name", image_name);
formatter->dump_string("global_id", status.info.global_id);
- formatter->dump_string("state", state);
- formatter->dump_string("description", local_status.description);
- daemon_service_info.dump(instance_id, formatter);
- formatter->dump_string("last_update", last_update);
+ if (local_site_r >= 0) {
+ formatter->dump_string("state", utils::mirror_image_site_status_state(
+ local_status));
+ formatter->dump_string("description", local_status.description);
+ daemon_service_info.dump(instance_id, formatter);
+ formatter->dump_string("last_update", utils::timestr(
+ local_status.last_update));
+ }
+ if (!status.site_statuses.empty()) {
+ formatter->open_array_section("peer_sites");
+ for (auto& status : status.site_statuses) {
+ formatter->open_object_section("peer_site");
+
+ auto name_it = peer_fsid_to_name.find(status.fsid);
+ formatter->dump_string("site_name",
+ (name_it != peer_fsid_to_name.end() ? name_it->second : ""));
+ formatter->dump_string("fsid", status.fsid);
+
+ formatter->dump_string("state", utils::mirror_image_site_status_state(
+ status));
+ formatter->dump_string("description", status.description);
+ formatter->dump_string("last_update", utils::timestr(
+ status.last_update));
+ formatter->close_section(); // peer_site
+ }
+ formatter->close_section(); // peer_sites
+ }
formatter->close_section(); // image
formatter->flush(std::cout);
} else {
std::cout << image_name << ":\n"
- << " global_id: " << status.info.global_id << "\n"
- << " state: " << state << "\n"
- << " description: " << local_status.description << "\n";
- if (!instance_id.empty()) {
- std::cout << " service: " <<
- daemon_service_info.get_description(instance_id) << "\n";
+ << " global_id: " << status.info.global_id << "\n";
+ if (local_site_r >= 0) {
+ std::cout << " state: " << utils::mirror_image_site_status_state(
+ local_status) << "\n"
+ << " description: " << local_status.description << "\n";
+ if (!instance_id.empty()) {
+ std::cout << " service: " <<
+ daemon_service_info.get_description(instance_id) << "\n";
+ }
+ std::cout << " last_update: " << utils::timestr(
+ local_status.last_update) << std::endl;
+ }
+ if (!status.site_statuses.empty()) {
+ std::cout << " peer_sites:" << std::endl;
+
+ bool first_site = true;
+ for (auto& site : status.site_statuses) {
+ if (!first_site) {
+ std::cout << std::endl;
+ }
+ first_site = false;
+
+ auto name_it = peer_fsid_to_name.find(site.fsid);
+ std::cout << " name: "
+ << (name_it != peer_fsid_to_name.end() ? name_it->second :
+ site.fsid)
+ << std::endl
+ << " state: " << utils::mirror_image_site_status_state(
+ site) << std::endl
+ << " description: " << site.description << std::endl
+ << " last_update: " << utils::timestr(
+ site.last_update) << std::endl;
+ }
}
- std::cout << " last_update: " << last_update << std::endl;
}
return 0;
struct MirrorPeerDirection {};
void validate(boost::any& v, const std::vector<std::string>& values,
- MirrorPeerDirection *target_type, int) {
+ MirrorPeerDirection *target_type, int permit_tx) {
po::validators::check_first_occurrence(v);
const std::string &s = po::validators::get_single_string(values);
v = boost::any(RBD_MIRROR_PEER_DIRECTION_RX);
} else if (s == "rx-tx") {
v = boost::any(RBD_MIRROR_PEER_DIRECTION_RX_TX);
+ } else if (permit_tx != 0 && s == "tx-only") {
+ v = boost::any(RBD_MIRROR_PEER_DIRECTION_TX);
} else {
throw po::validation_error(po::validation_error::invalid_option_value);
}
}
+void add_direction_optional(po::options_description *options) {
+ options->add_options()
+ ("direction", po::value<MirrorPeerDirection>(),
+ "mirroring direction (rx-only, rx-tx)\n"
+ "[default: rx-tx]");
+}
+
int validate_mirroring_enabled(librados::IoCtx& io_ctx) {
librbd::RBD rbd;
rbd_mirror_mode_t mirror_mode;
at::Format::Formatter formatter,
const std::vector<librbd::mirror_peer_site_t> &peers,
bool config_key) {
- TextTable tbl;
if (formatter != nullptr) {
formatter->open_array_section("peers");
} else {
- std::cout << "Peers: ";
+ std::cout << "Peer Sites: ";
if (peers.empty()) {
- std::cout << "none" << std::endl;
- } else {
- tbl.define_column("", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("UUID", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("CLIENT", TextTable::LEFT, TextTable::LEFT);
- if (config_key) {
- tbl.define_column("MON_HOST", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("KEY", TextTable::LEFT, TextTable::LEFT);
- }
+ std::cout << "none";
}
+ std::cout << std::endl;
}
for (auto &peer : peers) {
}
}
+ std::string direction;
+ switch (peer.direction) {
+ case RBD_MIRROR_PEER_DIRECTION_RX:
+ direction = "rx-only";
+ break;
+ case RBD_MIRROR_PEER_DIRECTION_TX:
+ direction = "tx-only";
+ break;
+ case RBD_MIRROR_PEER_DIRECTION_RX_TX:
+ direction = "rx-tx";
+ break;
+ default:
+ direction = "unknown";
+ break;
+ }
+
if (formatter != nullptr) {
formatter->open_object_section("peer");
formatter->dump_string("uuid", peer.uuid);
- formatter->dump_string("cluster_name", peer.site_name);
+ formatter->dump_string("direction", direction);
+ formatter->dump_string("site_name", peer.site_name);
+ formatter->dump_string("fsid", peer.fsid);
formatter->dump_string("client_name", peer.client_name);
for (auto& pair : attributes) {
formatter->dump_string(pair.first.c_str(), pair.second);
}
formatter->close_section();
} else {
- tbl << " "
- << peer.uuid
- << peer.site_name
- << peer.client_name;
+ std::cout << std::endl
+ << "UUID: " << peer.uuid << std::endl
+ << "Name: " << peer.site_name << std::endl;
+ if (peer.direction != RBD_MIRROR_PEER_DIRECTION_RX ||
+ !peer.fsid.empty()) {
+ std::cout << "FSID: " << peer.fsid << std::endl;
+ }
+ std::cout << "Direction: " << direction << std::endl;
+ if (peer.direction != RBD_MIRROR_PEER_DIRECTION_TX ||
+ !peer.client_name.empty()) {
+ std::cout << "Client: " << peer.client_name << std::endl;
+ }
if (config_key) {
- tbl << attributes["mon_host"]
- << attributes["key"];
+ std::cout << "Mon Host: " << attributes["mon_host"] << std::endl
+ << "Key: " << attributes["key"] << std::endl;
+ }
+ if (peer.site_name != peers.rbegin()->site_name) {
+ std::cout << std::endl;
}
- tbl << TextTable::endrow;
}
}
if (formatter != nullptr) {
formatter->close_section();
- } else {
- std::cout << std::endl << tbl;
}
return 0;
}
librados::IoCtx &io_ctx, OrderedThrottle &throttle,
const std::string &image_name,
const std::map<std::string, std::string> &instance_ids,
+ const std::vector<librbd::mirror_peer_site_t>& mirror_peers,
+ const std::map<std::string, std::string> &peer_fsid_to_name,
const MirrorDaemonServiceInfo &daemon_service_info,
at::Format::Formatter formatter)
: ImageRequestBase(io_ctx, throttle, image_name),
- m_instance_ids(instance_ids), m_daemon_service_info(daemon_service_info),
- m_formatter(formatter) {
+ m_instance_ids(instance_ids), m_mirror_peers(mirror_peers),
+ m_peer_fsid_to_name(peer_fsid_to_name),
+ m_daemon_service_info(daemon_service_info), m_formatter(formatter) {
}
protected:
return;
}
+ utils::populate_unknown_mirror_image_site_statuses(
+ m_mirror_peers, &m_mirror_image_global_status);
+
librbd::mirror_image_site_status_t local_status;
- utils::get_local_mirror_image_status(
+ int local_site_r = utils::get_local_mirror_image_status(
m_mirror_image_global_status, &local_status);
-
- std::string state = utils::mirror_image_site_status_state(local_status);
- std::string instance_id = (local_status.up &&
+ m_mirror_image_global_status.site_statuses.erase(
+ std::remove_if(m_mirror_image_global_status.site_statuses.begin(),
+ m_mirror_image_global_status.site_statuses.end(),
+ [](auto& status) {
+ return (status.fsid == RBD_MIRROR_IMAGE_STATUS_LOCAL_FSID);
+ }),
+ m_mirror_image_global_status.site_statuses.end());
+
+ std::string instance_id = (local_site_r >= 0 && local_status.up &&
m_instance_ids.count(m_image_id)) ?
m_instance_ids.find(m_image_id)->second : "";
- std::string last_update = (
- local_status.last_update == 0 ?
- "" : utils::timestr(local_status.last_update));
if (m_formatter != nullptr) {
m_formatter->open_object_section("image");
m_formatter->dump_string("name", m_mirror_image_global_status.name);
m_formatter->dump_string(
"global_id", m_mirror_image_global_status.info.global_id);
- m_formatter->dump_string("state", state);
- m_formatter->dump_string("description", local_status.description);
- m_daemon_service_info.dump(instance_id, m_formatter);
- m_formatter->dump_string("last_update", last_update);
+ if (local_site_r >= 0) {
+ m_formatter->dump_string("state", utils::mirror_image_site_status_state(
+ local_status));
+ m_formatter->dump_string("description", local_status.description);
+ m_daemon_service_info.dump(instance_id, m_formatter);
+ m_formatter->dump_string("last_update", utils::timestr(
+ local_status.last_update));
+ }
+ if (!m_mirror_image_global_status.site_statuses.empty()) {
+ m_formatter->open_array_section("peer_sites");
+ for (auto& status : m_mirror_image_global_status.site_statuses) {
+ m_formatter->open_object_section("peer_site");
+
+ auto name_it = m_peer_fsid_to_name.find(status.fsid);
+ m_formatter->dump_string("site_name",
+ (name_it != m_peer_fsid_to_name.end() ? name_it->second : ""));
+ m_formatter->dump_string("fsid", status.fsid);
+
+ m_formatter->dump_string(
+ "state", utils::mirror_image_site_status_state(status));
+ m_formatter->dump_string("description", status.description);
+ m_formatter->dump_string("last_update", utils::timestr(
+ status.last_update));
+ m_formatter->close_section(); // peer_site
+ }
+ m_formatter->close_section(); // peer_sites
+ }
m_formatter->close_section(); // image
} else {
- std::cout << "\n" << m_mirror_image_global_status.name << ":\n"
- << " global_id: "
- << m_mirror_image_global_status.info.global_id << "\n"
- << " state: " << state << "\n"
- << " description: " << local_status.description << "\n";
- if (!instance_id.empty()) {
- std::cout << " service: "
- << m_daemon_service_info.get_description(instance_id) << "\n";
+ std::cout << std::endl
+ << m_mirror_image_global_status.name << ":" << std::endl
+ << " global_id: "
+ << m_mirror_image_global_status.info.global_id << std::endl;
+ if (local_site_r >= 0) {
+ std::cout << " state: " << utils::mirror_image_site_status_state(
+ local_status) << std::endl
+ << " description: " << local_status.description << std::endl;
+ if (!instance_id.empty()) {
+ std::cout << " service: " <<
+ m_daemon_service_info.get_description(instance_id) << std::endl;
+ }
+ std::cout << " last_update: " << utils::timestr(
+ local_status.last_update) << std::endl;
+ }
+ if (!m_mirror_image_global_status.site_statuses.empty()) {
+ std::cout << " peer_sites:" << std::endl;
+ bool first_site = true;
+ for (auto& site : m_mirror_image_global_status.site_statuses) {
+ if (!first_site) {
+ std::cout << std::endl;
+ }
+ first_site = false;
+
+ auto name_it = m_peer_fsid_to_name.find(site.fsid);
+ std::cout << " name: "
+ << (name_it != m_peer_fsid_to_name.end() ? name_it->second :
+ site.fsid)
+ << std::endl
+ << " state: " << utils::mirror_image_site_status_state(
+ site) << std::endl
+ << " description: " << site.description << std::endl
+ << " last_update: " << utils::timestr(
+ site.last_update) << std::endl;
+ }
}
- std::cout << " last_update: " << last_update << std::endl;
}
}
private:
const std::map<std::string, std::string> &m_instance_ids;
+ const std::vector<librbd::mirror_peer_site_t> &m_mirror_peers;
+ const std::map<std::string, std::string> &m_peer_fsid_to_name;
const MirrorDaemonServiceInfo &m_daemon_service_info;
at::Format::Formatter m_formatter;
std::string m_image_id;
"bootstrap token file (or '-' for stdin)");
options->add_options()
("token-path", po::value<std::string>(),
- "bootstrap token file (or '-' for stdin)")
- ("direction", po::value<MirrorPeerDirection>(),
- "mirroring direction (rx-only, rx-tx)\n"
- "[default: rx-tx]");
+ "bootstrap token file (or '-' for stdin)");
+ add_direction_optional(options);
}
int execute_peer_bootstrap_import(
("remote-mon-host", po::value<std::string>(), "remote mon host(s)")
("remote-key-file", po::value<std::string>(),
"path to file containing remote key");
+ add_direction_optional(options);
}
int execute_peer_add(const po::variables_map &vm,
return -EINVAL;
}
+ rbd_mirror_peer_direction_t mirror_peer_direction =
+ RBD_MIRROR_PEER_DIRECTION_RX_TX;
+ if (vm.count("direction")) {
+ mirror_peer_direction = vm["direction"].as<rbd_mirror_peer_direction_t>();
+ }
+
std::string uuid;
r = rbd.mirror_peer_site_add(
- io_ctx, &uuid, RBD_MIRROR_PEER_DIRECTION_RX_TX, remote_cluster,
- remote_client_name);
+ io_ctx, &uuid, mirror_peer_direction, remote_cluster, remote_client_name);
if (r < 0) {
std::cerr << "rbd: error adding mirror peer" << std::endl;
return r;
at::add_pool_options(positional, options, false);
add_uuid_option(positional);
positional->add_options()
- ("key", "peer parameter [client, cluster, mon-host, key-file]")
- ("value", "new value for specified key");
+ ("key", "peer parameter\n"
+ "(direction, site-name, client, mon-host, key-file)")
+ ("value", "new value for specified key\n"
+ "(rx-only, tx-only, or rx-tx for direction)");
}
int execute_peer_set(const po::variables_map &vm,
return r;
}
- std::set<std::string> valid_keys{{"client", "cluster", "mon-host",
- "key-file"}};
+ std::set<std::string> valid_keys{{"direction", "site-name", "cluster",
+ "client", "mon-host", "key-file"}};
std::string key = utils::get_positional_argument(vm, arg_index++);
if (valid_keys.find(key) == valid_keys.end()) {
std::cerr << "rbd: must specify ";
if (key == "client") {
r = rbd.mirror_peer_site_set_client_name(io_ctx, uuid.c_str(),
value.c_str());
- } else if (key == "cluster") {
+ } else if (key == "site-name" || key == "cluster") {
r = rbd.mirror_peer_site_set_name(io_ctx, uuid.c_str(), value.c_str());
+ } else if (key == "direction") {
+ MirrorPeerDirection tag;
+ boost::any direction;
+ try {
+ validate(direction, {value}, &tag, 1);
+ } catch (...) {
+ std::cerr << "rbd: invalid direction" << std::endl;
+ return -EINVAL;
+ }
+
+ r = rbd.mirror_peer_site_set_direction(
+ io_ctx, uuid, boost::any_cast<rbd_mirror_peer_direction_t>(direction));
} else {
r = update_peer_config_key(io_ctx, uuid, key, value);
- if (r == -ENOENT) {
- std::cerr << "rbd: mirror peer " << uuid << " does not exist"
- << std::endl;
- }
+ }
+
+ if (r == -ENOENT) {
+ std::cerr << "rbd: mirror peer " << uuid << " does not exist"
+ << std::endl;
}
if (r < 0) {
if (formatter != nullptr) {
formatter->dump_string("site_name", site_name);
} else {
- std::cout << "Site Name: " << site_name << std::endl;
+ std::cout << "Site Name: " << site_name << std::endl
+ << std::endl;
}
r = format_mirror_peers(io_ctx, formatter, mirror_peers,
int ret = 0;
if (verbose) {
+ std::vector<librbd::mirror_peer_site_t> mirror_peers;
+ utils::get_mirror_peer_sites(io_ctx, &mirror_peers);
+
+ std::map<std::string, std::string> peer_fsid_to_name;
+ utils::get_mirror_peer_fsid_to_names(mirror_peers, &peer_fsid_to_name);
+
if (formatter != nullptr) {
formatter->open_array_section("images");
}
}
ImageRequestGenerator<StatusImageRequest> generator(
- io_ctx, instance_ids, daemon_service_info, formatter);
+ io_ctx, instance_ids, mirror_peers, peer_fsid_to_name,
+ daemon_service_info, formatter);
ret = generator.execute();
if (formatter != nullptr) {