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/ServiceDaemon.h"
21 #include "tools/rbd_mirror/Threads.h"
22 #include "tools/rbd_mirror/Throttler.h"
23 #include "tools/rbd_mirror/Types.h"
24 #include "librbd/ImageCtx.h"
25 #include "librbd/ImageState.h"
26 #include "librbd/Operations.h"
27 #include "librbd/Journal.h"
28 #include "librbd/internal.h"
29 #include "librbd/Utils.h"
30 #include "librbd/api/Image.h"
31 #include "librbd/api/Mirror.h"
32 #include "librbd/journal/DisabledPolicy.h"
33 #include "test/rbd_mirror/test_fixture.h"
35 #include "test/librados/test.h"
36 #include "gtest/gtest.h"
38 #define GLOBAL_IMAGE_ID "global_image_id"
39 #define GLOBAL_CLONE_IMAGE_ID "global_image_id_clone"
41 #define dout_subsys ceph_subsys_rbd_mirror
43 using rbd::mirror::RadosRef
;
44 using rbd::mirror::TestFixture
;
45 using namespace librbd
;
46 using cls::rbd::MirrorImageMode
;
47 using cls::rbd::MirrorImageState
;
50 void register_test_rbd_mirror_image_deleter() {
53 class TestImageDeleter
: public TestFixture
{
55 const std::string m_local_mirror_uuid
= "local mirror uuid";
56 const std::string m_remote_mirror_uuid
= "remote mirror uuid";
58 void SetUp() override
{
61 m_image_deletion_throttler
.reset(
62 new rbd::mirror::Throttler
<>(g_ceph_context
,
63 "rbd_mirror_concurrent_image_deletions"));
65 m_service_daemon
.reset(new rbd::mirror::ServiceDaemon
<>(g_ceph_context
,
68 librbd::api::Mirror
<>::mode_set(m_local_io_ctx
, RBD_MIRROR_MODE_IMAGE
);
70 m_deleter
= new rbd::mirror::ImageDeleter
<>(
71 m_local_io_ctx
, m_threads
, m_image_deletion_throttler
.get(),
72 m_service_daemon
.get());
74 m_local_image_id
= librbd::util::generate_image_id(m_local_io_ctx
);
75 librbd::ImageOptions image_opts
;
76 image_opts
.set(RBD_IMAGE_OPTION_FEATURES
, RBD_FEATURES_ALL
);
77 EXPECT_EQ(0, librbd::create(m_local_io_ctx
, m_image_name
, m_local_image_id
,
78 1 << 20, image_opts
, GLOBAL_IMAGE_ID
,
79 m_remote_mirror_uuid
, true));
81 cls::rbd::MirrorImage
mirror_image(
82 MirrorImageMode::MIRROR_IMAGE_MODE_JOURNAL
, GLOBAL_IMAGE_ID
,
83 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
84 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, m_local_image_id
,
88 void TearDown() override
{
92 m_deleter
->shut_down(&ctx
);
96 m_service_daemon
.reset();
98 TestFixture::TearDown();
101 void init_image_deleter() {
103 m_deleter
->init(&ctx
);
104 ASSERT_EQ(0, ctx
.wait());
107 void remove_image() {
108 cls::rbd::MirrorImage mirror_image
;
109 int r
= cls_client::mirror_image_get(&m_local_io_ctx
, m_local_image_id
,
111 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
113 mirror_image
.state
= MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
;
114 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
,
120 NoOpProgressContext ctx
;
121 r
= librbd::api::Image
<>::remove(m_local_io_ctx
, m_image_name
, ctx
);
122 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
125 void promote_image(ImageCtx
*ictx
=nullptr) {
129 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
131 r
= ictx
->state
->open(0);
135 EXPECT_EQ(1, r
== 0 || r
== -ENOENT
);
138 int r2
= librbd::api::Mirror
<>::image_promote(ictx
, true);
139 EXPECT_EQ(1, r2
== 0 || r2
== -EINVAL
);
143 EXPECT_EQ(0, ictx
->state
->close());
147 void demote_image(ImageCtx
*ictx
=nullptr) {
150 ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
152 EXPECT_EQ(0, ictx
->state
->open(0));
156 EXPECT_EQ(0, librbd::api::Mirror
<>::image_demote(ictx
));
159 EXPECT_EQ(0, ictx
->state
->close());
163 void create_snapshot(std::string snap_name
="snap1", bool protect
=false) {
164 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
166 EXPECT_EQ(0, ictx
->state
->open(0));
168 std::unique_lock image_locker
{ictx
->image_lock
};
169 ictx
->set_journal_policy(new librbd::journal::DisabledPolicy());
172 librbd::NoOpProgressContext prog_ctx
;
173 EXPECT_EQ(0, ictx
->operations
->snap_create(
174 cls::rbd::UserSnapshotNamespace(), snap_name
, 0, prog_ctx
));
177 EXPECT_EQ(0, ictx
->operations
->snap_protect(
178 cls::rbd::UserSnapshotNamespace(), snap_name
));
181 EXPECT_EQ(0, ictx
->state
->close());
184 std::string
create_clone() {
185 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
187 EXPECT_EQ(0, ictx
->state
->open(0));
189 std::unique_lock image_locker
{ictx
->image_lock
};
190 ictx
->set_journal_policy(new librbd::journal::DisabledPolicy());
193 librbd::NoOpProgressContext prog_ctx
;
194 EXPECT_EQ(0, ictx
->operations
->snap_create(
195 cls::rbd::UserSnapshotNamespace(), "snap1", 0, prog_ctx
));
196 EXPECT_EQ(0, ictx
->operations
->snap_protect(
197 cls::rbd::UserSnapshotNamespace(), "snap1"));
198 EXPECT_EQ(0, librbd::api::Image
<>::snap_set(
199 ictx
, cls::rbd::UserSnapshotNamespace(), "snap1"));
201 std::string clone_id
= librbd::util::generate_image_id(m_local_io_ctx
);
202 librbd::ImageOptions clone_opts
;
203 clone_opts
.set(RBD_IMAGE_OPTION_FEATURES
, ictx
->features
);
204 EXPECT_EQ(0, librbd::clone(m_local_io_ctx
, m_local_image_id
.c_str(),
205 nullptr, "snap1", m_local_io_ctx
,
206 clone_id
.c_str(), "clone1", clone_opts
,
207 GLOBAL_CLONE_IMAGE_ID
, m_remote_mirror_uuid
));
209 cls::rbd::MirrorImage
mirror_image(
210 MirrorImageMode::MIRROR_IMAGE_MODE_JOURNAL
, GLOBAL_CLONE_IMAGE_ID
,
211 MirrorImageState::MIRROR_IMAGE_STATE_ENABLED
);
212 EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx
, clone_id
,
214 EXPECT_EQ(0, ictx
->state
->close());
218 void check_image_deleted() {
219 ImageCtx
*ictx
= new ImageCtx("", m_local_image_id
, "", m_local_io_ctx
,
221 EXPECT_EQ(-ENOENT
, ictx
->state
->open(0));
223 cls::rbd::MirrorImage mirror_image
;
224 EXPECT_EQ(-ENOENT
, cls_client::mirror_image_get(&m_local_io_ctx
,
229 int trash_move(const std::string
& global_image_id
) {
231 rbd::mirror::ImageDeleter
<>::trash_move(m_local_io_ctx
, global_image_id
,
232 true, m_threads
->work_queue
, &ctx
);
237 std::string m_local_image_id
;
238 std::unique_ptr
<rbd::mirror::Throttler
<>> m_image_deletion_throttler
;
239 std::unique_ptr
<rbd::mirror::ServiceDaemon
<>> m_service_daemon
;
240 rbd::mirror::ImageDeleter
<> *m_deleter
;
243 TEST_F(TestImageDeleter
, ExistingTrashMove
) {
244 ASSERT_EQ(0, trash_move(GLOBAL_IMAGE_ID
));
247 m_deleter
->wait_for_deletion(m_local_image_id
, false, &ctx
);
248 init_image_deleter();
250 ASSERT_EQ(0, ctx
.wait());
253 TEST_F(TestImageDeleter
, LiveTrashMove
) {
254 init_image_deleter();
257 m_deleter
->wait_for_deletion(m_local_image_id
, false, &ctx
);
259 ASSERT_EQ(0, trash_move(GLOBAL_IMAGE_ID
));
260 ASSERT_EQ(0, ctx
.wait());
263 TEST_F(TestImageDeleter
, Delete_Image_With_Snapshots
) {
264 init_image_deleter();
265 create_snapshot("snap1");
266 create_snapshot("snap2");
269 m_deleter
->wait_for_deletion(m_local_image_id
, false, &ctx
);
270 ASSERT_EQ(0, trash_move(GLOBAL_IMAGE_ID
));
271 EXPECT_EQ(0, ctx
.wait());
273 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
274 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
277 TEST_F(TestImageDeleter
, Delete_Image_With_ProtectedSnapshots
) {
278 init_image_deleter();
279 create_snapshot("snap1", true);
280 create_snapshot("snap2", true);
283 m_deleter
->wait_for_deletion(m_local_image_id
, false, &ctx
);
284 ASSERT_EQ(0, trash_move(GLOBAL_IMAGE_ID
));
285 EXPECT_EQ(0, ctx
.wait());
287 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
288 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());
291 TEST_F(TestImageDeleter
, Delete_Image_With_Clone
) {
292 init_image_deleter();
293 std::string clone_id
= create_clone();
296 m_deleter
->set_busy_timer_interval(0.1);
297 m_deleter
->wait_for_deletion(m_local_image_id
, false, &ctx1
);
298 ASSERT_EQ(0, trash_move(GLOBAL_IMAGE_ID
));
299 EXPECT_EQ(-EBUSY
, ctx1
.wait());
302 m_deleter
->wait_for_deletion(clone_id
, false, &ctx2
);
303 ASSERT_EQ(0, trash_move(GLOBAL_CLONE_IMAGE_ID
));
304 EXPECT_EQ(0, ctx2
.wait());
307 m_deleter
->wait_for_deletion(m_local_image_id
, true, &ctx3
);
308 EXPECT_EQ(0, ctx3
.wait());
310 ASSERT_EQ(0u, m_deleter
->get_delete_queue_items().size());
311 ASSERT_EQ(0u, m_deleter
->get_failed_queue_items().size());