]>
Commit | Line | Data |
---|---|---|
c07f9fc5 FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "tools/rbd_mirror/ServiceDaemon.h" | |
5 | #include "include/Context.h" | |
6 | #include "include/stringify.h" | |
7 | #include "common/ceph_context.h" | |
8 | #include "common/config.h" | |
9 | #include "common/debug.h" | |
10 | #include "common/errno.h" | |
11 | #include "common/Formatter.h" | |
12 | #include "common/Timer.h" | |
13 | #include "tools/rbd_mirror/Threads.h" | |
14 | #include <sstream> | |
15 | ||
16 | #define dout_context g_ceph_context | |
17 | #define dout_subsys ceph_subsys_rbd_mirror | |
18 | #undef dout_prefix | |
19 | #define dout_prefix *_dout << "rbd::mirror::ServiceDaemon: " << this << " " \ | |
20 | << __func__ << ": " | |
21 | ||
22 | namespace rbd { | |
23 | namespace mirror { | |
24 | ||
25 | namespace { | |
26 | ||
27 | const std::string RBD_MIRROR_AUTH_ID_PREFIX("rbd-mirror."); | |
28 | ||
29 | struct AttributeDumpVisitor : public boost::static_visitor<void> { | |
30 | ceph::Formatter *f; | |
31 | const std::string& name; | |
32 | ||
33 | AttributeDumpVisitor(ceph::Formatter *f, const std::string& name) | |
34 | : f(f), name(name) { | |
35 | } | |
36 | ||
37 | void operator()(bool val) const { | |
38 | f->dump_bool(name.c_str(), val); | |
39 | } | |
40 | void operator()(uint64_t val) const { | |
41 | f->dump_unsigned(name.c_str(), val); | |
42 | } | |
43 | void operator()(const std::string& val) const { | |
44 | f->dump_string(name.c_str(), val); | |
45 | } | |
46 | }; | |
47 | ||
48 | } // anonymous namespace | |
49 | ||
50 | using namespace service_daemon; | |
51 | ||
52 | template <typename I> | |
53 | ServiceDaemon<I>::ServiceDaemon(CephContext *cct, RadosRef rados, | |
54 | Threads<I>* threads) | |
9f95a23c | 55 | : m_cct(cct), m_rados(rados), m_threads(threads) { |
c07f9fc5 FG |
56 | dout(20) << dendl; |
57 | } | |
58 | ||
59 | template <typename I> | |
60 | ServiceDaemon<I>::~ServiceDaemon() { | |
61 | dout(20) << dendl; | |
9f95a23c | 62 | std::lock_guard timer_locker{m_threads->timer_lock}; |
c07f9fc5 FG |
63 | if (m_timer_ctx != nullptr) { |
64 | m_threads->timer->cancel_event(m_timer_ctx); | |
65 | update_status(); | |
66 | } | |
67 | } | |
68 | ||
69 | template <typename I> | |
70 | int ServiceDaemon<I>::init() { | |
71 | dout(20) << dendl; | |
72 | ||
11fdf7f2 TL |
73 | std::string id = m_cct->_conf->name.get_id(); |
74 | if (id.find(RBD_MIRROR_AUTH_ID_PREFIX) == 0) { | |
75 | id = id.substr(RBD_MIRROR_AUTH_ID_PREFIX.size()); | |
c07f9fc5 FG |
76 | } |
77 | ||
11fdf7f2 | 78 | std::string instance_id = stringify(m_rados->get_instance_id()); |
c07f9fc5 | 79 | std::map<std::string, std::string> service_metadata = { |
11fdf7f2 TL |
80 | {"id", id}, {"instance_id", instance_id}}; |
81 | int r = m_rados->service_daemon_register("rbd-mirror", instance_id, | |
c07f9fc5 FG |
82 | service_metadata); |
83 | if (r < 0) { | |
84 | return r; | |
85 | } | |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | template <typename I> | |
91 | void ServiceDaemon<I>::add_pool(int64_t pool_id, const std::string& pool_name) { | |
92 | dout(20) << "pool_id=" << pool_id << ", pool_name=" << pool_name << dendl; | |
93 | ||
94 | { | |
9f95a23c | 95 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
96 | m_pools.insert({pool_id, {pool_name}}); |
97 | } | |
98 | schedule_update_status(); | |
99 | } | |
100 | ||
101 | template <typename I> | |
102 | void ServiceDaemon<I>::remove_pool(int64_t pool_id) { | |
103 | dout(20) << "pool_id=" << pool_id << dendl; | |
104 | { | |
9f95a23c | 105 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
106 | m_pools.erase(pool_id); |
107 | } | |
108 | schedule_update_status(); | |
109 | } | |
110 | ||
9f95a23c TL |
111 | template <typename I> |
112 | void ServiceDaemon<I>::add_namespace(int64_t pool_id, | |
113 | const std::string& namespace_name) { | |
114 | dout(20) << "pool_id=" << pool_id << ", namespace=" << namespace_name | |
115 | << dendl; | |
116 | ||
117 | std::lock_guard locker{m_lock}; | |
118 | auto pool_it = m_pools.find(pool_id); | |
119 | if (pool_it == m_pools.end()) { | |
120 | return; | |
121 | } | |
122 | pool_it->second.ns_attributes[namespace_name]; | |
123 | ||
124 | // don't schedule update status as the namespace attributes are empty yet | |
125 | } | |
126 | ||
127 | template <typename I> | |
128 | void ServiceDaemon<I>::remove_namespace(int64_t pool_id, | |
129 | const std::string& namespace_name) { | |
130 | dout(20) << "pool_id=" << pool_id << ", namespace=" << namespace_name | |
131 | << dendl; | |
132 | { | |
133 | std::lock_guard locker{m_lock}; | |
134 | auto pool_it = m_pools.find(pool_id); | |
135 | if (pool_it == m_pools.end()) { | |
136 | return; | |
137 | } | |
138 | pool_it->second.ns_attributes.erase(namespace_name); | |
139 | } | |
140 | schedule_update_status(); | |
141 | } | |
142 | ||
c07f9fc5 FG |
143 | template <typename I> |
144 | uint64_t ServiceDaemon<I>::add_or_update_callout(int64_t pool_id, | |
145 | uint64_t callout_id, | |
146 | CalloutLevel callout_level, | |
147 | const std::string& text) { | |
148 | dout(20) << "pool_id=" << pool_id << ", " | |
149 | << "callout_id=" << callout_id << ", " | |
150 | << "callout_level=" << callout_level << ", " | |
151 | << "text=" << text << dendl; | |
152 | ||
153 | { | |
9f95a23c | 154 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
155 | auto pool_it = m_pools.find(pool_id); |
156 | if (pool_it == m_pools.end()) { | |
157 | return CALLOUT_ID_NONE; | |
158 | } | |
159 | ||
160 | if (callout_id == CALLOUT_ID_NONE) { | |
161 | callout_id = ++m_callout_id; | |
162 | } | |
163 | pool_it->second.callouts[callout_id] = {callout_level, text}; | |
164 | } | |
165 | ||
166 | schedule_update_status(); | |
167 | return callout_id; | |
168 | } | |
169 | ||
170 | template <typename I> | |
171 | void ServiceDaemon<I>::remove_callout(int64_t pool_id, uint64_t callout_id) { | |
172 | dout(20) << "pool_id=" << pool_id << ", " | |
173 | << "callout_id=" << callout_id << dendl; | |
174 | ||
175 | { | |
9f95a23c | 176 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
177 | auto pool_it = m_pools.find(pool_id); |
178 | if (pool_it == m_pools.end()) { | |
179 | return; | |
180 | } | |
181 | pool_it->second.callouts.erase(callout_id); | |
182 | } | |
183 | ||
184 | schedule_update_status(); | |
185 | } | |
186 | ||
187 | template <typename I> | |
188 | void ServiceDaemon<I>::add_or_update_attribute(int64_t pool_id, | |
189 | const std::string& key, | |
190 | const AttributeValue& value) { | |
191 | dout(20) << "pool_id=" << pool_id << ", " | |
192 | << "key=" << key << ", " | |
193 | << "value=" << value << dendl; | |
194 | ||
195 | { | |
9f95a23c | 196 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
197 | auto pool_it = m_pools.find(pool_id); |
198 | if (pool_it == m_pools.end()) { | |
199 | return; | |
200 | } | |
201 | pool_it->second.attributes[key] = value; | |
202 | } | |
203 | ||
204 | schedule_update_status(); | |
205 | } | |
206 | ||
9f95a23c TL |
207 | template <typename I> |
208 | void ServiceDaemon<I>::add_or_update_namespace_attribute( | |
209 | int64_t pool_id, const std::string& namespace_name, const std::string& key, | |
210 | const AttributeValue& value) { | |
211 | if (namespace_name.empty()) { | |
212 | add_or_update_attribute(pool_id, key, value); | |
213 | return; | |
214 | } | |
215 | ||
216 | dout(20) << "pool_id=" << pool_id << ", " | |
217 | << "namespace=" << namespace_name << ", " | |
218 | << "key=" << key << ", " | |
219 | << "value=" << value << dendl; | |
220 | ||
221 | { | |
222 | std::lock_guard locker{m_lock}; | |
223 | auto pool_it = m_pools.find(pool_id); | |
224 | if (pool_it == m_pools.end()) { | |
225 | return; | |
226 | } | |
227 | ||
228 | auto ns_it = pool_it->second.ns_attributes.find(namespace_name); | |
229 | if (ns_it == pool_it->second.ns_attributes.end()) { | |
230 | return; | |
231 | } | |
232 | ||
233 | ns_it->second[key] = value; | |
234 | } | |
235 | ||
236 | schedule_update_status(); | |
237 | } | |
238 | ||
c07f9fc5 FG |
239 | template <typename I> |
240 | void ServiceDaemon<I>::remove_attribute(int64_t pool_id, | |
241 | const std::string& key) { | |
242 | dout(20) << "pool_id=" << pool_id << ", " | |
243 | << "key=" << key << dendl; | |
244 | ||
245 | { | |
9f95a23c | 246 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
247 | auto pool_it = m_pools.find(pool_id); |
248 | if (pool_it == m_pools.end()) { | |
249 | return; | |
250 | } | |
251 | pool_it->second.attributes.erase(key); | |
252 | } | |
253 | ||
254 | schedule_update_status(); | |
255 | } | |
256 | ||
257 | template <typename I> | |
258 | void ServiceDaemon<I>::schedule_update_status() { | |
9f95a23c | 259 | std::lock_guard timer_locker{m_threads->timer_lock}; |
c07f9fc5 FG |
260 | if (m_timer_ctx != nullptr) { |
261 | return; | |
262 | } | |
263 | ||
9f95a23c | 264 | m_timer_ctx = new LambdaContext([this](int) { |
c07f9fc5 FG |
265 | m_timer_ctx = nullptr; |
266 | update_status(); | |
267 | }); | |
268 | m_threads->timer->add_event_after(1, m_timer_ctx); | |
269 | } | |
270 | ||
271 | template <typename I> | |
272 | void ServiceDaemon<I>::update_status() { | |
273 | dout(20) << dendl; | |
9f95a23c | 274 | ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock)); |
c07f9fc5 FG |
275 | |
276 | ceph::JSONFormatter f; | |
277 | { | |
9f95a23c | 278 | std::lock_guard locker{m_lock}; |
c07f9fc5 FG |
279 | f.open_object_section("pools"); |
280 | for (auto& pool_pair : m_pools) { | |
281 | f.open_object_section(stringify(pool_pair.first).c_str()); | |
282 | f.dump_string("name", pool_pair.second.name); | |
283 | f.open_object_section("callouts"); | |
284 | for (auto& callout : pool_pair.second.callouts) { | |
285 | f.open_object_section(stringify(callout.first).c_str()); | |
286 | f.dump_string("level", stringify(callout.second.level).c_str()); | |
287 | f.dump_string("text", callout.second.text.c_str()); | |
288 | f.close_section(); | |
289 | } | |
290 | f.close_section(); // callouts | |
291 | ||
292 | for (auto& attribute : pool_pair.second.attributes) { | |
293 | AttributeDumpVisitor attribute_dump_visitor(&f, attribute.first); | |
294 | boost::apply_visitor(attribute_dump_visitor, attribute.second); | |
295 | } | |
9f95a23c TL |
296 | |
297 | if (!pool_pair.second.ns_attributes.empty()) { | |
298 | f.open_object_section("namespaces"); | |
299 | for (auto& [ns, attributes] : pool_pair.second.ns_attributes) { | |
300 | f.open_object_section(ns.c_str()); | |
301 | for (auto& [key, value] : attributes) { | |
302 | AttributeDumpVisitor attribute_dump_visitor(&f, key); | |
303 | boost::apply_visitor(attribute_dump_visitor, value); | |
304 | } | |
305 | f.close_section(); // namespace | |
306 | } | |
307 | f.close_section(); // namespaces | |
308 | } | |
c07f9fc5 FG |
309 | f.close_section(); // pool |
310 | } | |
311 | f.close_section(); // pools | |
312 | } | |
313 | ||
314 | std::stringstream ss; | |
315 | f.flush(ss); | |
316 | ||
317 | int r = m_rados->service_daemon_update_status({{"json", ss.str()}}); | |
318 | if (r < 0) { | |
319 | derr << "failed to update service daemon status: " << cpp_strerror(r) | |
320 | << dendl; | |
321 | } | |
322 | } | |
323 | ||
324 | } // namespace mirror | |
325 | } // namespace rbd | |
326 | ||
327 | template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>; |