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>;