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/Threads.h"
22 #include "librbd/ImageCtx.h"
23 #include "librbd/ImageState.h"
24 #include "librbd/Operations.h"
25 #include "librbd/Journal.h"
26 #include "librbd/internal.h"
27 #include "librbd/Utils.h"
28 #include "librbd/api/Mirror.h"
29 #include "test/rbd_mirror/test_fixture.h"
31 #include "test/librados/test.h"
32 #include "gtest/gtest.h"
34 #define GLOBAL_IMAGE_ID "global_image_id"
35 #define GLOBAL_CLONE_IMAGE_ID "global_image_id_clone"
37 #define dout_subsys ceph_subsys_rbd_mirror
39 using rbd::mirror::RadosRef
;
40 using rbd::mirror::TestFixture
;
41 using namespace librbd
;
42 using cls::rbd::MirrorImageState
;
45 void register_test_rbd_mirror_image_deleter() {
48 class TestImageDeleter
: public TestFixture
{
51 static int64_t m_local_pool_id
;
53 const std::string m_local_mirror_uuid
= "local mirror uuid";
54 const std::string m_remote_mirror_uuid
= "remote mirror uuid";
56 static void SetUpTestCase() {
57 TestFixture::SetUpTestCase();
59 m_local_pool_id
= _rados
->pool_lookup(_local_pool_name
.c_str());
62 void SetUp() override
{
65 librbd::api::Mirror
<>::mode_set(m_local_io_ctx
, RBD_MIRROR_MODE_IMAGE
);
67 m_deleter
= new rbd::mirror::ImageDeleter(m_threads
->work_queue
,
69 &m_threads
->timer_lock
);
71 EXPECT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, 1 << 20));
72 ImageCtx
*ictx
= new ImageCtx(m_image_name
, "", "", m_local_io_ctx
,
74 EXPECT_EQ(0, ictx
->state
->open(false));
75 m_local_image_id
= ictx
->id
;
77 cls::rbd::MirrorImage
mirror_image(GLOBAL_IMAGE_ID
,
78 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
79 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, ictx
->id
,
83 EXPECT_EQ(0, ictx
->state
->close());
86 void TearDown() override
{
88 TestFixture::TearDown();
92 void remove_image(bool force
=false) {
94 cls::rbd::MirrorImage mirror_image
;
95 int r
= cls_client::mirror_image_get(&m_local_io_ctx
, m_local_image_id
,
97 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
99 mirror_image
.state
= MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
;
100 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
,
106 NoOpProgressContext ctx
;
107 int r
= remove(m_local_io_ctx
, m_image_name
, "", ctx
, force
);
108 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
111 void promote_image(ImageCtx
*ictx
=nullptr) {
115 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
117 r
= ictx
->state
->open(false);
121 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
124 int r2
= librbd::api::Mirror
<>::image_promote(ictx
, true);
125 EXPECT_EQ(1, r2
== 0 || r2
== -EINVAL
);
129 EXPECT_EQ(0, ictx
->state
->close());
133 void demote_image(ImageCtx
*ictx
=nullptr) {
136 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
138 EXPECT_EQ(0, ictx
->state
->open(false));
142 EXPECT_EQ(0, librbd::api::Mirror
<>::image_demote(ictx
));
145 EXPECT_EQ(0, ictx
->state
->close());
149 void create_snapshot(std::string snap_name
="snap1", bool protect
=false) {
150 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
152 EXPECT_EQ(0, ictx
->state
->open(false));
155 EXPECT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
159 EXPECT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
164 EXPECT_EQ(0, ictx
->state
->close());
167 std::string
create_clone() {
168 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
170 EXPECT_EQ(0, ictx
->state
->open(false));
173 EXPECT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
175 EXPECT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
178 EXPECT_EQ(0, librbd::clone(m_local_io_ctx
, ictx
->name
.c_str(), "snap1",
179 m_local_io_ctx
, "clone1", ictx
->features
,
181 std::string clone_id
;
182 ImageCtx
*ictx_clone
= new ImageCtx("clone1", "", "", m_local_io_ctx
,
184 EXPECT_EQ(0, ictx_clone
->state
->open(false));
185 clone_id
= ictx_clone
->id
;
186 cls::rbd::MirrorImage
mirror_image(GLOBAL_CLONE_IMAGE_ID
,
187 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
188 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, clone_id
,
190 demote_image(ictx_clone
);
191 EXPECT_EQ(0, ictx_clone
->state
->close());
194 EXPECT_EQ(0, ictx
->state
->close());
199 void check_image_deleted() {
200 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
202 EXPECT_EQ(-ENOENT
, ictx
->state
->open(false));
204 cls::rbd::MirrorImage mirror_image
;
205 EXPECT_EQ(-ENOENT
, cls_client::mirror_image_get(&m_local_io_ctx
,
212 std::string m_local_image_id
;
213 rbd::mirror::ImageDeleter
*m_deleter
;
216 int64_t TestImageDeleter::m_local_pool_id
;
219 TEST_F(TestImageDeleter
, Delete_NonPrimary_Image
) {
220 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
223 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
225 EXPECT_EQ(0, ctx
.wait());
227 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
228 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
230 check_image_deleted();
233 TEST_F(TestImageDeleter
, Fail_Delete_Primary_Image
) {
236 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
239 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
241 EXPECT_EQ(-rbd::mirror::ImageDeleter::EISPRM
, ctx
.wait());
243 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
244 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
247 TEST_F(TestImageDeleter
, Delete_Image_With_Child
) {
250 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
253 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
255 EXPECT_EQ(0, ctx
.wait());
257 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
258 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
261 TEST_F(TestImageDeleter
, Delete_Image_With_Children
) {
262 create_snapshot("snap1");
263 create_snapshot("snap2");
265 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
268 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
270 EXPECT_EQ(0, ctx
.wait());
272 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
273 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
276 TEST_F(TestImageDeleter
, Delete_Image_With_ProtectedChild
) {
277 create_snapshot("snap1", true);
279 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(0, 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_ProtectedChildren
) {
291 create_snapshot("snap1", true);
292 create_snapshot("snap2", true);
294 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_Clone
) {
306 std::string clone_id
= create_clone();
308 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
311 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
313 EXPECT_EQ(-EBUSY
, ctx
.wait());
315 ASSERT_EQ(1u, m_deleter
->get_delete_queue_items().size());
316 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
318 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
,
319 GLOBAL_CLONE_IMAGE_ID
);
322 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_CLONE_IMAGE_ID
,
324 EXPECT_EQ(0, ctx2
.wait());
327 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
329 EXPECT_EQ(0, ctx3
.wait());
331 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
332 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
335 TEST_F(TestImageDeleter
, Delete_NonExistent_Image
) {
338 cls::rbd::MirrorImage
mirror_image(GLOBAL_IMAGE_ID
,
339 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
340 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
343 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
346 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
348 EXPECT_EQ(0, ctx
.wait());
350 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
351 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
353 check_image_deleted();
356 TEST_F(TestImageDeleter
, Delete_NonExistent_Image_With_MirroringState
) {
359 cls::rbd::MirrorImage
mirror_image(GLOBAL_IMAGE_ID
,
360 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
361 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
363 mirror_image
.state
= MirrorImageState::MIRROR_IMAGE_STATE_DISABLING
;
364 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
367 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
370 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
372 EXPECT_EQ(0, ctx
.wait());
374 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
375 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
377 check_image_deleted();
380 TEST_F(TestImageDeleter
, Delete_NonExistent_Image_Without_MirroringState
) {
383 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
386 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
388 EXPECT_EQ(-ENOENT
, ctx
.wait());
390 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
391 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
393 check_image_deleted();
396 TEST_F(TestImageDeleter
, Fail_Delete_NonPrimary_Image
) {
397 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
399 EXPECT_EQ(0, ictx
->state
->open(false));
401 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
404 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
406 EXPECT_EQ(-EBUSY
, ctx
.wait());
408 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
409 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
411 EXPECT_EQ(0, ictx
->state
->close());
414 TEST_F(TestImageDeleter
, Retry_Failed_Deletes
) {
415 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
417 EXPECT_EQ(0, ictx
->state
->open(false));
419 m_deleter
->set_failed_timer_interval(2);
421 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
424 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
426 EXPECT_EQ(-EBUSY
, ctx
.wait());
428 EXPECT_EQ(0, ictx
->state
->close());
431 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
433 EXPECT_EQ(0, ctx2
.wait());
435 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
436 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
438 check_image_deleted();
441 TEST_F(TestImageDeleter
, Delete_Is_Idempotent
) {
442 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
444 EXPECT_EQ(0, ictx
->state
->open(false));
446 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
449 m_deleter
->wait_for_scheduled_deletion(m_local_pool_id
, GLOBAL_IMAGE_ID
,
451 EXPECT_EQ(-EBUSY
, ctx
.wait());
453 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
454 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
456 m_deleter
->schedule_image_delete(_rados
, m_local_pool_id
, GLOBAL_IMAGE_ID
);
458 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
459 ASSERT_EQ(1u, m_deleter
->get_failed_queue_items().size());
461 EXPECT_EQ(0, ictx
->state
->close());