From: Arthur Outhenin-Chalandre Date: Thu, 29 Jul 2021 09:54:45 +0000 (+0200) Subject: rbd-mirror: handle disabling/creating image in PrepareLocalImageRequest X-Git-Tag: v17.1.0~611^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=965bc4150eafc8e3bbe69f63beea9c7fbb20ceb6;p=ceph-ci.git rbd-mirror: handle disabling/creating image in PrepareLocalImageRequest Signed-off-by: Arthur Outhenin-Chalandre --- diff --git a/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc index 0b0a87e8de5..54c3b24efac 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc @@ -5,6 +5,7 @@ #include "cls/rbd/cls_rbd_types.h" #include "librbd/journal/TypeTraits.h" #include "librbd/mirror/GetInfoRequest.h" +#include "tools/rbd_mirror/ImageDeleter.h" #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h" #include "tools/rbd_mirror/image_replayer/StateBuilder.h" @@ -70,6 +71,28 @@ GetInfoRequest* GetInfoRequest +struct ImageDeleter { + static ImageDeleter* s_instance; + + static void trash_move(librados::IoCtx& local_io_ctx, + const std::string& global_image_id, bool resync, + librbd::asio::ContextWQ* work_queue, + Context* on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->trash_move(global_image_id, resync, on_finish); + } + + MOCK_METHOD3(trash_move, void(const std::string&, bool, Context*)); + + ImageDeleter() { + s_instance = this; + } +}; + +ImageDeleter* ImageDeleter::s_instance = nullptr; + namespace image_replayer { template <> @@ -176,6 +199,7 @@ using ::testing::WithArgs; class TestMockImageReplayerPrepareLocalImageRequest : public TestMockFixture { public: + typedef ImageDeleter MockImageDeleter; typedef PrepareLocalImageRequest MockPrepareLocalImageRequest; typedef GetMirrorImageIdRequest MockGetMirrorImageIdRequest; typedef StateBuilder MockStateBuilder; @@ -222,6 +246,17 @@ public: mock_get_mirror_info_request.on_finish, r); })); } + + void expect_trash_move(MockImageDeleter& mock_image_deleter, + const std::string& global_image_id, + bool ignore_orphan, int r) { + EXPECT_CALL(mock_image_deleter, + trash_move(global_image_id, ignore_orphan, _)) + .WillOnce(WithArg<2>(Invoke([this, r](Context* ctx) { + m_threads->work_queue->queue(ctx, r); + }))); + } + }; TEST_F(TestMockImageReplayerPrepareLocalImageRequest, SuccessJournal) { @@ -400,6 +435,71 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageInfoError) { ASSERT_EQ(-EINVAL, ctx.wait()); } +TEST_F(TestMockImageReplayerPrepareLocalImageRequest, ImageCreating) { + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "local image id", + 0); + expect_dir_get_name(m_local_io_ctx, "local image name", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_CREATING}, + librbd::mirror::PROMOTION_STATE_NON_PRIMARY, + "remote mirror uuid", 0); + + MockImageDeleter mock_image_deleter; + expect_trash_move(mock_image_deleter, "global image id", false, 0); + + MockSnapshotStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + std::string local_image_name; + C_SaferCond ctx; + auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx, + "global image id", + &local_image_name, + &mock_state_builder, + m_threads->work_queue, + &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); + ASSERT_TRUE(mock_state_builder == nullptr); +} + +TEST_F(TestMockImageReplayerPrepareLocalImageRequest, ImageDisabling) { + InSequence seq; + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "local image id", + 0); + expect_dir_get_name(m_local_io_ctx, "local image name", 0); + + MockGetMirrorInfoRequest mock_get_mirror_info_request; + expect_get_mirror_info(mock_get_mirror_info_request, + {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, + "global image id", + cls::rbd::MIRROR_IMAGE_STATE_DISABLING}, + librbd::mirror::PROMOTION_STATE_NON_PRIMARY, + "remote mirror uuid", 0); + + MockSnapshotStateBuilder mock_journal_state_builder; + MockStateBuilder* mock_state_builder = nullptr; + std::string local_image_name; + C_SaferCond ctx; + auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx, + "global image id", + &local_image_name, + &mock_state_builder, + m_threads->work_queue, + &ctx); + req->send(); + + ASSERT_EQ(-ERESTART, ctx.wait()); + ASSERT_TRUE(mock_state_builder == nullptr); +} + } // namespace image_replayer } // namespace mirror } // namespace rbd diff --git a/src/tools/rbd_mirror/ImageReplayer.cc b/src/tools/rbd_mirror/ImageReplayer.cc index 9546d09fce1..f04dc68d68f 100644 --- a/src/tools/rbd_mirror/ImageReplayer.cc +++ b/src/tools/rbd_mirror/ImageReplayer.cc @@ -397,6 +397,9 @@ void ImageReplayer::handle_bootstrap(int r) { m_delete_requested = true; on_start_fail(0, "remote image no longer exists"); return; + } else if (r == -ERESTART) { + on_start_fail(r, "image in transient state, try again"); + return; } else if (r < 0) { on_start_fail(r, "error bootstrapping replay"); return; diff --git a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc index a64117425d9..b1fef725476 100644 --- a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc @@ -10,6 +10,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "librbd/mirror/GetInfoRequest.h" +#include "tools/rbd_mirror/ImageDeleter.h" #include "tools/rbd_mirror/Threads.h" #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h" @@ -124,9 +125,16 @@ void PrepareLocalImageRequest::handle_get_mirror_info(int r) { return; } - // TODO save current mirror state to determine if we should - // delete a partially formed image - // (e.g. MIRROR_IMAGE_STATE_CREATING/DELETING) + if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_CREATING) { + dout(5) << "local image is still in creating state, issuing a removal" + << dendl; + move_to_trash(); + return; + } else if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) { + dout(5) << "local image mirroring is in disabling state" << dendl; + finish(-ERESTART); + return; + } switch (m_mirror_image.mode) { case cls::rbd::MIRROR_IMAGE_MODE_JOURNAL: @@ -156,6 +164,24 @@ void PrepareLocalImageRequest::handle_get_mirror_info(int r) { finish(0); } +template +void PrepareLocalImageRequest::move_to_trash() { + dout(10) << dendl; + + Context *ctx = create_context_callback< + PrepareLocalImageRequest, + &PrepareLocalImageRequest::handle_move_to_trash>(this); + ImageDeleter::trash_move(m_io_ctx, m_global_image_id, + false, m_work_queue, ctx); +} + +template +void PrepareLocalImageRequest::handle_move_to_trash(int r) { + dout(10) << ": r=" << r << dendl; + + finish(-ENOENT); +} + template void PrepareLocalImageRequest::finish(int r) { dout(10) << "r=" << r << dendl; diff --git a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h index 8285ca060b3..6372169ff05 100644 --- a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h +++ b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h @@ -67,6 +67,10 @@ private: * v * GET_MIRROR_INFO * | + * | (if the image mirror state is CREATING) + * v + * TRASH_MOVE + * | * v * * @@ -95,6 +99,9 @@ private: void get_mirror_info(); void handle_get_mirror_info(int r); + void move_to_trash(); + void handle_move_to_trash(int r); + void finish(int r); };