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)
55 : m_cct(cct), m_rados(rados), m_threads(threads) {
56 dout(20) << dendl;
57 }
58
59 template <typename I>
(1) Event exn_spec_violation: |
An exception of type "std::length_error" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate(). |
Also see events: |
[fun_call_w_exception] |
60 ServiceDaemon<I>::~ServiceDaemon() {
(2) Event fun_call_w_exception: |
Called function throws an exception of type "std::length_error". [details] |
Also see events: |
[exn_spec_violation] |
61 dout(20) << dendl;
62 std::lock_guard timer_locker{m_threads->timer_lock};
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
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());
76 }
77
78 std::string instance_id = stringify(m_rados->get_instance_id());
79 std::map<std::string, std::string> service_metadata = {
80 {"id", id}, {"instance_id", instance_id}};
81 int r = m_rados->service_daemon_register("rbd-mirror", instance_id,
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 {
95 std::lock_guard locker{m_lock};
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 {
105 std::lock_guard locker{m_lock};
106 m_pools.erase(pool_id);
107 }
108 schedule_update_status();
109 }
110
111 template <typename I>
112 uint64_t ServiceDaemon<I>::add_or_update_callout(int64_t pool_id,
113 uint64_t callout_id,
114 CalloutLevel callout_level,
115 const std::string& text) {
116 dout(20) << "pool_id=" << pool_id << ", "
117 << "callout_id=" << callout_id << ", "
118 << "callout_level=" << callout_level << ", "
119 << "text=" << text << dendl;
120
121 {
122 std::lock_guard locker{m_lock};
123 auto pool_it = m_pools.find(pool_id);
124 if (pool_it == m_pools.end()) {
125 return CALLOUT_ID_NONE;
126 }
127
128 if (callout_id == CALLOUT_ID_NONE) {
129 callout_id = ++m_callout_id;
130 }
131 pool_it->second.callouts[callout_id] = {callout_level, text};
132 }
133
134 schedule_update_status();
135 return callout_id;
136 }
137
138 template <typename I>
139 void ServiceDaemon<I>::remove_callout(int64_t pool_id, uint64_t callout_id) {
140 dout(20) << "pool_id=" << pool_id << ", "
141 << "callout_id=" << callout_id << dendl;
142
143 {
144 std::lock_guard locker{m_lock};
145 auto pool_it = m_pools.find(pool_id);
146 if (pool_it == m_pools.end()) {
147 return;
148 }
149 pool_it->second.callouts.erase(callout_id);
150 }
151
152 schedule_update_status();
153 }
154
155 template <typename I>
156 void ServiceDaemon<I>::add_or_update_attribute(int64_t pool_id,
157 const std::string& key,
158 const AttributeValue& value) {
159 dout(20) << "pool_id=" << pool_id << ", "
160 << "key=" << key << ", "
161 << "value=" << value << dendl;
162
163 {
164 std::lock_guard locker{m_lock};
165 auto pool_it = m_pools.find(pool_id);
166 if (pool_it == m_pools.end()) {
167 return;
168 }
169 pool_it->second.attributes[key] = value;
170 }
171
172 schedule_update_status();
173 }
174
175 template <typename I>
176 void ServiceDaemon<I>::remove_attribute(int64_t pool_id,
177 const std::string& key) {
178 dout(20) << "pool_id=" << pool_id << ", "
179 << "key=" << key << dendl;
180
181 {
182 std::lock_guard locker{m_lock};
183 auto pool_it = m_pools.find(pool_id);
184 if (pool_it == m_pools.end()) {
185 return;
186 }
187 pool_it->second.attributes.erase(key);
188 }
189
190 schedule_update_status();
191 }
192
193 template <typename I>
194 void ServiceDaemon<I>::schedule_update_status() {
195 std::lock_guard timer_locker{m_threads->timer_lock};
196 if (m_timer_ctx != nullptr) {
197 return;
198 }
199
200 m_timer_ctx = new LambdaContext([this](int) {
201 m_timer_ctx = nullptr;
202 update_status();
203 });
204 m_threads->timer->add_event_after(1, m_timer_ctx);
205 }
206
207 template <typename I>
208 void ServiceDaemon<I>::update_status() {
209 dout(20) << dendl;
210 ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock));
211
212 ceph::JSONFormatter f;
213 {
214 std::lock_guard locker{m_lock};
215 f.open_object_section("pools");
216 for (auto& pool_pair : m_pools) {
217 f.open_object_section(stringify(pool_pair.first).c_str());
218 f.dump_string("name", pool_pair.second.name);
219 f.open_object_section("callouts");
220 for (auto& callout : pool_pair.second.callouts) {
221 f.open_object_section(stringify(callout.first).c_str());
222 f.dump_string("level", stringify(callout.second.level).c_str());
223 f.dump_string("text", callout.second.text.c_str());
224 f.close_section();
225 }
226 f.close_section(); // callouts
227
228 for (auto& attribute : pool_pair.second.attributes) {
229 AttributeDumpVisitor attribute_dump_visitor(&f, attribute.first);
230 boost::apply_visitor(attribute_dump_visitor, attribute.second);
231 }
232 f.close_section(); // pool
233 }
234 f.close_section(); // pools
235 }
236
237 std::stringstream ss;
238 f.flush(ss);
239
240 int r = m_rados->service_daemon_update_status({{"json", ss.str()}});
241 if (r < 0) {
242 derr << "failed to update service daemon status: " << cpp_strerror(r)
243 << dendl;
244 }
245 }
246
247 } // namespace mirror
248 } // namespace rbd
249
250 template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>;
251