]>
Commit | Line | Data |
---|---|---|
224ce89b WB |
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 | ||
f67539c2 | 6 | #include <fmt/format.h> |
f67539c2 | 7 | |
224ce89b WB |
8 | #include "common/Formatter.h" |
9 | ||
9f95a23c TL |
10 | using ceph::bufferlist; |
11 | using ceph::Formatter; | |
12 | ||
224ce89b WB |
13 | // Daemon |
14 | ||
15 | void ServiceMap::Daemon::encode(bufferlist& bl, uint64_t features) const | |
16 | { | |
9f95a23c | 17 | ENCODE_START(2, 1, bl); |
11fdf7f2 TL |
18 | encode(gid, bl); |
19 | encode(addr, bl, features); | |
20 | encode(start_epoch, bl); | |
21 | encode(start_stamp, bl); | |
22 | encode(metadata, bl); | |
9f95a23c | 23 | encode(task_status, bl); |
224ce89b WB |
24 | ENCODE_FINISH(bl); |
25 | } | |
26 | ||
11fdf7f2 | 27 | void ServiceMap::Daemon::decode(bufferlist::const_iterator& p) |
224ce89b | 28 | { |
9f95a23c | 29 | DECODE_START(2, p); |
11fdf7f2 TL |
30 | decode(gid, p); |
31 | decode(addr, p); | |
32 | decode(start_epoch, p); | |
33 | decode(start_stamp, p); | |
34 | decode(metadata, p); | |
9f95a23c TL |
35 | if (struct_v >= 2) { |
36 | decode(task_status, p); | |
37 | } | |
224ce89b WB |
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); | |
11fdf7f2 | 46 | f->dump_string("addr", addr.get_legacy_str()); |
224ce89b WB |
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(); | |
9f95a23c TL |
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(); | |
224ce89b WB |
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"; | |
9f95a23c | 65 | ls.back()->task_status["task1"] = "running"; |
224ce89b WB |
66 | } |
67 | ||
68 | // Service | |
69 | ||
f67539c2 TL |
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 | } | |
20effc67 TL |
101 | for (auto k : {std::make_pair("zone", "zone_id"), |
102 | std::make_pair("host", "hostname")}) { | |
f67539c2 TL |
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 | ||
224ce89b WB |
169 | void ServiceMap::Service::encode(bufferlist& bl, uint64_t features) const |
170 | { | |
171 | ENCODE_START(1, 1, bl); | |
11fdf7f2 TL |
172 | encode(daemons, bl, features); |
173 | encode(summary, bl); | |
224ce89b WB |
174 | ENCODE_FINISH(bl); |
175 | } | |
176 | ||
11fdf7f2 | 177 | void ServiceMap::Service::decode(bufferlist::const_iterator& p) |
224ce89b WB |
178 | { |
179 | DECODE_START(1, p); | |
11fdf7f2 TL |
180 | decode(daemons, p); |
181 | decode(summary, p); | |
224ce89b WB |
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); | |
11fdf7f2 TL |
208 | encode(epoch, bl); |
209 | encode(modified, bl); | |
210 | encode(services, bl, features); | |
224ce89b WB |
211 | ENCODE_FINISH(bl); |
212 | } | |
213 | ||
11fdf7f2 | 214 | void ServiceMap::decode(bufferlist::const_iterator& p) |
224ce89b WB |
215 | { |
216 | DECODE_START(1, p); | |
11fdf7f2 TL |
217 | decode(epoch, p); |
218 | decode(modified, p); | |
219 | decode(services, p); | |
224ce89b WB |
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 | } |