]> git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/ServiceMap.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / mgr / ServiceMap.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "mgr/ServiceMap.h"
5
6 #include <fmt/format.h>
7
8 #include "common/Formatter.h"
9
10 using ceph::bufferlist;
11 using ceph::Formatter;
12
13 // Daemon
14
15 void ServiceMap::Daemon::encode(bufferlist& bl, uint64_t features) const
16 {
17 ENCODE_START(2, 1, bl);
18 encode(gid, bl);
19 encode(addr, bl, features);
20 encode(start_epoch, bl);
21 encode(start_stamp, bl);
22 encode(metadata, bl);
23 encode(task_status, bl);
24 ENCODE_FINISH(bl);
25 }
26
27 void ServiceMap::Daemon::decode(bufferlist::const_iterator& p)
28 {
29 DECODE_START(2, p);
30 decode(gid, p);
31 decode(addr, p);
32 decode(start_epoch, p);
33 decode(start_stamp, p);
34 decode(metadata, p);
35 if (struct_v >= 2) {
36 decode(task_status, p);
37 }
38 DECODE_FINISH(p);
39 }
40
41 void ServiceMap::Daemon::dump(Formatter *f) const
42 {
43 f->dump_unsigned("start_epoch", start_epoch);
44 f->dump_stream("start_stamp") << start_stamp;
45 f->dump_unsigned("gid", gid);
46 f->dump_string("addr", addr.get_legacy_str());
47 f->open_object_section("metadata");
48 for (auto& p : metadata) {
49 f->dump_string(p.first.c_str(), p.second);
50 }
51 f->close_section();
52 f->open_object_section("task_status");
53 for (auto& p : task_status) {
54 f->dump_string(p.first.c_str(), p.second);
55 }
56 f->close_section();
57 }
58
59 void ServiceMap::Daemon::generate_test_instances(std::list<Daemon*>& ls)
60 {
61 ls.push_back(new Daemon);
62 ls.push_back(new Daemon);
63 ls.back()->gid = 222;
64 ls.back()->metadata["this"] = "that";
65 ls.back()->task_status["task1"] = "running";
66 }
67
68 // Service
69
70 std::string ServiceMap::Service::get_summary() const
71 {
72 if (!summary.empty()) {
73 return summary;
74 }
75 if (daemons.empty()) {
76 return "no daemons active";
77 }
78
79 // If "daemon_type" is present, this will be used in place of "daemon" when
80 // reporting the count (e.g., "${N} daemons").
81 //
82 // We will additional break down the count by various groupings, based
83 // on the following keys:
84 //
85 // "hostname" -> host(s)
86 // "zone_id" -> zone(s)
87 //
88 // The `ceph -s` will be something likes:
89 // iscsi: 3 portals active (3 hosts)
90 // rgw: 3 gateways active (3 hosts, 1 zone)
91
92 std::map<std::string, std::set<std::string>> groupings;
93 std::string type("daemon");
94 int num = 0;
95 for (auto& d : daemons) {
96 ++num;
97 if (auto p = d.second.metadata.find("daemon_type");
98 p != d.second.metadata.end()) {
99 type = p->second;
100 }
101 for (auto k : {std::make_pair("zone", "zone_id"),
102 std::make_pair("host", "hostname")}) {
103 auto p = d.second.metadata.find(k.second);
104 if (p != d.second.metadata.end()) {
105 groupings[k.first].insert(p->second);
106 }
107 }
108 }
109
110 std::ostringstream ss;
111 ss << num << " " << type << (num > 1 ? "s" : "") << " active";
112 if (groupings.size()) {
113 ss << " (";
114 for (auto i = groupings.begin(); i != groupings.end(); ++i) {
115 if (i != groupings.begin()) {
116 ss << ", ";
117 }
118 ss << i->second.size() << " " << i->first << (i->second.size() ? "s" : "");
119 }
120 ss << ")";
121 }
122
123 return ss.str();
124 }
125
126 bool ServiceMap::Service::has_running_tasks() const
127 {
128 return std::any_of(daemons.begin(), daemons.end(), [](auto& daemon) {
129 return !daemon.second.task_status.empty();
130 });
131 }
132
133 std::string ServiceMap::Service::get_task_summary(const std::string_view task_prefix) const
134 {
135 // contruct a map similar to:
136 // {"service1 status" -> {"service1.0" -> "running"}}
137 // {"service2 status" -> {"service2.0" -> "idle"},
138 // {"service2.1" -> "running"}}
139 std::map<std::string, std::map<std::string, std::string>> by_task;
140 for (const auto& [service_id, daemon] : daemons) {
141 for (const auto& [task_name, status] : daemon.task_status) {
142 by_task[task_name].emplace(fmt::format("{}.{}", task_prefix, service_id),
143 status);
144 }
145 }
146 std::stringstream ss;
147 for (const auto &[task_name, status_by_service] : by_task) {
148 ss << "\n " << task_name << ":";
149 for (auto& [service, status] : status_by_service) {
150 ss << "\n " << service << ": " << status;
151 }
152 }
153 return ss.str();
154 }
155
156 void ServiceMap::Service::count_metadata(const std::string& field,
157 std::map<std::string,int> *out) const
158 {
159 for (auto& p : daemons) {
160 auto q = p.second.metadata.find(field);
161 if (q == p.second.metadata.end()) {
162 (*out)["unknown"]++;
163 } else {
164 (*out)[q->second]++;
165 }
166 }
167 }
168
169 void ServiceMap::Service::encode(bufferlist& bl, uint64_t features) const
170 {
171 ENCODE_START(1, 1, bl);
172 encode(daemons, bl, features);
173 encode(summary, bl);
174 ENCODE_FINISH(bl);
175 }
176
177 void ServiceMap::Service::decode(bufferlist::const_iterator& p)
178 {
179 DECODE_START(1, p);
180 decode(daemons, p);
181 decode(summary, p);
182 DECODE_FINISH(p);
183 }
184
185 void ServiceMap::Service::dump(Formatter *f) const
186 {
187 f->open_object_section("daemons");
188 f->dump_string("summary", summary);
189 for (auto& p : daemons) {
190 f->dump_object(p.first.c_str(), p.second);
191 }
192 f->close_section();
193 }
194
195 void ServiceMap::Service::generate_test_instances(std::list<Service*>& ls)
196 {
197 ls.push_back(new Service);
198 ls.push_back(new Service);
199 ls.back()->daemons["one"].gid = 1;
200 ls.back()->daemons["two"].gid = 2;
201 }
202
203 // ServiceMap
204
205 void ServiceMap::encode(bufferlist& bl, uint64_t features) const
206 {
207 ENCODE_START(1, 1, bl);
208 encode(epoch, bl);
209 encode(modified, bl);
210 encode(services, bl, features);
211 ENCODE_FINISH(bl);
212 }
213
214 void ServiceMap::decode(bufferlist::const_iterator& p)
215 {
216 DECODE_START(1, p);
217 decode(epoch, p);
218 decode(modified, p);
219 decode(services, p);
220 DECODE_FINISH(p);
221 }
222
223 void ServiceMap::dump(Formatter *f) const
224 {
225 f->dump_unsigned("epoch", epoch);
226 f->dump_stream("modified") << modified;
227 f->open_object_section("services");
228 for (auto& p : services) {
229 f->dump_object(p.first.c_str(), p.second);
230 }
231 f->close_section();
232 }
233
234 void ServiceMap::generate_test_instances(std::list<ServiceMap*>& ls)
235 {
236 ls.push_back(new ServiceMap);
237 ls.push_back(new ServiceMap);
238 ls.back()->epoch = 123;
239 ls.back()->services["rgw"].daemons["one"].gid = 123;
240 ls.back()->services["rgw"].daemons["two"].gid = 344;
241 ls.back()->services["iscsi"].daemons["foo"].gid = 3222;
242 }