]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / rbd_mirror / image_replayer / test_mock_BootstrapRequest.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 "test/rbd_mirror/test_mock_fixture.h"
5 #include "librbd/journal/TypeTraits.h"
6 #include "tools/rbd_mirror/InstanceWatcher.h"
7 #include "tools/rbd_mirror/Threads.h"
8 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
9 #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
10 #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h"
11 #include "tools/rbd_mirror/image_replayer/IsPrimaryRequest.h"
12 #include "tools/rbd_mirror/image_replayer/OpenImageRequest.h"
13 #include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h"
14 #include "test/journal/mock/MockJournaler.h"
15 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
16 #include "test/librbd/mock/MockImageCtx.h"
17 #include "test/librbd/mock/MockJournal.h"
18
19 namespace librbd {
20
21 namespace {
22
23 struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
26 }
27 };
28
29 } // anonymous namespace
30
31 namespace journal {
32
33 template <>
34 struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
36 };
37
38 } // namespace journal
39 } // namespace librbd
40
41 namespace rbd {
42 namespace mirror {
43
44 class ProgressContext;
45
46 template<>
47 struct ImageSync<librbd::MockTestImageCtx> {
48 static ImageSync* s_instance;
49 Context *on_finish = nullptr;
50
51 static ImageSync* create(
52 librbd::MockTestImageCtx *local_image_ctx,
53 librbd::MockTestImageCtx *remote_image_ctx,
54 SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid,
55 ::journal::MockJournaler *journaler,
56 librbd::journal::MirrorPeerClientMeta *client_meta, ContextWQ *work_queue,
57 InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
58 Context *on_finish, ProgressContext *progress_ctx) {
59 assert(s_instance != nullptr);
60 s_instance->on_finish = on_finish;
61 return s_instance;
62 }
63
64 ImageSync() {
65 assert(s_instance == nullptr);
66 s_instance = this;
67 }
68 ~ImageSync() {
69 s_instance = nullptr;
70 }
71
72 MOCK_METHOD0(get, void());
73 MOCK_METHOD0(put, void());
74 MOCK_METHOD0(send, void());
75 MOCK_METHOD0(cancel, void());
76 };
77
78 ImageSync<librbd::MockTestImageCtx>*
79 ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr;
80
81 template<>
82 struct InstanceWatcher<librbd::MockTestImageCtx> {
83 };
84
85 namespace image_replayer {
86
87 template<>
88 struct CloseImageRequest<librbd::MockTestImageCtx> {
89 static CloseImageRequest* s_instance;
90 librbd::MockTestImageCtx **image_ctx = nullptr;
91 Context *on_finish = nullptr;
92
93 static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
94 Context *on_finish) {
95 assert(s_instance != nullptr);
96 s_instance->image_ctx = image_ctx;
97 s_instance->on_finish = on_finish;
98 s_instance->construct(*image_ctx);
99 return s_instance;
100 }
101
102 CloseImageRequest() {
103 assert(s_instance == nullptr);
104 s_instance = this;
105 }
106 ~CloseImageRequest() {
107 s_instance = nullptr;
108 }
109
110 MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx));
111 MOCK_METHOD0(send, void());
112 };
113
114 template<>
115 struct CreateImageRequest<librbd::MockTestImageCtx> {
116 static CreateImageRequest* s_instance;
117 std::string *local_image_id = nullptr;
118 Context *on_finish = nullptr;
119
120 static CreateImageRequest* create(librados::IoCtx &local_io_ctx,
121 ContextWQ *work_queue,
122 const std::string &global_image_id,
123 const std::string &remote_mirror_uuid,
124 const std::string &local_image_name,
125 librbd::MockTestImageCtx *remote_image_ctx,
126 std::string *local_image_id,
127 Context *on_finish) {
128 assert(s_instance != nullptr);
129 s_instance->local_image_id = local_image_id;
130 s_instance->on_finish = on_finish;
131 return s_instance;
132 }
133
134 CreateImageRequest() {
135 assert(s_instance == nullptr);
136 s_instance = this;
137 }
138 ~CreateImageRequest() {
139 s_instance = nullptr;
140 }
141
142 MOCK_METHOD0(send, void());
143 };
144
145 template<>
146 struct IsPrimaryRequest<librbd::MockTestImageCtx> {
147 static IsPrimaryRequest* s_instance;
148 bool *primary = nullptr;
149 Context *on_finish = nullptr;
150
151 static IsPrimaryRequest* create(librbd::MockTestImageCtx *image_ctx,
152 bool *primary, Context *on_finish) {
153 assert(s_instance != nullptr);
154 s_instance->primary = primary;
155 s_instance->on_finish = on_finish;
156 return s_instance;
157 }
158
159 IsPrimaryRequest() {
160 assert(s_instance == nullptr);
161 s_instance = this;
162 }
163 ~IsPrimaryRequest() {
164 s_instance = nullptr;
165 }
166
167 MOCK_METHOD0(send, void());
168 };
169
170 template<>
171 struct OpenImageRequest<librbd::MockTestImageCtx> {
172 static OpenImageRequest* s_instance;
173 librbd::MockTestImageCtx **image_ctx = nullptr;
174 Context *on_finish = nullptr;
175
176 static OpenImageRequest* create(librados::IoCtx &io_ctx,
177 librbd::MockTestImageCtx **image_ctx,
178 const std::string &image_id,
179 bool read_only, Context *on_finish) {
180 assert(s_instance != nullptr);
181 s_instance->image_ctx = image_ctx;
182 s_instance->on_finish = on_finish;
183 s_instance->construct(io_ctx, image_id);
184 return s_instance;
185 }
186
187 OpenImageRequest() {
188 assert(s_instance == nullptr);
189 s_instance = this;
190 }
191 ~OpenImageRequest() {
192 s_instance = nullptr;
193 }
194
195 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
196 const std::string &image_id));
197 MOCK_METHOD0(send, void());
198 };
199
200 template<>
201 struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
202 static OpenLocalImageRequest* s_instance;
203 librbd::MockTestImageCtx **image_ctx = nullptr;
204 Context *on_finish = nullptr;
205
206 static OpenLocalImageRequest* create(librados::IoCtx &local_io_ctx,
207 librbd::MockTestImageCtx **local_image_ctx,
208 const std::string &local_image_id,
209 ContextWQ *work_queue,
210 Context *on_finish) {
211 assert(s_instance != nullptr);
212 s_instance->image_ctx = local_image_ctx;
213 s_instance->on_finish = on_finish;
214 s_instance->construct(local_io_ctx, local_image_id);
215 return s_instance;
216 }
217
218 OpenLocalImageRequest() {
219 assert(s_instance == nullptr);
220 s_instance = this;
221 }
222 ~OpenLocalImageRequest() {
223 s_instance = nullptr;
224 }
225
226 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
227 const std::string &image_id));
228 MOCK_METHOD0(send, void());
229 };
230
231 CloseImageRequest<librbd::MockTestImageCtx>*
232 CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
233 CreateImageRequest<librbd::MockTestImageCtx>*
234 CreateImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
235 IsPrimaryRequest<librbd::MockTestImageCtx>*
236 IsPrimaryRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
237 OpenImageRequest<librbd::MockTestImageCtx>*
238 OpenImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
239 OpenLocalImageRequest<librbd::MockTestImageCtx>*
240 OpenLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
241
242 } // namespace image_replayer
243 } // namespace mirror
244 } // namespace rbd
245
246 // template definitions
247 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
248 template class rbd::mirror::image_replayer::BootstrapRequest<librbd::MockTestImageCtx>;
249
250 namespace rbd {
251 namespace mirror {
252 namespace image_replayer {
253
254 using ::testing::_;
255 using ::testing::DoAll;
256 using ::testing::InSequence;
257 using ::testing::Invoke;
258 using ::testing::Return;
259 using ::testing::SetArgPointee;
260 using ::testing::StrEq;
261 using ::testing::WithArg;
262
263 MATCHER_P(IsSameIoCtx, io_ctx, "") {
264 return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
265 }
266
267 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
268 public:
269 typedef BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
270 typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
271 typedef CreateImageRequest<librbd::MockTestImageCtx> MockCreateImageRequest;
272 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
273 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
274 typedef IsPrimaryRequest<librbd::MockTestImageCtx> MockIsPrimaryRequest;
275 typedef OpenImageRequest<librbd::MockTestImageCtx> MockOpenImageRequest;
276 typedef OpenLocalImageRequest<librbd::MockTestImageCtx> MockOpenLocalImageRequest;
277 typedef std::list<cls::journal::Tag> Tags;
278
279 void SetUp() override {
280 TestMockFixture::SetUp();
281
282 librbd::RBD rbd;
283 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
284 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
285 }
286
287 void create_local_image() {
288 librbd::RBD rbd;
289 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
290 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
291 }
292
293 void expect_journaler_get_client(::journal::MockJournaler &mock_journaler,
294 const std::string &client_id,
295 cls::journal::Client &client, int r) {
296 EXPECT_CALL(mock_journaler, get_client(StrEq(client_id), _, _))
297 .WillOnce(DoAll(WithArg<1>(Invoke([client](cls::journal::Client *out_client) {
298 *out_client = client;
299 })),
300 WithArg<2>(Invoke([this, r](Context *on_finish) {
301 m_threads->work_queue->queue(on_finish, r);
302 }))));
303 }
304
305 void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
306 uint64_t tag_class, const Tags& tags,
307 int r) {
308 EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
309 .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
310 *out_tags = tags;
311 })),
312 WithArg<2>(Invoke([this, r](Context *on_finish) {
313 m_threads->work_queue->queue(on_finish, r);
314 }))));
315 }
316
317 void expect_journaler_register_client(::journal::MockJournaler &mock_journaler,
318 const librbd::journal::ClientData &client_data,
319 int r) {
320 bufferlist bl;
321 ::encode(client_data, bl);
322
323 EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _))
324 .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
325 m_threads->work_queue->queue(on_finish, r);
326 })));
327 }
328
329 void expect_journaler_update_client(::journal::MockJournaler &mock_journaler,
330 const librbd::journal::ClientData &client_data,
331 int r) {
332 bufferlist bl;
333 ::encode(client_data, bl);
334
335 EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _))
336 .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
337 m_threads->work_queue->queue(on_finish, r);
338 })));
339 }
340
341 void expect_open_image(MockOpenImageRequest &mock_open_image_request,
342 librados::IoCtx &io_ctx, const std::string &image_id,
343 librbd::MockTestImageCtx &mock_image_ctx, int r) {
344 EXPECT_CALL(mock_open_image_request, construct(IsSameIoCtx(&io_ctx), image_id));
345 EXPECT_CALL(mock_open_image_request, send())
346 .WillOnce(Invoke([this, &mock_open_image_request, &mock_image_ctx, r]() {
347 *mock_open_image_request.image_ctx = &mock_image_ctx;
348 m_threads->work_queue->queue(mock_open_image_request.on_finish, r);
349 }));
350 }
351
352 void expect_open_local_image(MockOpenLocalImageRequest &mock_open_local_image_request,
353 librados::IoCtx &io_ctx, const std::string &image_id,
354 librbd::MockTestImageCtx *mock_image_ctx, int r) {
355 EXPECT_CALL(mock_open_local_image_request,
356 construct(IsSameIoCtx(&io_ctx), image_id));
357 EXPECT_CALL(mock_open_local_image_request, send())
358 .WillOnce(Invoke([this, &mock_open_local_image_request, mock_image_ctx, r]() {
359 *mock_open_local_image_request.image_ctx = mock_image_ctx;
360 m_threads->work_queue->queue(mock_open_local_image_request.on_finish,
361 r);
362 }));
363 }
364
365 void expect_close_image(MockCloseImageRequest &mock_close_image_request,
366 librbd::MockTestImageCtx &mock_image_ctx, int r) {
367 EXPECT_CALL(mock_close_image_request, construct(&mock_image_ctx));
368 EXPECT_CALL(mock_close_image_request, send())
369 .WillOnce(Invoke([this, &mock_close_image_request, r]() {
370 *mock_close_image_request.image_ctx = nullptr;
371 m_threads->work_queue->queue(mock_close_image_request.on_finish, r);
372 }));
373 }
374
375 void expect_is_primary(MockIsPrimaryRequest &mock_is_primary_request,
376 bool primary, int r) {
377 EXPECT_CALL(mock_is_primary_request, send())
378 .WillOnce(Invoke([this, &mock_is_primary_request, primary, r]() {
379 *mock_is_primary_request.primary = primary;
380 m_threads->work_queue->queue(mock_is_primary_request.on_finish, r);
381 }));
382 }
383
384 void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
385 uint64_t tag_tid) {
386 EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
387 }
388
389 void expect_journal_get_tag_data(librbd::MockJournal &mock_journal,
390 const librbd::journal::TagData &tag_data) {
391 EXPECT_CALL(mock_journal, get_tag_data()).WillOnce(Return(tag_data));
392 }
393
394 void expect_is_resync_requested(librbd::MockJournal &mock_journal,
395 bool do_resync, int r) {
396 EXPECT_CALL(mock_journal, is_resync_requested(_))
397 .WillOnce(DoAll(SetArgPointee<0>(do_resync),
398 Return(r)));
399 }
400
401 void expect_create_image(MockCreateImageRequest &mock_create_image_request,
402 const std::string &image_id, int r) {
403 EXPECT_CALL(mock_create_image_request, send())
404 .WillOnce(Invoke([this, &mock_create_image_request, image_id, r]() {
405 *mock_create_image_request.local_image_id = image_id;
406 m_threads->work_queue->queue(mock_create_image_request.on_finish, r);
407 }));
408 }
409
410 void expect_image_sync(MockImageSync &mock_image_sync, int r) {
411 EXPECT_CALL(mock_image_sync, get());
412 EXPECT_CALL(mock_image_sync, send())
413 .WillOnce(Invoke([this, &mock_image_sync, r]() {
414 m_threads->work_queue->queue(mock_image_sync.on_finish, r);
415 }));
416 EXPECT_CALL(mock_image_sync, put());
417 }
418
419 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
420 bufferlist bl;
421 ::encode(tag_data, bl);
422 return bl;
423 }
424
425 MockBootstrapRequest *create_request(MockInstanceWatcher *mock_instance_watcher,
426 ::journal::MockJournaler &mock_journaler,
427 const std::string &local_image_id,
428 const std::string &remote_image_id,
429 const std::string &global_image_id,
430 const std::string &local_mirror_uuid,
431 const std::string &remote_mirror_uuid,
432 Context *on_finish) {
433 return new MockBootstrapRequest(m_local_io_ctx,
434 m_remote_io_ctx,
435 mock_instance_watcher,
436 &m_local_test_image_ctx,
437 local_image_id,
438 remote_image_id,
439 global_image_id,
440 m_threads->work_queue,
441 m_threads->timer,
442 &m_threads->timer_lock,
443 local_mirror_uuid,
444 remote_mirror_uuid,
445 &mock_journaler,
446 &m_mirror_peer_client_meta,
447 on_finish, &m_do_resync);
448 }
449
450 librbd::ImageCtx *m_remote_image_ctx;
451 librbd::ImageCtx *m_local_image_ctx = nullptr;
452 librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
453 librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta;
454 bool m_do_resync;
455 };
456
457 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
458 create_local_image();
459
460 InSequence seq;
461
462 // lookup remote image tag class
463 cls::journal::Client client;
464 librbd::journal::ClientData client_data{
465 librbd::journal::ImageClientMeta{123}};
466 ::encode(client_data, client.data);
467 ::journal::MockJournaler mock_journaler;
468 expect_journaler_get_client(mock_journaler,
469 librbd::Journal<>::IMAGE_CLIENT_ID,
470 client, 0);
471
472 // lookup local peer in remote journal
473 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
474 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
475 mock_local_image_ctx.id};
476 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
477 client_data.client_meta = mirror_peer_client_meta;
478 client.data.clear();
479 ::encode(client_data, client.data);
480 expect_journaler_get_client(mock_journaler, "local mirror uuid",
481 client, 0);
482
483 // open the remote image
484 librbd::MockJournal mock_journal;
485 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
486 MockOpenImageRequest mock_open_image_request;
487 expect_open_image(mock_open_image_request, m_remote_io_ctx,
488 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
489 MockIsPrimaryRequest mock_is_primary_request;
490 expect_is_primary(mock_is_primary_request, false, 0);
491
492 // switch the state to replaying
493 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
494 client_data.client_meta = mirror_peer_client_meta;
495 expect_journaler_update_client(mock_journaler, client_data, 0);
496
497 MockCloseImageRequest mock_close_image_request;
498 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
499
500 C_SaferCond ctx;
501 MockInstanceWatcher mock_instance_watcher;
502 MockBootstrapRequest *request = create_request(
503 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
504 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
505 "remote mirror uuid", &ctx);
506 request->send();
507 ASSERT_EQ(-EREMOTEIO, ctx.wait());
508 }
509
510 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
511 create_local_image();
512
513 InSequence seq;
514
515 // lookup remote image tag class
516 cls::journal::Client client;
517 librbd::journal::ClientData client_data{
518 librbd::journal::ImageClientMeta{123}};
519 ::encode(client_data, client.data);
520 ::journal::MockJournaler mock_journaler;
521 expect_journaler_get_client(mock_journaler,
522 librbd::Journal<>::IMAGE_CLIENT_ID,
523 client, 0);
524
525 // lookup local peer in remote journal
526 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
527 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
528 mock_local_image_ctx.id};
529 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
530 client_data.client_meta = mirror_peer_client_meta;
531 client.data.clear();
532 ::encode(client_data, client.data);
533 expect_journaler_get_client(mock_journaler, "local mirror uuid",
534 client, 0);
535
536 // open the remote image
537 librbd::MockJournal mock_journal;
538 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
539 MockOpenImageRequest mock_open_image_request;
540 expect_open_image(mock_open_image_request, m_remote_io_ctx,
541 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
542 MockIsPrimaryRequest mock_is_primary_request;
543 expect_is_primary(mock_is_primary_request, true, 0);
544
545 // open the local image
546 mock_local_image_ctx.journal = &mock_journal;
547 MockOpenLocalImageRequest mock_open_local_image_request;
548 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
549 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
550 expect_is_resync_requested(mock_journal, false, 0);
551
552 // remote demotion / promotion event
553 Tags tags = {
554 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
555 librbd::Journal<>::LOCAL_MIRROR_UUID,
556 true, 1, 99})},
557 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
558 librbd::Journal<>::LOCAL_MIRROR_UUID,
559 true, 2, 1})},
560 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
561 librbd::Journal<>::ORPHAN_MIRROR_UUID,
562 true, 2, 1})},
563 {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
564 librbd::Journal<>::ORPHAN_MIRROR_UUID,
565 true, 4, 369})}
566 };
567 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
568 expect_journal_get_tag_tid(mock_journal, 345);
569 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
570
571 MockCloseImageRequest mock_close_image_request;
572 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
573
574 C_SaferCond ctx;
575 MockInstanceWatcher mock_instance_watcher;
576 MockBootstrapRequest *request = create_request(
577 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
578 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
579 "remote mirror uuid", &ctx);
580 request->send();
581 ASSERT_EQ(0, ctx.wait());
582 }
583
584 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
585 create_local_image();
586
587 InSequence seq;
588
589 // lookup remote image tag class
590 cls::journal::Client client;
591 librbd::journal::ClientData client_data{
592 librbd::journal::ImageClientMeta{123}};
593 ::encode(client_data, client.data);
594 ::journal::MockJournaler mock_journaler;
595 expect_journaler_get_client(mock_journaler,
596 librbd::Journal<>::IMAGE_CLIENT_ID,
597 client, 0);
598
599 // lookup local peer in remote journal
600 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
601 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
602 mock_local_image_ctx.id};
603 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
604 client_data.client_meta = mirror_peer_client_meta;
605 client.data.clear();
606 ::encode(client_data, client.data);
607 expect_journaler_get_client(mock_journaler, "local mirror uuid",
608 client, 0);
609
610 // open the remote image
611 librbd::MockJournal mock_journal;
612 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
613 MockOpenImageRequest mock_open_image_request;
614 expect_open_image(mock_open_image_request, m_remote_io_ctx,
615 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
616 MockIsPrimaryRequest mock_is_primary_request;
617 expect_is_primary(mock_is_primary_request, true, 0);
618
619 // open the local image
620 mock_local_image_ctx.journal = &mock_journal;
621 MockOpenLocalImageRequest mock_open_local_image_request;
622 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
623 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
624 expect_is_resync_requested(mock_journal, false, 0);
625
626 // remote demotion / promotion event
627 Tags tags = {
628 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
629 librbd::Journal<>::LOCAL_MIRROR_UUID,
630 true, 1, 99})},
631 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
632 librbd::Journal<>::LOCAL_MIRROR_UUID,
633 true, 2, 1})},
634 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
635 librbd::Journal<>::ORPHAN_MIRROR_UUID,
636 true, 3, 1})},
637 {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
638 librbd::Journal<>::LOCAL_MIRROR_UUID,
639 true, 4, 1})},
640 {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
641 librbd::Journal<>::ORPHAN_MIRROR_UUID,
642 true, 5, 1})},
643 {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
644 librbd::Journal<>::LOCAL_MIRROR_UUID,
645 true, 6, 1})},
646 {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
647 librbd::Journal<>::ORPHAN_MIRROR_UUID,
648 true, 7, 1})}
649 };
650 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
651 expect_journal_get_tag_tid(mock_journal, 345);
652 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
653 "remote mirror uuid", true, 4, 1});
654
655 MockCloseImageRequest mock_close_image_request;
656 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
657
658 C_SaferCond ctx;
659 MockInstanceWatcher mock_instance_watcher;
660 MockBootstrapRequest *request = create_request(
661 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
662 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
663 "remote mirror uuid", &ctx);
664 request->send();
665 ASSERT_EQ(0, ctx.wait());
666 }
667
668 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
669 create_local_image();
670
671 InSequence seq;
672
673 // lookup remote image tag class
674 cls::journal::Client client;
675 librbd::journal::ClientData client_data{
676 librbd::journal::ImageClientMeta{123}};
677 ::encode(client_data, client.data);
678 ::journal::MockJournaler mock_journaler;
679 expect_journaler_get_client(mock_journaler,
680 librbd::Journal<>::IMAGE_CLIENT_ID,
681 client, 0);
682
683 // lookup local peer in remote journal
684 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
685 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
686 mock_local_image_ctx.id};
687 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
688 client_data.client_meta = mirror_peer_client_meta;
689 client.data.clear();
690 ::encode(client_data, client.data);
691 expect_journaler_get_client(mock_journaler, "local mirror uuid",
692 client, 0);
693
694 // open the remote image
695 librbd::MockJournal mock_journal;
696 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
697 MockOpenImageRequest mock_open_image_request;
698 expect_open_image(mock_open_image_request, m_remote_io_ctx,
699 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
700 MockIsPrimaryRequest mock_is_primary_request;
701 expect_is_primary(mock_is_primary_request, true, 0);
702
703 // open the local image
704 mock_local_image_ctx.journal = &mock_journal;
705 MockOpenLocalImageRequest mock_open_local_image_request;
706 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
707 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
708 expect_is_resync_requested(mock_journal, false, 0);
709
710 // remote demotion / promotion event
711 Tags tags = {
712 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
713 true, 344, 99})},
714 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
715 "local mirror uuid", true, 345, 1})},
716 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
717 librbd::Journal<>::ORPHAN_MIRROR_UUID,
718 true, 3, 1})}
719 };
720 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
721 expect_journal_get_tag_tid(mock_journal, 346);
722 expect_journal_get_tag_data(mock_journal,
723 {librbd::Journal<>::ORPHAN_MIRROR_UUID,
724 librbd::Journal<>::LOCAL_MIRROR_UUID,
725 true, 345, 1});
726
727 MockCloseImageRequest mock_close_image_request;
728 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
729
730 C_SaferCond ctx;
731 MockInstanceWatcher mock_instance_watcher;
732 MockBootstrapRequest *request = create_request(
733 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
734 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
735 "remote mirror uuid", &ctx);
736 request->send();
737 ASSERT_EQ(0, ctx.wait());
738 }
739
740 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
741 create_local_image();
742
743 InSequence seq;
744
745 // lookup remote image tag class
746 cls::journal::Client client;
747 librbd::journal::ClientData client_data{
748 librbd::journal::ImageClientMeta{123}};
749 ::encode(client_data, client.data);
750 ::journal::MockJournaler mock_journaler;
751 expect_journaler_get_client(mock_journaler,
752 librbd::Journal<>::IMAGE_CLIENT_ID,
753 client, 0);
754
755 // lookup local peer in remote journal
756 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
757 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
758 mock_local_image_ctx.id};
759 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
760 client_data.client_meta = mirror_peer_client_meta;
761 client.data.clear();
762 ::encode(client_data, client.data);
763 expect_journaler_get_client(mock_journaler, "local mirror uuid",
764 client, 0);
765
766 // open the remote image
767 librbd::MockJournal mock_journal;
768 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
769 MockOpenImageRequest mock_open_image_request;
770 expect_open_image(mock_open_image_request, m_remote_io_ctx,
771 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
772 MockIsPrimaryRequest mock_is_primary_request;
773 expect_is_primary(mock_is_primary_request, true, 0);
774
775 // open the local image
776 mock_local_image_ctx.journal = &mock_journal;
777 MockOpenLocalImageRequest mock_open_local_image_request;
778 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
779 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
780 expect_is_resync_requested(mock_journal, false, 0);
781
782 // remote demotion / promotion event
783 Tags tags = {
784 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
785 librbd::Journal<>::LOCAL_MIRROR_UUID,
786 true, 1, 99})},
787 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
788 librbd::Journal<>::LOCAL_MIRROR_UUID,
789 true, 2, 1})}
790 };
791 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
792 expect_journal_get_tag_tid(mock_journal, 345);
793 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
794 librbd::Journal<>::ORPHAN_MIRROR_UUID,
795 true, 344, 0});
796
797 MockCloseImageRequest mock_close_image_request;
798 expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
799 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
800
801 C_SaferCond ctx;
802 MockInstanceWatcher mock_instance_watcher;
803 MockBootstrapRequest *request = create_request(
804 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
805 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
806 "remote mirror uuid", &ctx);
807 request->send();
808 ASSERT_EQ(-EEXIST, ctx.wait());
809 ASSERT_EQ(NULL, m_local_test_image_ctx);
810 }
811
812 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
813 create_local_image();
814
815 InSequence seq;
816
817 // lookup remote image tag class
818 cls::journal::Client client;
819 librbd::journal::ClientData client_data{
820 librbd::journal::ImageClientMeta{123}};
821 ::encode(client_data, client.data);
822 ::journal::MockJournaler mock_journaler;
823 expect_journaler_get_client(mock_journaler,
824 librbd::Journal<>::IMAGE_CLIENT_ID,
825 client, 0);
826
827 // lookup local peer in remote journal
828 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
829 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
830 mock_local_image_ctx.id};
831 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
832 client_data.client_meta = mirror_peer_client_meta;
833 client.data.clear();
834 ::encode(client_data, client.data);
835 expect_journaler_get_client(mock_journaler, "local mirror uuid",
836 client, 0);
837
838 // open the remote image
839 librbd::MockJournal mock_journal;
840 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
841 MockOpenImageRequest mock_open_image_request;
842 expect_open_image(mock_open_image_request, m_remote_io_ctx,
843 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
844 MockIsPrimaryRequest mock_is_primary_request;
845 expect_is_primary(mock_is_primary_request, true, 0);
846
847 // open the local image
848 mock_local_image_ctx.journal = &mock_journal;
849 MockOpenLocalImageRequest mock_open_local_image_request;
850 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
851 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
852
853 // resync is requested
854 expect_is_resync_requested(mock_journal, true, 0);
855
856
857 MockCloseImageRequest mock_close_image_request;
858 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
859
860 C_SaferCond ctx;
861 MockInstanceWatcher mock_instance_watcher;
862 MockBootstrapRequest *request = create_request(
863 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
864 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
865 "remote mirror uuid", &ctx);
866 m_do_resync = false;
867 request->send();
868 ASSERT_EQ(0, ctx.wait());
869 ASSERT_TRUE(m_do_resync);
870 }
871
872 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
873 create_local_image();
874
875 InSequence seq;
876
877 // lookup remote image tag class
878 cls::journal::Client client;
879 librbd::journal::ClientData client_data{
880 librbd::journal::ImageClientMeta{123}};
881 ::encode(client_data, client.data);
882 ::journal::MockJournaler mock_journaler;
883 expect_journaler_get_client(mock_journaler,
884 librbd::Journal<>::IMAGE_CLIENT_ID,
885 client, 0);
886
887 // lookup local peer in remote journal
888 client = {};
889 expect_journaler_get_client(mock_journaler, "local mirror uuid",
890 client, -ENOENT);
891
892 // register missing client in remote journal
893 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
894 client_data.client_meta = mirror_peer_client_meta;
895 expect_journaler_register_client(mock_journaler, client_data, 0);
896
897 // open the remote image
898 librbd::MockJournal mock_journal;
899 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
900 MockOpenImageRequest mock_open_image_request;
901 expect_open_image(mock_open_image_request, m_remote_io_ctx,
902 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
903 MockIsPrimaryRequest mock_is_primary_request;
904 expect_is_primary(mock_is_primary_request, true, 0);
905
906 // create the local image
907 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
908 mock_local_image_ctx.journal = &mock_journal;
909
910 MockCreateImageRequest mock_create_image_request;
911 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
912
913 // open the local image
914 MockOpenLocalImageRequest mock_open_local_image_request;
915 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
916 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
917 expect_is_resync_requested(mock_journal, false, 0);
918
919 // update client state back to syncing
920 mirror_peer_client_meta = {mock_local_image_ctx.id};
921 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
922 client_data.client_meta = mirror_peer_client_meta;
923 client.data.clear();
924 ::encode(client_data, client.data);
925 expect_journaler_update_client(mock_journaler, client_data, 0);
926
927 // sync the remote image to the local image
928 MockImageSync mock_image_sync;
929 expect_image_sync(mock_image_sync, 0);
930
931 MockCloseImageRequest mock_close_image_request;
932 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
933
934 C_SaferCond ctx;
935 MockInstanceWatcher mock_instance_watcher;
936 MockBootstrapRequest *request = create_request(
937 &mock_instance_watcher, mock_journaler, "",
938 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
939 "remote mirror uuid", &ctx);
940 request->send();
941 ASSERT_EQ(0, ctx.wait());
942 }
943
944 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
945 create_local_image();
946
947 InSequence seq;
948
949 // lookup remote image tag class
950 cls::journal::Client client;
951 librbd::journal::ClientData client_data{
952 librbd::journal::ImageClientMeta{123}};
953 ::encode(client_data, client.data);
954 ::journal::MockJournaler mock_journaler;
955 expect_journaler_get_client(mock_journaler,
956 librbd::Journal<>::IMAGE_CLIENT_ID,
957 client, 0);
958
959 // lookup local peer in remote journal
960 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
961 "missing image id"};
962 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
963 client_data.client_meta = mirror_peer_client_meta;
964 client.data.clear();
965 ::encode(client_data, client.data);
966 expect_journaler_get_client(mock_journaler, "local mirror uuid",
967 client, 0);
968
969 // open the remote image
970 librbd::MockJournal mock_journal;
971 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
972 MockOpenImageRequest mock_open_image_request;
973 expect_open_image(mock_open_image_request, m_remote_io_ctx,
974 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
975 MockIsPrimaryRequest mock_is_primary_request;
976 expect_is_primary(mock_is_primary_request, true, 0);
977
978 // open the missing local image
979 MockOpenLocalImageRequest mock_open_local_image_request;
980 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
981 "missing image id", nullptr, -ENOENT);
982
983 // create the missing local image
984 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
985 mock_local_image_ctx.journal = &mock_journal;
986
987 MockCreateImageRequest mock_create_image_request;
988 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
989
990 // open the local image
991 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
992 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
993 expect_is_resync_requested(mock_journal, false, 0);
994
995 // update client state back to syncing
996 mirror_peer_client_meta = {mock_local_image_ctx.id};
997 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
998 client_data.client_meta = mirror_peer_client_meta;
999 client.data.clear();
1000 ::encode(client_data, client.data);
1001 expect_journaler_update_client(mock_journaler, client_data, 0);
1002
1003 // sync the remote image to the local image
1004 MockImageSync mock_image_sync;
1005 expect_image_sync(mock_image_sync, 0);
1006
1007 MockCloseImageRequest mock_close_image_request;
1008 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1009
1010 C_SaferCond ctx;
1011 MockInstanceWatcher mock_instance_watcher;
1012 MockBootstrapRequest *request = create_request(
1013 &mock_instance_watcher, mock_journaler, "",
1014 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
1015 "remote mirror uuid", &ctx);
1016 request->send();
1017 ASSERT_EQ(0, ctx.wait());
1018 }
1019
1020 } // namespace image_replayer
1021 } // namespace mirror
1022 } // namespace rbd