]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/ServiceDaemon.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / rbd_mirror / ServiceDaemon.cc
CommitLineData
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
22namespace rbd {
23namespace mirror {
24
25namespace {
26
27const std::string RBD_MIRROR_AUTH_ID_PREFIX("rbd-mirror.");
28
29struct 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
50using namespace service_daemon;
51
52template <typename I>
53ServiceDaemon<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
59template <typename I>
60ServiceDaemon<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
69template <typename I>
70int 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
90template <typename I>
91void 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
101template <typename I>
102void 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
111template <typename I>
112void 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
127template <typename I>
128void 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
143template <typename I>
144uint64_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
170template <typename I>
171void 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
187template <typename I>
188void 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
207template <typename I>
208void 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
239template <typename I>
240void 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
257template <typename I>
258void 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
271template <typename I>
272void 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
327template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>;