Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_realm_watcher.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 "common/errno.h"
5
6 #include "rgw_realm_watcher.h"
7 #include "rgw_rados.h"
8
9 #define dout_subsys ceph_subsys_rgw
10
11 #undef dout_prefix
12 #define dout_prefix (*_dout << "rgw realm watcher: ")
13
14
15 RGWRealmWatcher::RGWRealmWatcher(CephContext* cct, RGWRealm& realm)
16   : cct(cct)
17 {
18   // no default realm, nothing to watch
19   if (realm.get_id().empty()) {
20     ldout(cct, 4) << "No realm, disabling dynamic reconfiguration." << dendl;
21     return;
22   }
23
24   // establish the watch on RGWRealm
25   int r = watch_start(realm);
26   if (r < 0) {
27     lderr(cct) << "Failed to establish a watch on RGWRealm, "
28         "disabling dynamic reconfiguration." << dendl;
29     return;
30   }
31 }
32
33 RGWRealmWatcher::~RGWRealmWatcher()
34 {
35   watch_stop();
36 }
37
38 void RGWRealmWatcher::add_watcher(RGWRealmNotify type, Watcher& watcher)
39 {
40   watchers.emplace(type, watcher);
41 }
42
43 void RGWRealmWatcher::handle_notify(uint64_t notify_id, uint64_t cookie,
44                                     uint64_t notifier_id, bufferlist& bl)
45 {
46   if (cookie != watch_handle)
47     return;
48
49   // send an empty notify ack
50   bufferlist reply;
51   pool_ctx.notify_ack(watch_oid, notify_id, cookie, reply);
52
53   try {
54     auto p = bl.begin();
55     while (!p.end()) {
56       RGWRealmNotify notify;
57       ::decode(notify, p);
58       auto watcher = watchers.find(notify);
59       if (watcher == watchers.end()) {
60         lderr(cct) << "Failed to find a watcher for notify type "
61             << static_cast<int>(notify) << dendl;
62         break;
63       }
64       watcher->second.handle_notify(notify, p);
65     }
66   } catch (const buffer::error &e) {
67     lderr(cct) << "Failed to decode realm notifications." << dendl;
68   }
69 }
70
71 void RGWRealmWatcher::handle_error(uint64_t cookie, int err)
72 {
73   if (cookie != watch_handle)
74     return;
75
76   if (err == -ENOTCONN) {
77     ldout(cct, 4) << "Disconnected watch on " << watch_oid << dendl;
78     watch_restart();
79   }
80 }
81
82 int RGWRealmWatcher::watch_start(RGWRealm& realm)
83 {
84   // initialize a Rados client
85   int r = rados.init_with_context(cct);
86   if (r < 0) {
87     lderr(cct) << "Rados client initialization failed with "
88         << cpp_strerror(-r) << dendl;
89     return r;
90   }
91   r = rados.connect();
92   if (r < 0) {
93     lderr(cct) << "Rados client connection failed with "
94         << cpp_strerror(-r) << dendl;
95     return r;
96   }
97
98   // open an IoCtx for the realm's pool
99   rgw_pool pool(realm.get_pool(cct));
100   r = rgw_init_ioctx(&rados, pool, pool_ctx);
101   if (r < 0) {
102     lderr(cct) << "Failed to open pool " << pool
103         << " with " << cpp_strerror(-r) << dendl;
104     rados.shutdown();
105     return r;
106   }
107
108   // register a watch on the realm's control object
109   auto oid = realm.get_control_oid();
110   r = pool_ctx.watch2(oid, &watch_handle, this);
111   if (r < 0) {
112     lderr(cct) << "Failed to watch " << oid
113         << " with " << cpp_strerror(-r) << dendl;
114     pool_ctx.close();
115     rados.shutdown();
116     return r;
117   }
118
119   ldout(cct, 10) << "Watching " << oid << dendl;
120   std::swap(watch_oid, oid);
121   return 0;
122 }
123
124 int RGWRealmWatcher::watch_restart()
125 {
126   assert(!watch_oid.empty());
127   int r = pool_ctx.unwatch2(watch_handle);
128   if (r < 0) {
129     lderr(cct) << "Failed to unwatch on " << watch_oid
130         << " with " << cpp_strerror(-r) << dendl;
131   }
132   r = pool_ctx.watch2(watch_oid, &watch_handle, this);
133   if (r < 0) {
134     lderr(cct) << "Failed to restart watch on " << watch_oid
135         << " with " << cpp_strerror(-r) << dendl;
136     pool_ctx.close();
137     watch_oid.clear();
138   }
139   return r;
140 }
141
142 void RGWRealmWatcher::watch_stop()
143 {
144   if (!watch_oid.empty()) {
145     pool_ctx.unwatch2(watch_handle);
146     pool_ctx.close();
147     watch_oid.clear();
148   }
149 }