summaryrefslogtreecommitdiffstats
path: root/src/mgr/ServiceMap.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr/ServiceMap.cc')
-rw-r--r--src/mgr/ServiceMap.cc244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/mgr/ServiceMap.cc b/src/mgr/ServiceMap.cc
new file mode 100644
index 000000000..b6f8ad97c
--- /dev/null
+++ b/src/mgr/ServiceMap.cc
@@ -0,0 +1,244 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "mgr/ServiceMap.h"
+
+#include <experimental/iterator>
+#include <fmt/format.h>
+#include <regex>
+
+#include "common/Formatter.h"
+
+using ceph::bufferlist;
+using ceph::Formatter;
+
+// Daemon
+
+void ServiceMap::Daemon::encode(bufferlist& bl, uint64_t features) const
+{
+ ENCODE_START(2, 1, bl);
+ encode(gid, bl);
+ encode(addr, bl, features);
+ encode(start_epoch, bl);
+ encode(start_stamp, bl);
+ encode(metadata, bl);
+ encode(task_status, bl);
+ ENCODE_FINISH(bl);
+}
+
+void ServiceMap::Daemon::decode(bufferlist::const_iterator& p)
+{
+ DECODE_START(2, p);
+ decode(gid, p);
+ decode(addr, p);
+ decode(start_epoch, p);
+ decode(start_stamp, p);
+ decode(metadata, p);
+ if (struct_v >= 2) {
+ decode(task_status, p);
+ }
+ DECODE_FINISH(p);
+}
+
+void ServiceMap::Daemon::dump(Formatter *f) const
+{
+ f->dump_unsigned("start_epoch", start_epoch);
+ f->dump_stream("start_stamp") << start_stamp;
+ f->dump_unsigned("gid", gid);
+ f->dump_string("addr", addr.get_legacy_str());
+ f->open_object_section("metadata");
+ for (auto& p : metadata) {
+ f->dump_string(p.first.c_str(), p.second);
+ }
+ f->close_section();
+ f->open_object_section("task_status");
+ for (auto& p : task_status) {
+ f->dump_string(p.first.c_str(), p.second);
+ }
+ f->close_section();
+}
+
+void ServiceMap::Daemon::generate_test_instances(std::list<Daemon*>& ls)
+{
+ ls.push_back(new Daemon);
+ ls.push_back(new Daemon);
+ ls.back()->gid = 222;
+ ls.back()->metadata["this"] = "that";
+ ls.back()->task_status["task1"] = "running";
+}
+
+// Service
+
+std::string ServiceMap::Service::get_summary() const
+{
+ if (!summary.empty()) {
+ return summary;
+ }
+ if (daemons.empty()) {
+ return "no daemons active";
+ }
+
+ // If "daemon_type" is present, this will be used in place of "daemon" when
+ // reporting the count (e.g., "${N} daemons").
+ //
+ // We will additional break down the count by various groupings, based
+ // on the following keys:
+ //
+ // "hostname" -> host(s)
+ // "zone_id" -> zone(s)
+ //
+ // The `ceph -s` will be something likes:
+ // iscsi: 3 portals active (3 hosts)
+ // rgw: 3 gateways active (3 hosts, 1 zone)
+
+ std::map<std::string, std::set<std::string>> groupings;
+ std::string type("daemon");
+ int num = 0;
+ for (auto& d : daemons) {
+ ++num;
+ if (auto p = d.second.metadata.find("daemon_type");
+ p != d.second.metadata.end()) {
+ type = p->second;
+ }
+ 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);
+ }
+ }
+ }
+
+ 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();
+}
+
+bool ServiceMap::Service::has_running_tasks() const
+{
+ return std::any_of(daemons.begin(), daemons.end(), [](auto& daemon) {
+ return !daemon.second.task_status.empty();
+ });
+}
+
+std::string ServiceMap::Service::get_task_summary(const std::string_view task_prefix) const
+{
+ // contruct a map similar to:
+ // {"service1 status" -> {"service1.0" -> "running"}}
+ // {"service2 status" -> {"service2.0" -> "idle"},
+ // {"service2.1" -> "running"}}
+ std::map<std::string, std::map<std::string, std::string>> by_task;
+ for (const auto& [service_id, daemon] : daemons) {
+ for (const auto& [task_name, status] : daemon.task_status) {
+ by_task[task_name].emplace(fmt::format("{}.{}", task_prefix, service_id),
+ status);
+ }
+ }
+ std::stringstream ss;
+ for (const auto &[task_name, status_by_service] : by_task) {
+ ss << "\n " << task_name << ":";
+ for (auto& [service, status] : status_by_service) {
+ ss << "\n " << service << ": " << status;
+ }
+ }
+ return ss.str();
+}
+
+void ServiceMap::Service::count_metadata(const std::string& field,
+ std::map<std::string,int> *out) const
+{
+ for (auto& p : daemons) {
+ auto q = p.second.metadata.find(field);
+ if (q == p.second.metadata.end()) {
+ (*out)["unknown"]++;
+ } else {
+ (*out)[q->second]++;
+ }
+ }
+}
+
+void ServiceMap::Service::encode(bufferlist& bl, uint64_t features) const
+{
+ ENCODE_START(1, 1, bl);
+ encode(daemons, bl, features);
+ encode(summary, bl);
+ ENCODE_FINISH(bl);
+}
+
+void ServiceMap::Service::decode(bufferlist::const_iterator& p)
+{
+ DECODE_START(1, p);
+ decode(daemons, p);
+ decode(summary, p);
+ DECODE_FINISH(p);
+}
+
+void ServiceMap::Service::dump(Formatter *f) const
+{
+ f->open_object_section("daemons");
+ f->dump_string("summary", summary);
+ for (auto& p : daemons) {
+ f->dump_object(p.first.c_str(), p.second);
+ }
+ f->close_section();
+}
+
+void ServiceMap::Service::generate_test_instances(std::list<Service*>& ls)
+{
+ ls.push_back(new Service);
+ ls.push_back(new Service);
+ ls.back()->daemons["one"].gid = 1;
+ ls.back()->daemons["two"].gid = 2;
+}
+
+// ServiceMap
+
+void ServiceMap::encode(bufferlist& bl, uint64_t features) const
+{
+ ENCODE_START(1, 1, bl);
+ encode(epoch, bl);
+ encode(modified, bl);
+ encode(services, bl, features);
+ ENCODE_FINISH(bl);
+}
+
+void ServiceMap::decode(bufferlist::const_iterator& p)
+{
+ DECODE_START(1, p);
+ decode(epoch, p);
+ decode(modified, p);
+ decode(services, p);
+ DECODE_FINISH(p);
+}
+
+void ServiceMap::dump(Formatter *f) const
+{
+ f->dump_unsigned("epoch", epoch);
+ f->dump_stream("modified") << modified;
+ f->open_object_section("services");
+ for (auto& p : services) {
+ f->dump_object(p.first.c_str(), p.second);
+ }
+ f->close_section();
+}
+
+void ServiceMap::generate_test_instances(std::list<ServiceMap*>& ls)
+{
+ ls.push_back(new ServiceMap);
+ ls.push_back(new ServiceMap);
+ ls.back()->epoch = 123;
+ ls.back()->services["rgw"].daemons["one"].gid = 123;
+ ls.back()->services["rgw"].daemons["two"].gid = 344;
+ ls.back()->services["iscsi"].daemons["foo"].gid = 3222;
+}