1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "include/rados/librados.hpp"
4 #include "common/Cond.h"
5 #include "common/errno.h"
6 #include "common/ceph_mutex.h"
7 #include "librbd/internal.h"
8 #include "librbd/api/Mirror.h"
9 #include "tools/rbd_mirror/ClusterWatcher.h"
10 #include "tools/rbd_mirror/ServiceDaemon.h"
11 #include "tools/rbd_mirror/Types.h"
12 #include "test/rbd_mirror/test_fixture.h"
13 #include "test/librados/test_cxx.h"
14 #include "test/librbd/test_support.h"
15 #include "gtest/gtest.h"
16 #include <boost/scope_exit.hpp>
17 #include <iostream>
18 #include <map>
19 #include <memory>
20 #include <set>
21
22 using rbd::mirror::ClusterWatcher;
23 using rbd::mirror::PeerSpec;
24 using rbd::mirror::RadosRef;
25 using std::map;
26 using std::set;
27 using std::string;
28
29 void register_test_cluster_watcher() {
30 }
31
32 class TestClusterWatcher : public ::rbd::mirror::TestFixture {
33 public:
34
35 TestClusterWatcher() {
36 m_cluster = std::make_shared<librados::Rados>();
37 EXPECT_EQ("", connect_cluster_pp(*m_cluster));
38 }
39
40 ~TestClusterWatcher() override {
41 m_cluster->wait_for_latest_osdmap();
42 for (auto& pool : m_pools) {
43 EXPECT_EQ(0, m_cluster->pool_delete(pool.c_str()));
44 }
45 }
46
47 void SetUp() override {
48 TestFixture::SetUp();
49 m_service_daemon.reset(new rbd::mirror::ServiceDaemon<>(g_ceph_context,
50 m_cluster,
51 m_threads));
52 m_cluster_watcher.reset(new ClusterWatcher(m_cluster, m_lock,
53 m_service_daemon.get()));
54 }
55
56 void TearDown() override {
57 m_service_daemon.reset();
58 m_cluster_watcher.reset();
59 TestFixture::TearDown();
60 }
61
62 void create_pool(bool enable_mirroring, const PeerSpec &peer,
63 string *uuid = nullptr, string *name=nullptr) {
64 string pool_name = get_temp_pool_name("test-rbd-mirror-");
65 ASSERT_EQ(0, m_cluster->pool_create(pool_name.c_str()));
66
67 int64_t pool_id = m_cluster->pool_lookup(pool_name.c_str());
68 ASSERT_GE(pool_id, 0);
69
70 librados::IoCtx ioctx;
71 ASSERT_EQ(0, m_cluster->ioctx_create2(pool_id, ioctx));
72 ioctx.application_enable("rbd", true);
73
74 m_pools.insert(pool_name);
75 if (enable_mirroring) {
76 ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(ioctx,
77 RBD_MIRROR_MODE_POOL));
78
79 std::string gen_uuid;
80 ASSERT_EQ(0, librbd::api::Mirror<>::peer_add(ioctx,
81 uuid != nullptr ? uuid :
82 &gen_uuid,
83 peer.cluster_name,
84 peer.client_name));
85 m_pool_peers[pool_id].insert(peer);
86 }
87 if (name != nullptr) {
88 *name = pool_name;
89 }
90 }
91
92 void delete_pool(const string &name, const PeerSpec &peer) {
93 int64_t pool_id = m_cluster->pool_lookup(name.c_str());
94 ASSERT_GE(pool_id, 0);
95 if (m_pool_peers.find(pool_id) != m_pool_peers.end()) {
96 m_pool_peers[pool_id].erase(peer);
97 if (m_pool_peers[pool_id].empty()) {
98 m_pool_peers.erase(pool_id);
99 }
100 }
101 m_pools.erase(name);
102 ASSERT_EQ(0, m_cluster->pool_delete(name.c_str()));
103 }
104
105 void set_peer_config_key(const std::string& pool_name,
106 const PeerSpec &peer) {
107 int64_t pool_id = m_cluster->pool_lookup(pool_name.c_str());
108 ASSERT_GE(pool_id, 0);
109
110 std::string json =
111 "{"
112 "\\\"mon_host\\\": \\\"" + peer.mon_host + "\\\", "
113 "\\\"key\\\": \\\"" + peer.key + "\\\""
114 "}";
115
116 bufferlist in_bl;
117 ASSERT_EQ(0, m_cluster->mon_command(
118 "{"
119 "\"prefix\": \"config-key set\","
120 "\"key\": \"" RBD_MIRROR_PEER_CONFIG_KEY_PREFIX + stringify(pool_id) +
121 "/" + peer.uuid + "\","
122 "\"val\": \"" + json + "\"" +
123 "}", in_bl, nullptr, nullptr));
124 }
125
126 void create_cache_pool(const string &base_pool, string *cache_pool_name) {
127 bufferlist inbl;
128 *cache_pool_name = get_temp_pool_name("test-rbd-mirror-");
129 ASSERT_EQ(0, m_cluster->pool_create(cache_pool_name->c_str()));
130
131 ASSERT_EQ(0, m_cluster->mon_command(
132 "{\"prefix\": \"osd tier add\", \"pool\": \"" + base_pool +
133 "\", \"tierpool\": \"" + *cache_pool_name +
134 "\", \"force_nonempty\": \"--force-nonempty\" }",
135 inbl, NULL, NULL));
136 ASSERT_EQ(0, m_cluster->mon_command(
137 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + base_pool +
138 "\", \"overlaypool\": \"" + *cache_pool_name + "\"}",
139 inbl, NULL, NULL));
140 ASSERT_EQ(0, m_cluster->mon_command(
141 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + *cache_pool_name +
142 "\", \"mode\": \"writeback\"}",
143 inbl, NULL, NULL));
144 m_cluster->wait_for_latest_osdmap();
145 }
146
147 void remove_cache_pool(const string &base_pool, const string &cache_pool) {
(1) Event fun_call_w_exception: |
Called function throws an exception of type "ceph::buffer::v14_2_0::end_of_buffer". [details] |
148 bufferlist inbl;
149 // tear down tiers
150 ASSERT_EQ(0, m_cluster->mon_command(
151 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + base_pool +
152 "\"}",
153 inbl, NULL, NULL));
154 ASSERT_EQ(0, m_cluster->mon_command(
155 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + base_pool +
156 "\", \"tierpool\": \"" + cache_pool + "\"}",
157 inbl, NULL, NULL));
158 m_cluster->wait_for_latest_osdmap();
159 m_cluster->pool_delete(cache_pool.c_str());
160 }
161
162 void check_peers() {
163 m_cluster_watcher->refresh_pools();
164 std::lock_guard l{m_lock};
165 ASSERT_EQ(m_pool_peers, m_cluster_watcher->get_pool_peers());
166 }
167
168 RadosRef m_cluster;
169 ceph::mutex m_lock = ceph::make_mutex("TestClusterWatcherLock");
170 unique_ptr<rbd::mirror::ServiceDaemon<>> m_service_daemon;
171 unique_ptr<ClusterWatcher> m_cluster_watcher;
172
173 set<string> m_pools;
174 ClusterWatcher::PoolPeers m_pool_peers;
175 };
176
177 TEST_F(TestClusterWatcher, NoPools) {
178 check_peers();
179 }
180
181 TEST_F(TestClusterWatcher, NoMirroredPools) {
182 check_peers();
183 create_pool(false, PeerSpec());
184 check_peers();
185 create_pool(false, PeerSpec());
186 check_peers();
187 create_pool(false, PeerSpec());
188 check_peers();
189 }
190
191 TEST_F(TestClusterWatcher, ReplicatedPools) {
192 PeerSpec site1("", "site1", "mirror1");
193 PeerSpec site2("", "site2", "mirror2");
194 string first_pool, last_pool;
195 check_peers();
196 create_pool(true, site1, &site1.uuid, &first_pool);
197 check_peers();
198 create_pool(false, PeerSpec());
199 check_peers();
200 create_pool(false, PeerSpec());
201 check_peers();
202 create_pool(false, PeerSpec());
203 check_peers();
204 create_pool(true, site2, &site2.uuid);
205 check_peers();
206 create_pool(true, site2, &site2.uuid);
207 check_peers();
208 create_pool(true, site2, &site2.uuid, &last_pool);
209 check_peers();
210 delete_pool(first_pool, site1);
211 check_peers();
212 delete_pool(last_pool, site2);
213 check_peers();
214 }
215
216 TEST_F(TestClusterWatcher, CachePools) {
217 PeerSpec site1("", "site1", "mirror1");
218 string base1, base2, cache1, cache2;
219 create_pool(true, site1, &site1.uuid, &base1);
220 check_peers();
221
222 create_cache_pool(base1, &cache1);
(1) Event exn_spec_violation: |
An exception of type "ceph::buffer::v14_2_0::end_of_buffer" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate(). |
(2) Event fun_call_w_exception: |
Called function throws an exception of type "ceph::buffer::v14_2_0::end_of_buffer". [details] |
223 BOOST_SCOPE_EXIT( base1, cache1, this_ ) {
(1) Event fun_call_w_exception: |
Called function throws an exception of type "ceph::buffer::v14_2_0::end_of_buffer". [details] |
224 this_->remove_cache_pool(base1, cache1);
225 } BOOST_SCOPE_EXIT_END;
226 check_peers();
227
228 create_pool(false, PeerSpec(), nullptr, &base2);
229 create_cache_pool(base2, &cache2);
230 BOOST_SCOPE_EXIT( base2, cache2, this_ ) {
231 this_->remove_cache_pool(base2, cache2);
232 } BOOST_SCOPE_EXIT_END;
233 check_peers();
234 }
235
236 TEST_F(TestClusterWatcher, ConfigKey) {
237 REQUIRE(!is_librados_test_stub(*m_cluster));
238
239 std::string pool_name;
240 check_peers();
241
242 PeerSpec site1("", "site1", "mirror1");
243 create_pool(true, site1, &site1.uuid, &pool_name);
244 check_peers();
245
246 PeerSpec site2("", "site2", "mirror2");
247 site2.mon_host = "abc";
248 site2.key = "xyz";
249 create_pool(false, site2, &site2.uuid);
250 set_peer_config_key(pool_name, site2);
251
252 check_peers();
253 }
254