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