Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / rbd_mirror / ServiceDaemon.cc
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     m_lock("rbd::mirror::ServiceDaemon") {
57   dout(20) << dendl;
58 }
59
60 template <typename I>
61 ServiceDaemon<I>::~ServiceDaemon() {
62   dout(20) << dendl;
63   Mutex::Locker timer_locker(m_threads->timer_lock);
64   if (m_timer_ctx != nullptr) {
65     m_threads->timer->cancel_event(m_timer_ctx);
66     update_status();
67   }
68 }
69
70 template <typename I>
71 int ServiceDaemon<I>::init() {
72   dout(20) << dendl;
73
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());
77   }
78
79   std::map<std::string, std::string> service_metadata = {
80       {"instance_id", stringify(m_rados->get_instance_id())}
81     };
82   int r = m_rados->service_daemon_register("rbd-mirror", name,
83                                            service_metadata);
84   if (r < 0) {
85     return r;
86   }
87
88   return 0;
89 }
90
91 template <typename I>
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;
94
95   {
96     Mutex::Locker locker(m_lock);
97     m_pools.insert({pool_id, {pool_name}});
98   }
99   schedule_update_status();
100 }
101
102 template <typename I>
103 void ServiceDaemon<I>::remove_pool(int64_t pool_id) {
104   dout(20) << "pool_id=" << pool_id << dendl;
105   {
106     Mutex::Locker locker(m_lock);
107     m_pools.erase(pool_id);
108   }
109   schedule_update_status();
110 }
111
112 template <typename I>
113 uint64_t ServiceDaemon<I>::add_or_update_callout(int64_t pool_id,
114                                                  uint64_t callout_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;
121
122   {
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;
127     }
128
129     if (callout_id == CALLOUT_ID_NONE) {
130       callout_id = ++m_callout_id;
131     }
132     pool_it->second.callouts[callout_id] = {callout_level, text};
133   }
134
135   schedule_update_status();
136   return callout_id;
137 }
138
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;
143
144   {
145     Mutex::Locker locker(m_lock);
146     auto pool_it = m_pools.find(pool_id);
147     if (pool_it == m_pools.end()) {
148       return;
149     }
150     pool_it->second.callouts.erase(callout_id);
151   }
152
153   schedule_update_status();
154 }
155
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;
163
164   {
165     Mutex::Locker locker(m_lock);
166     auto pool_it = m_pools.find(pool_id);
167     if (pool_it == m_pools.end()) {
168       return;
169     }
170     pool_it->second.attributes[key] = value;
171   }
172
173   schedule_update_status();
174 }
175
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;
181
182   {
183     Mutex::Locker locker(m_lock);
184     auto pool_it = m_pools.find(pool_id);
185     if (pool_it == m_pools.end()) {
186       return;
187     }
188     pool_it->second.attributes.erase(key);
189   }
190
191   schedule_update_status();
192 }
193
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) {
198     return;
199   }
200
201   m_timer_ctx = new FunctionContext([this](int) {
202       m_timer_ctx = nullptr;
203       update_status();
204     });
205   m_threads->timer->add_event_after(1, m_timer_ctx);
206 }
207
208 template <typename I>
209 void ServiceDaemon<I>::update_status() {
210   dout(20) << dendl;
211   assert(m_threads->timer_lock.is_locked());
212
213   ceph::JSONFormatter f;
214   {
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());
225         f.close_section();
226       }
227       f.close_section(); // callouts
228
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);
232       }
233       f.close_section(); // pool
234     }
235     f.close_section(); // pools
236   }
237
238   std::stringstream ss;
239   f.flush(ss);
240
241   int r = m_rados->service_daemon_update_status({{"json", ss.str()}});
242   if (r < 0) {
243     derr << "failed to update service daemon status: " << cpp_strerror(r)
244          << dendl;
245   }
246 }
247
248 } // namespace mirror
249 } // namespace rbd
250
251 template class rbd::mirror::ServiceDaemon<librbd::ImageCtx>;