1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
16 #define dout_context g_ceph_context
17 #define dout_subsys ceph_subsys_rbd_mirror
19 #define dout_prefix *_dout << "rbd::mirror::ServiceDaemon: " << this << " " \
27 const std::string
RBD_MIRROR_AUTH_ID_PREFIX("rbd-mirror.");
29 struct AttributeDumpVisitor
: public boost::static_visitor
<void> {
31 const std::string
& name
;
33 AttributeDumpVisitor(ceph::Formatter
*f
, const std::string
& name
)
37 void operator()(bool val
) const {
38 f
->dump_bool(name
.c_str(), val
);
40 void operator()(uint64_t val
) const {
41 f
->dump_unsigned(name
.c_str(), val
);
43 void operator()(const std::string
& val
) const {
44 f
->dump_string(name
.c_str(), val
);
48 } // anonymous namespace
50 using namespace service_daemon
;
53 ServiceDaemon
<I
>::ServiceDaemon(CephContext
*cct
, RadosRef rados
,
55 : m_cct(cct
), m_rados(rados
), m_threads(threads
),
56 m_lock("rbd::mirror::ServiceDaemon") {
61 ServiceDaemon
<I
>::~ServiceDaemon() {
63 Mutex::Locker
timer_locker(m_threads
->timer_lock
);
64 if (m_timer_ctx
!= nullptr) {
65 m_threads
->timer
->cancel_event(m_timer_ctx
);
71 int ServiceDaemon
<I
>::init() {
74 std::string name
= m_cct
->_conf
->name
.get_id();
75 if (name
.find(RBD_MIRROR_AUTH_ID_PREFIX
) == 0) {
76 name
= name
.substr(RBD_MIRROR_AUTH_ID_PREFIX
.size());
79 std::map
<std::string
, std::string
> service_metadata
= {
80 {"instance_id", stringify(m_rados
->get_instance_id())}
82 int r
= m_rados
->service_daemon_register("rbd-mirror", name
,
92 void ServiceDaemon
<I
>::add_pool(int64_t pool_id
, const std::string
& pool_name
) {
93 dout(20) << "pool_id=" << pool_id
<< ", pool_name=" << pool_name
<< dendl
;
96 Mutex::Locker
locker(m_lock
);
97 m_pools
.insert({pool_id
, {pool_name
}});
99 schedule_update_status();
102 template <typename I
>
103 void ServiceDaemon
<I
>::remove_pool(int64_t pool_id
) {
104 dout(20) << "pool_id=" << pool_id
<< dendl
;
106 Mutex::Locker
locker(m_lock
);
107 m_pools
.erase(pool_id
);
109 schedule_update_status();
112 template <typename I
>
113 uint64_t ServiceDaemon
<I
>::add_or_update_callout(int64_t pool_id
,
115 CalloutLevel callout_level
,
116 const std::string
& text
) {
117 dout(20) << "pool_id=" << pool_id
<< ", "
118 << "callout_id=" << callout_id
<< ", "
119 << "callout_level=" << callout_level
<< ", "
120 << "text=" << text
<< dendl
;
123 Mutex::Locker
locker(m_lock
);
124 auto pool_it
= m_pools
.find(pool_id
);
125 if (pool_it
== m_pools
.end()) {
126 return CALLOUT_ID_NONE
;
129 if (callout_id
== CALLOUT_ID_NONE
) {
130 callout_id
= ++m_callout_id
;
132 pool_it
->second
.callouts
[callout_id
] = {callout_level
, text
};
135 schedule_update_status();
139 template <typename I
>
140 void ServiceDaemon
<I
>::remove_callout(int64_t pool_id
, uint64_t callout_id
) {
141 dout(20) << "pool_id=" << pool_id
<< ", "
142 << "callout_id=" << callout_id
<< dendl
;
145 Mutex::Locker
locker(m_lock
);
146 auto pool_it
= m_pools
.find(pool_id
);
147 if (pool_it
== m_pools
.end()) {
150 pool_it
->second
.callouts
.erase(callout_id
);
153 schedule_update_status();
156 template <typename I
>
157 void ServiceDaemon
<I
>::add_or_update_attribute(int64_t pool_id
,
158 const std::string
& key
,
159 const AttributeValue
& value
) {
160 dout(20) << "pool_id=" << pool_id
<< ", "
161 << "key=" << key
<< ", "
162 << "value=" << value
<< dendl
;
165 Mutex::Locker
locker(m_lock
);
166 auto pool_it
= m_pools
.find(pool_id
);
167 if (pool_it
== m_pools
.end()) {
170 pool_it
->second
.attributes
[key
] = value
;
173 schedule_update_status();
176 template <typename I
>
177 void ServiceDaemon
<I
>::remove_attribute(int64_t pool_id
,
178 const std::string
& key
) {
179 dout(20) << "pool_id=" << pool_id
<< ", "
180 << "key=" << key
<< dendl
;
183 Mutex::Locker
locker(m_lock
);
184 auto pool_it
= m_pools
.find(pool_id
);
185 if (pool_it
== m_pools
.end()) {
188 pool_it
->second
.attributes
.erase(key
);
191 schedule_update_status();
194 template <typename I
>
195 void ServiceDaemon
<I
>::schedule_update_status() {
196 Mutex::Locker
timer_locker(m_threads
->timer_lock
);
197 if (m_timer_ctx
!= nullptr) {
201 m_timer_ctx
= new FunctionContext([this](int) {
202 m_timer_ctx
= nullptr;
205 m_threads
->timer
->add_event_after(1, m_timer_ctx
);
208 template <typename I
>
209 void ServiceDaemon
<I
>::update_status() {
211 assert(m_threads
->timer_lock
.is_locked());
213 ceph::JSONFormatter f
;
215 Mutex::Locker
locker(m_lock
);
216 f
.open_object_section("pools");
217 for (auto& pool_pair
: m_pools
) {
218 f
.open_object_section(stringify(pool_pair
.first
).c_str());
219 f
.dump_string("name", pool_pair
.second
.name
);
220 f
.open_object_section("callouts");
221 for (auto& callout
: pool_pair
.second
.callouts
) {
222 f
.open_object_section(stringify(callout
.first
).c_str());
223 f
.dump_string("level", stringify(callout
.second
.level
).c_str());
224 f
.dump_string("text", callout
.second
.text
.c_str());
227 f
.close_section(); // callouts
229 for (auto& attribute
: pool_pair
.second
.attributes
) {
230 AttributeDumpVisitor
attribute_dump_visitor(&f
, attribute
.first
);
231 boost::apply_visitor(attribute_dump_visitor
, attribute
.second
);
233 f
.close_section(); // pool
235 f
.close_section(); // pools
238 std::stringstream ss
;
241 int r
= m_rados
->service_daemon_update_status({{"json", ss
.str()}});
243 derr
<< "failed to update service daemon status: " << cpp_strerror(r
)
248 } // namespace mirror
251 template class rbd::mirror::ServiceDaemon
<librbd::ImageCtx
>;