]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: handle disabling/creating image in PrepareLocalImageRequest
authorArthur Outhenin-Chalandre <arthur.outhenin-chalandre@cern.ch>
Thu, 29 Jul 2021 09:54:45 +0000 (11:54 +0200)
committerArthur Outhenin-Chalandre <arthur.outhenin-chalandre@cern.ch>
Wed, 12 Jan 2022 09:03:42 +0000 (10:03 +0100)
Signed-off-by: Arthur Outhenin-Chalandre <arthur.outhenin-chalandre@cern.ch>
(cherry picked from commit 965bc4150eafc8e3bbe69f63beea9c7fbb20ceb6)
Conflicts:
        src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc
- Trivial conflict resolution; s/lirbd::asio:://

src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc
src/tools/rbd_mirror/ImageReplayer.cc
src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc
src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h

index d2cb1afb67735881027293563e597bd2b6f6bdc4..051c87cf4c786d1b8e3178b39a92975f7d1cfe1d 100644 (file)
@@ -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<librbd::MockTestImageCtx>* GetInfoRequest<librbd::MockTestImageCt
 
 namespace rbd {
 namespace mirror {
+
+template <>
+struct ImageDeleter<librbd::MockTestImageCtx> {
+  static ImageDeleter* s_instance;
+
+  static void trash_move(librados::IoCtx& local_io_ctx,
+                         const std::string& global_image_id, bool resync,
+                         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<librbd::MockTestImageCtx>* ImageDeleter<librbd::MockTestImageCtx>::s_instance = nullptr;
+
 namespace image_replayer {
 
 template <>
@@ -176,6 +199,7 @@ using ::testing::WithArgs;
 
 class TestMockImageReplayerPrepareLocalImageRequest : public TestMockFixture {
 public:
+  typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter;
   typedef PrepareLocalImageRequest<librbd::MockTestImageCtx> MockPrepareLocalImageRequest;
   typedef GetMirrorImageIdRequest<librbd::MockTestImageCtx> MockGetMirrorImageIdRequest;
   typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder;
@@ -221,6 +245,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) {
@@ -399,6 +434,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
index f045b1bfd9858bfe6b34b9a49549318e5267284a..afc980bd809efd7419b1e7343f80365f4c902ba3 100644 (file)
@@ -395,6 +395,9 @@ void ImageReplayer<I>::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;
index a64117425d93f5bedcc221303024d8a01078ac99..b1fef7254760a1178045d8c47229fe759f205015 100644 (file)
@@ -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<I>::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<I>::handle_get_mirror_info(int r) {
   finish(0);
 }
 
+template <typename I>
+void PrepareLocalImageRequest<I>::move_to_trash() {
+  dout(10) << dendl;
+
+  Context *ctx = create_context_callback<
+    PrepareLocalImageRequest<I>,
+    &PrepareLocalImageRequest<I>::handle_move_to_trash>(this);
+  ImageDeleter<I>::trash_move(m_io_ctx, m_global_image_id,
+                              false, m_work_queue, ctx);
+}
+
+template <typename I>
+void PrepareLocalImageRequest<I>::handle_move_to_trash(int r) {
+  dout(10) << ": r=" << r << dendl;
+
+  finish(-ENOENT);
+}
+
 template <typename I>
 void PrepareLocalImageRequest<I>::finish(int r) {
   dout(10) << "r=" << r << dendl;
index 05473c204aed4493e1c84379722d555b8bff0802..74c37ba38b6f07e708cb7a9385cc878307587308 100644 (file)
@@ -65,6 +65,10 @@ private:
    *    v
    * GET_MIRROR_INFO
    *    |
+   *    | (if the image mirror state is CREATING)
+   *    v
+   * TRASH_MOVE
+   *    |
    *    v
    * <finish>
    *
@@ -93,6 +97,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);
 
 };