Return(r)));
}
+ void expect_get_mirror_mode(librados::IoCtx &io_ctx,
+ cls::rbd::MirrorImageMode mode, int r) {
+ cls::rbd::MirrorImage mirror_image;
+ mirror_image.mode = mode;
+
+ bufferlist bl;
+ encode(mirror_image, bl);
+
+ EXPECT_CALL(get_mock_io_ctx(io_ctx),
+ exec(RBD_MIRRORING, _, StrEq("rbd"),
+ StrEq("mirror_image_get"), _, _, _))
+ .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
+ *out_bl = bl;
+ })),
+ Return(r)));
+ }
+
void expect_journaler_get_client(::journal::MockJournaler &mock_journaler,
const std::string &client_id,
cls::journal::Client &client, int r) {
expect_get_mirror_image_id(mock_get_mirror_image_id_request,
"remote image id", 0);
+ expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+ 0);
+
EXPECT_CALL(mock_remote_journaler, construct());
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
expect_get_mirror_image_id(mock_get_mirror_image_id_request,
"remote image id", 0);
+ expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+ 0);
+
EXPECT_CALL(mock_remote_journaler, construct());
cls::journal::Client client;
ASSERT_TRUE(remote_journaler == nullptr);
}
+TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, MirrorModeError) {
+ journal::MockJournaler mock_remote_journaler;
+ MockThreads mock_threads(m_threads);
+
+ InSequence seq;
+ expect_mirror_uuid_get(m_remote_io_ctx, "remote mirror uuid", 0);
+ MockGetMirrorImageIdRequest mock_get_mirror_image_id_request;
+ expect_get_mirror_image_id(mock_get_mirror_image_id_request,
+ "remote image id", 0);
+
+ expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+ -EINVAL);
+
+ std::string remote_mirror_uuid;
+ std::string remote_image_id;
+ journal::MockJournalerProxy *remote_journaler = nullptr;
+ cls::journal::ClientState client_state;
+ librbd::journal::MirrorPeerClientMeta client_meta;
+ C_SaferCond ctx;
+ auto req = MockPrepareRemoteImageRequest::create(&mock_threads,
+ m_remote_io_ctx,
+ "global image id",
+ "local mirror uuid",
+ "", {}, nullptr,
+ &remote_mirror_uuid,
+ &remote_image_id,
+ &remote_journaler,
+ &client_state, &client_meta,
+ &ctx);
+ req->send();
+
+ ASSERT_EQ(-EINVAL, ctx.wait());
+ ASSERT_TRUE(remote_journaler == nullptr);
+}
+
TEST_F(TestMockImageReplayerPrepareRemoteImageRequest, GetClientError) {
journal::MockJournaler mock_remote_journaler;
MockThreads mock_threads(m_threads);
expect_get_mirror_image_id(mock_get_mirror_image_id_request,
"remote image id", 0);
+ expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+ 0);
+
EXPECT_CALL(mock_remote_journaler, construct());
cls::journal::Client client;
expect_get_mirror_image_id(mock_get_mirror_image_id_request,
"remote image id", 0);
+ expect_get_mirror_mode(m_remote_io_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
+ 0);
+
EXPECT_CALL(mock_remote_journaler, construct());
cls::journal::Client client;
return;
}
- get_client();
+ get_mirror_image();
+}
+
+template <typename I>
+void PrepareRemoteImageRequest<I>::get_mirror_image() {
+ dout(10) << dendl;
+
+ librados::ObjectReadOperation op;
+ librbd::cls_client::mirror_image_get_start(&op, *m_remote_image_id);
+
+ auto aio_comp = create_rados_callback<
+ PrepareRemoteImageRequest<I>,
+ &PrepareRemoteImageRequest<I>::handle_get_mirror_image>(this);
+ m_out_bl.clear();
+ int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
+ ceph_assert(r == 0);
+ aio_comp->release();
+}
+
+template <typename I>
+void PrepareRemoteImageRequest<I>::handle_get_mirror_image(int r) {
+ dout(10) << "r=" << r << dendl;
+ cls::rbd::MirrorImage mirror_image;
+ if (r == 0) {
+ auto iter = m_out_bl.cbegin();
+ r = librbd::cls_client::mirror_image_get_finish(&iter, &mirror_image);
+ }
+
+ if (r == -ENOENT) {
+ dout(10) << "image " << m_global_image_id << " not mirrored" << dendl;
+ finish(r);
+ return;
+ } else if (r < 0) {
+ derr << "failed to retrieve mirror image details for image "
+ << m_global_image_id << ": " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ }
+
+ switch (mirror_image.mode) {
+ case cls::rbd::MIRROR_IMAGE_MODE_JOURNAL:
+ get_client();
+ break;
+ case cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT:
+ // TODO
+ default:
+ derr << "unsupported mirror image mode " << mirror_image.mode << " "
+ << "for image " << m_global_image_id << dendl;
+ finish(-EOPNOTSUPP);
+ break;
+ }
}
template <typename I>