1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 SUSE LINUX GmbH
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
14 #include "include/rados/librados.hpp"
15 #include "include/rbd/librbd.hpp"
16 #include "include/stringify.h"
17 #include "cls/rbd/cls_rbd_types.h"
18 #include "cls/rbd/cls_rbd_client.h"
19 #include "tools/rbd_mirror/ImageDeleter.h"
20 #include "tools/rbd_mirror/ImageReplayer.h"
21 #include "tools/rbd_mirror/ServiceDaemon.h"
22 #include "tools/rbd_mirror/Threads.h"
23 #include "librbd/ImageCtx.h"
24 #include "librbd/ImageState.h"
25 #include "librbd/Operations.h"
26 #include "librbd/Journal.h"
27 #include "librbd/internal.h"
28 #include "librbd/Utils.h"
29 #include "librbd/api/Mirror.h"
30 #include "librbd/journal/DisabledPolicy.h"
31 #include "test/rbd_mirror/test_fixture.h"
33 #include "test/librados/test.h"
34 #include "gtest/gtest.h"
36 #define GLOBAL_IMAGE_ID "global_image_id"
37 #define GLOBAL_CLONE_IMAGE_ID "global_image_id_clone"
39 #define dout_subsys ceph_subsys_rbd_mirror
41 using rbd::mirror::RadosRef
;
42 using rbd::mirror::TestFixture
;
43 using namespace librbd
;
44 using cls::rbd::MirrorImageState
;
47 void register_test_rbd_mirror_image_deleter() {
50 class TestImageDeleter
: public TestFixture
{
53 static int64_t m_local_pool_id
;
55 const std::string m_local_mirror_uuid
= "local mirror uuid";
56 const std::string m_remote_mirror_uuid
= "remote mirror uuid";
58 static void SetUpTestCase() {
59 TestFixture::SetUpTestCase();
61 m_local_pool_id
= _rados
->pool_lookup(_local_pool_name
.c_str());
64 void SetUp() override
{
66 m_service_daemon
.reset(new rbd::mirror::ServiceDaemon
<>(g_ceph_context
,
69 librbd::api::Mirror
<>::mode_set(m_local_io_ctx
, RBD_MIRROR_MODE_IMAGE
);
71 m_deleter
= new rbd::mirror::ImageDeleter
<>(m_threads
->work_queue
,
73 &m_threads
->timer_lock
,
74 m_service_daemon
.get());
76 m_local_image_id
= librbd::util::generate_image_id(m_local_io_ctx
);
77 librbd::ImageOptions image_opts
;
78 image_opts
.set(RBD_IMAGE_OPTION_FEATURES
, RBD_FEATURES_ALL
);
79 EXPECT_EQ(0, librbd::create(m_local_io_ctx
, m_image_name
, m_local_image_id
,
80 1 << 20, image_opts
, GLOBAL_IMAGE_ID
,
81 m_remote_mirror_uuid
, true));
83 cls::rbd::MirrorImage
mirror_image(
84 GLOBAL_IMAGE_ID
, MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
85 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
89 void TearDown() override
{
92 m_service_daemon
.reset();
94 TestFixture::TearDown();
97 void remove_image(bool force
=false) {
99 cls::rbd::MirrorImage mirror_image
;
100 int r
= cls_client::mirror_image_get(&m_local_io_ctx
, m_local_image_id
,
102 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
104 mirror_image
.state
= MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
;
105 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
,
111 NoOpProgressContext ctx
;
112 int r
= remove(m_local_io_ctx
, m_image_name
, "", ctx
, force
);
113 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
116 void promote_image(ImageCtx
*ictx
=nullptr) {
120 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
122 r
= ictx
->state
->open(false);
126 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
129 int r2
= librbd::api::Mirror
<>::image_promote(ictx
, true);
130 EXPECT_EQ(1, r2
== 0 || r2
== -EINVAL
);
134 EXPECT_EQ(0, ictx
->state
->close());
138 void demote_image(ImageCtx
*ictx
=nullptr) {
141 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
143 EXPECT_EQ(0, ictx
->state
->open(false));
147 EXPECT_EQ(0, librbd::api::Mirror
<>::image_demote(ictx
));
150 EXPECT_EQ(0, ictx
->state
->close());
154 void create_snapshot(std::string snap_name
="snap1", bool protect
=false) {
155 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
157 EXPECT_EQ(0, ictx
->state
->open(false));
159 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
160 ictx
->set_journal_policy(new librbd::journal::DisabledPolicy());
163 EXPECT_EQ(0, ictx
->operations
->snap_create(
164 cls::rbd::UserSnapshotNamespace(), snap_name
.c_str()));
167 EXPECT_EQ(0, ictx
->operations
->snap_protect(
168 cls::rbd::UserSnapshotNamespace(), snap_name
.c_str()));
171 EXPECT_EQ(0, ictx
->state
->close());
174 std::string
create_clone() {
175 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
177 EXPECT_EQ(0, ictx
->state
->open(false));
179 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
180 ictx
->set_journal_policy(new librbd::journal::DisabledPolicy());
183 EXPECT_EQ(0, ictx
->operations
->snap_create(
184 cls::rbd::UserSnapshotNamespace(), "snap1"));
185 EXPECT_EQ(0, ictx
->operations
->snap_protect(
186 cls::rbd::UserSnapshotNamespace(), "snap1"));
187 EXPECT_EQ(0, librbd::snap_set(ictx
, cls::rbd::UserSnapshotNamespace(),
190 std::string clone_id
= librbd::util::generate_image_id(m_local_io_ctx
);
191 librbd::ImageOptions clone_opts
;
192 clone_opts
.set(RBD_IMAGE_OPTION_FEATURES
, ictx
->features
);
193 EXPECT_EQ(0, librbd::clone(ictx
, m_local_io_ctx
, "clone1", clone_id
,
194 clone_opts
, GLOBAL_CLONE_IMAGE_ID
,
195 m_remote_mirror_uuid
));
197 cls::rbd::MirrorImage
mirror_image(
198 GLOBAL_CLONE_IMAGE_ID
, MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
199 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, clone_id
,
201 EXPECT_EQ(0, ictx
->state
->close());
205 void check_image_deleted() {
206 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
208 EXPECT_EQ(-ENOENT
, ictx
->state
->open(false));
210 cls::rbd::MirrorImage mirror_image
;
211 EXPECT_EQ(-ENOENT
, cls_client::mirror_image_get(&m_local_io_ctx
,
218 std::string m_local_image_id
;
219 std::unique_ptr
<rbd::mirror::ServiceDaemon
<>> m_service_daemon
;
220 rbd::mirror::ImageDeleter
<> *m_deleter
;
223 int64_t TestImageDeleter::m_local_pool_id
;
226 TEST_F(TestImageDeleter
, Delete_NonPrimary_Image
) {
227 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
231 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
233 EXPECT_EQ(0, ctx
.wait());
235 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
236 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
238 check_image_deleted();
241 TEST_F(TestImageDeleter
, Delete_Split_Brain_Image
) {
245 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
249 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
251 EXPECT_EQ(0, ctx
.wait());
253 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
254 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
256 check_image_deleted();
259 TEST_F(TestImageDeleter
, Fail_Delete_Primary_Image
) {
262 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
266 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
268 EXPECT_EQ(-rbd::mirror::ImageDeleter
<>::EISPRM
, ctx
.wait());
270 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
271 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
274 TEST_F(TestImageDeleter
, Fail_Delete_Orphan_Image
) {
278 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
282 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
284 EXPECT_EQ(-rbd::mirror::ImageDeleter
<>::EISPRM
, ctx
.wait());
286 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
287 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
290 TEST_F(TestImageDeleter
, Delete_Image_With_Child
) {
293 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
297 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
299 EXPECT_EQ(0, ctx
.wait());
301 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
302 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
305 TEST_F(TestImageDeleter
, Delete_Image_With_Children
) {
306 create_snapshot("snap1");
307 create_snapshot("snap2");
309 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
313 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
315 EXPECT_EQ(0, ctx
.wait());
317 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
318 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
321 TEST_F(TestImageDeleter
, Delete_Image_With_ProtectedChild
) {
322 create_snapshot("snap1", true);
324 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
328 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
330 EXPECT_EQ(0, ctx
.wait());
332 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
333 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
336 TEST_F(TestImageDeleter
, Delete_Image_With_ProtectedChildren
) {
337 create_snapshot("snap1", true);
338 create_snapshot("snap2", true);
340 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
344 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
346 EXPECT_EQ(0, ctx
.wait());
348 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
349 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
352 TEST_F(TestImageDeleter
, Delete_Image_With_Clone
) {
353 std::string clone_id
= create_clone();
355 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
359 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
361 EXPECT_EQ(-EBUSY
, ctx
.wait());
363 ASSERT_EQ(1u, m_deleter
->get_delete_queue_items().size());
364 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
366 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
,
367 GLOBAL_CLONE_IMAGE_ID
, false);
370 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_CLONE_IMAGE_ID
,
372 EXPECT_EQ(0, ctx2
.wait());
375 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
377 EXPECT_EQ(0, ctx3
.wait());
379 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
380 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
383 TEST_F(TestImageDeleter
, Delete_NonExistent_Image
) {
386 cls::rbd::MirrorImage
mirror_image(GLOBAL_IMAGE_ID
,
387 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
388 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
391 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
395 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
397 EXPECT_EQ(0, ctx
.wait());
399 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
400 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
402 check_image_deleted();
405 TEST_F(TestImageDeleter
, Delete_NonExistent_Image_With_MirroringState
) {
408 cls::rbd::MirrorImage
mirror_image(GLOBAL_IMAGE_ID
,
409 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
410 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
412 mirror_image
.state
= MirrorImageState::MIRROR_IMAGE_STATE_DISABLING
;
413 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
416 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
420 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
422 EXPECT_EQ(0, ctx
.wait());
424 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
425 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
427 check_image_deleted();
430 TEST_F(TestImageDeleter
, Delete_NonExistent_Image_Without_MirroringState
) {
433 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
437 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
439 EXPECT_EQ(-ENOENT
, ctx
.wait());
441 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
442 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
444 check_image_deleted();
447 TEST_F(TestImageDeleter
, Fail_Delete_NonPrimary_Image
) {
448 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
450 EXPECT_EQ(0, ictx
->state
->open(false));
452 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
456 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
458 EXPECT_EQ(-EBUSY
, ctx
.wait());
460 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
461 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
463 EXPECT_EQ(0, ictx
->state
->close());
466 TEST_F(TestImageDeleter
, Retry_Failed_Deletes
) {
467 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
469 EXPECT_EQ(0, ictx
->state
->open(false));
471 m_deleter
->set_failed_timer_interval(2);
473 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
477 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
479 EXPECT_EQ(-EBUSY
, ctx
.wait());
481 EXPECT_EQ(0, ictx
->state
->close());
484 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
486 EXPECT_EQ(0, ctx2
.wait());
488 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
489 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
491 check_image_deleted();
494 TEST_F(TestImageDeleter
, Delete_Is_Idempotent
) {
495 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
497 EXPECT_EQ(0, ictx
->state
->open(false));
499 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
503 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
505 EXPECT_EQ(-EBUSY
, ctx
.wait());
507 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
508 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
510 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
,
513 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
514 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
516 EXPECT_EQ(0, ictx
->state
->close());