1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "ClusterWatcher.h"
5 #include "include/stringify.h"
6 #include "common/ceph_json.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "librbd/internal.h"
11 #include "librbd/api/Mirror.h"
12 #include "tools/rbd_mirror/ServiceDaemon.h"
13 #include "json_spirit/json_spirit.h"
15 #define dout_context g_ceph_context
16 #define dout_subsys ceph_subsys_rbd_mirror
18 #define dout_prefix *_dout << "rbd::mirror::ClusterWatcher:" << this << " " \
26 using std::unique_ptr
;
29 using librados::Rados
;
30 using librados::IoCtx
;
35 ClusterWatcher::ClusterWatcher(RadosRef cluster
, ceph::mutex
&lock
,
36 ServiceDaemon
<librbd::ImageCtx
>* service_daemon
)
37 : m_cluster(cluster
), m_lock(lock
), m_service_daemon(service_daemon
)
41 const ClusterWatcher::PoolPeers
& ClusterWatcher::get_pool_peers() const
43 ceph_assert(ceph_mutex_is_locked(m_lock
));
47 std::string
ClusterWatcher::get_site_name() const {
48 ceph_assert(ceph_mutex_is_locked(m_lock
));
52 void ClusterWatcher::refresh_pools()
54 dout(20) << "enter" << dendl
;
57 read_pool_peers(&pool_peers
);
59 std::string site_name
;
60 int r
= read_site_name(&site_name
);
62 std::lock_guard l
{m_lock
};
63 m_pool_peers
= pool_peers
;
66 m_site_name
= site_name
;
69 // TODO: perhaps use a workqueue instead, once we get notifications
70 // about config changes for existing pools
73 void ClusterWatcher::read_pool_peers(PoolPeers
*pool_peers
)
75 int r
= m_cluster
->wait_for_latest_osdmap();
77 derr
<< "error waiting for OSD map: " << cpp_strerror(r
) << dendl
;
81 list
<pair
<int64_t, string
> > pools
;
82 r
= m_cluster
->pool_list2(pools
);
84 derr
<< "error listing pools: " << cpp_strerror(r
) << dendl
;
88 std::set
<int64_t> service_pool_ids
;
89 for (auto& kv
: pools
) {
90 int64_t pool_id
= kv
.first
;
91 auto& pool_name
= kv
.second
;
93 r
= m_cluster
->pool_get_base_tier(pool_id
, &base_tier
);
95 dout(10) << "pool " << pool_name
<< " no longer exists" << dendl
;
98 derr
<< "Error retrieving base tier for pool " << pool_name
<< dendl
;
101 if (pool_id
!= base_tier
) {
102 // pool is a cache; skip it
107 r
= m_cluster
->ioctx_create2(pool_id
, ioctx
);
109 dout(10) << "pool " << pool_id
<< " no longer exists" << dendl
;
112 derr
<< "Error accessing pool " << pool_name
<< cpp_strerror(r
) << dendl
;
116 cls::rbd::MirrorMode mirror_mode_internal
;
117 r
= librbd::cls_client::mirror_mode_get(&ioctx
, &mirror_mode_internal
);
118 if (r
== 0 && mirror_mode_internal
== cls::rbd::MIRROR_MODE_DISABLED
) {
119 dout(10) << "mirroring is disabled for pool " << pool_name
<< dendl
;
123 service_pool_ids
.insert(pool_id
);
124 if (m_service_pools
.find(pool_id
) == m_service_pools
.end()) {
125 m_service_pools
[pool_id
] = {};
126 m_service_daemon
->add_pool(pool_id
, pool_name
);
130 dout(10) << "access denied querying pool " << pool_name
<< dendl
;
131 m_service_pools
[pool_id
] = m_service_daemon
->add_or_update_callout(
132 pool_id
, m_service_pools
[pool_id
],
133 service_daemon::CALLOUT_LEVEL_WARNING
, "access denied");
136 derr
<< "could not tell whether mirroring was enabled for " << pool_name
137 << " : " << cpp_strerror(r
) << dendl
;
138 m_service_pools
[pool_id
] = m_service_daemon
->add_or_update_callout(
139 pool_id
, m_service_pools
[pool_id
],
140 service_daemon::CALLOUT_LEVEL_WARNING
, "mirroring mode query failed");
144 vector
<librbd::mirror_peer_site_t
> configs
;
145 r
= librbd::api::Mirror
<>::peer_site_list(ioctx
, &configs
);
147 derr
<< "error reading mirroring config for pool " << pool_name
148 << cpp_strerror(r
) << dendl
;
149 m_service_pools
[pool_id
] = m_service_daemon
->add_or_update_callout(
150 pool_id
, m_service_pools
[pool_id
],
151 service_daemon::CALLOUT_LEVEL_ERROR
, "mirroring peer list failed");
155 std::vector
<PeerSpec
> peers
;
156 peers
.reserve(configs
.size());
157 for (auto& peer
: configs
) {
158 if (peer
.direction
!= RBD_MIRROR_PEER_DIRECTION_TX
) {
159 peers
.push_back(peer
);
163 for (auto& peer
: peers
) {
164 r
= resolve_peer_site_config_keys(pool_id
, pool_name
, &peer
);
170 if (m_service_pools
[pool_id
] != service_daemon::CALLOUT_ID_NONE
) {
171 m_service_daemon
->remove_callout(pool_id
, m_service_pools
[pool_id
]);
172 m_service_pools
[pool_id
] = service_daemon::CALLOUT_ID_NONE
;
175 pool_peers
->emplace(pool_id
, Peers
{peers
.begin(), peers
.end()});
178 for (auto it
= m_service_pools
.begin(); it
!= m_service_pools
.end(); ) {
179 auto current_it(it
++);
180 if (service_pool_ids
.find(current_it
->first
) == service_pool_ids
.end()) {
181 m_service_daemon
->remove_pool(current_it
->first
);
182 m_service_pools
.erase(current_it
->first
);
187 int ClusterWatcher::read_site_name(std::string
* site_name
) {
191 return rbd
.mirror_site_name_get(*m_cluster
, site_name
);
194 int ClusterWatcher::resolve_peer_site_config_keys(int64_t pool_id
,
195 const std::string
& pool_name
,
197 dout(10) << "retrieving config-key: pool_id=" << pool_id
<< ", "
198 << "pool_name=" << pool_name
<< ", "
199 << "peer_uuid=" << peer
->uuid
<< dendl
;
203 "\"prefix\": \"config-key get\", "
204 "\"key\": \"" RBD_MIRROR_PEER_CONFIG_KEY_PREFIX
+ stringify(pool_id
) +
205 "/" + peer
->uuid
+ "\""
210 int r
= m_cluster
->mon_command(cmd
, in_bl
, &out_bl
, nullptr);
211 if (r
== -ENOENT
|| out_bl
.length() == 0) {
214 derr
<< "error reading mirroring peer config for pool " << pool_name
<< ": "
215 << cpp_strerror(r
) << dendl
;
216 m_service_pools
[pool_id
] = m_service_daemon
->add_or_update_callout(
217 pool_id
, m_service_pools
[pool_id
],
218 service_daemon::CALLOUT_LEVEL_WARNING
,
219 "mirroring peer config-key query failed");
223 bool json_valid
= false;
224 json_spirit::mValue json_root
;
225 if(json_spirit::read(out_bl
.to_str(), json_root
)) {
227 auto& json_obj
= json_root
.get_obj();
228 if (json_obj
.count("mon_host")) {
229 peer
->mon_host
= json_obj
["mon_host"].get_str();
231 if (json_obj
.count("key")) {
232 peer
->key
= json_obj
["key"].get_str();
235 } catch (std::runtime_error
&) {
240 derr
<< "error parsing mirroring peer config for pool " << pool_name
<< ", "
241 << "peer " << peer
->uuid
<< dendl
;
242 m_service_pools
[pool_id
] = m_service_daemon
->add_or_update_callout(
243 pool_id
, m_service_pools
[pool_id
],
244 service_daemon::CALLOUT_LEVEL_WARNING
,
245 "mirroring peer config-key decode failed");
251 } // namespace mirror