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