mgr/ServiceMap: adjust 'ceph -s' summary

- Do not list individual daemon ids as this won't scale for larger
  clusters
- Do not contemplate multile daemons of the same type that register with
  different "daemon_type" -- not until we actually have any that do that.
- Present counts by various groupings: distinct hosts and rgw zones to
  start.

  services:
    mon:           1 daemons, quorum a (age 4m)
    mgr:           x(active, since 3m)
    osd:           1 osds: 1 up (since 3m), 1 in (since 3m)
    cephfs-mirror: 1 daemon active (1 hosts)
    rbd-mirror:    2 daemons active (1 hosts)
    rgw:           2 daemons active (1 hosts, 1 zones)

Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
Sage Weil 2021-03-19 08:21:18 -04:00
parent afc33758e0
commit ab0d8f2ae9
2 changed files with 42 additions and 50 deletions

View File

@ -78,60 +78,48 @@ std::string ServiceMap::Service::get_summary() const
return "no daemons active";
}
std::ostringstream ss;
// The format two pairs in metadata:
// "daemon_type" : "${TYPE}"
// "daemon_prefix" : "${PREFIX}"
// If "daemon_type" is present, this will be used in place of "daemon" when
// reporting the count (e.g., "${N} daemons").
//
// TYPE: will be used to replace the default "daemon(s)"
// showed in `ceph -s`. If absent, the "daemon" will be used.
// PREFIX: if present the active members will be classified
// by the prefix instead of "daemon_name".
// We will additional break down the count by various groupings, based
// on the following keys:
//
// "hostname" -> host(s)
// "zone_id" -> zone(s)
//
// For exmaple for iscsi gateways, it will be something likes:
// "daemon_type" : "portal"
// "daemon_prefix" : "gateway${N}"
// The `ceph -s` will be something likes:
// iscsi: 3 portals active (gateway0, gateway1, gateway2)
// iscsi: 3 portals active (3 hosts)
// rgw: 3 gateways active (3 hosts, 1 zone)
std::map<std::string, std::set<std::string>> prefs;
std::map<std::string, std::set<std::string>> groupings;
std::string type("daemon");
int num = 0;
for (auto& d : daemons) {
// In case the "daemon_type" is absent, use the
// default "daemon" type
std::string type("daemon");
std::string prefix;
auto t = d.second.metadata.find("daemon_type");
if (t != d.second.metadata.end()) {
type = d.second.metadata.at("daemon_type");
++num;
if (auto p = d.second.metadata.find("daemon_type");
p != d.second.metadata.end()) {
type = p->second;
}
auto p = d.second.metadata.find("daemon_prefix");
if (p != d.second.metadata.end()) {
prefix = d.second.metadata.at("daemon_prefix");
} else {
// In case the "daemon_prefix" is absent, show
// the daemon_name instead.
prefix = d.first;
for (auto k : {make_pair("zone", "zone_id"),
make_pair("host", "hostname")}) {
auto p = d.second.metadata.find(k.second);
if (p != d.second.metadata.end()) {
groupings[k.first].insert(p->second);
}
}
auto& pref = prefs[type];
pref.insert(prefix);
}
for (auto &pr : prefs) {
if (!ss.str().empty())
ss << ", ";
ss << pr.second.size() << " " << pr.first
<< (pr.second.size() > 1 ? "s" : "")
<< " active";
if (pr.second.size()) {
ss << " (";
std::copy(std::begin(pr.second), std::end(pr.second),
std::experimental::make_ostream_joiner(ss, ", "));
ss << ")";
std::ostringstream ss;
ss << num << " " << type << (num > 1 ? "s" : "") << " active";
if (groupings.size()) {
ss << " (";
for (auto i = groupings.begin(); i != groupings.end(); ++i) {
if (i != groupings.begin()) {
ss << ", ";
}
ss << i->second.size() << " " << i->first << (i->second.size() ? "s" : "");
}
ss << ")";
}
return ss.str();

View File

@ -71,12 +71,16 @@ static void status_format_func(const int i, std::mutex &lock,
"daemon_prefix", '\0', "gateway", '\0'));
} else {
string prefix = string("gw") + stringify(i % 4);
ASSERT_NE(-1, asprintf(&metadata_buf, "%s%c%s%c%s%c%s%c",
string zone = string("z") + stringify(i % 3);
ASSERT_NE(-1, asprintf(&metadata_buf, "%s%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c",
"daemon_type", '\0', "portal", '\0',
"daemon_prefix", '\0', prefix.c_str(), '\0'));
"daemon_prefix", '\0', prefix.c_str(), '\0',
"hostname", '\0', prefix.c_str(), '\0',
"zone_id", '\0', zone.c_str(), '\0'
));
}
string name = string("rbd/image") + stringify(i);
ASSERT_EQ(0, rados_service_register(cluster, "iscsi", name.c_str(),
ASSERT_EQ(0, rados_service_register(cluster, "foo", name.c_str(),
metadata_buf));
std::unique_lock<std::mutex> l(lock);
@ -140,10 +144,10 @@ TEST(LibRadosService, StatusFormat) {
ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0,
&outbuf, &outlen, NULL, NULL));
std::string out(outbuf, outlen);
cout << out << std::endl;
bool success = false;
auto r1 = out.find("5 portals active (gw0, gw1, gw2, gw3, rbd/image1)");
auto r2 = out.find("2 daemons active (gateway, rbd/image0");
if (std::string::npos != r1 && std::string::npos != r2) {
auto r1 = out.find("16 portals active (1 hosts, 3 zones)");
if (std::string::npos != r1) {
success = true;
}
rados_buffer_free(outbuf);