From: Mykola Golub Date: Thu, 19 Sep 2019 13:07:16 +0000 (+0100) Subject: librbd: add mirror image snapshot API X-Git-Tag: v15.1.0~565^2~10 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=01a8a510f61cf6c50de0e030cff18256f908af3c;p=ceph-ci.git librbd: add mirror image snapshot API Signed-off-by: Mykola Golub --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 31976d98e9a..c5bdd8ae838 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -1180,6 +1180,8 @@ CEPH_RBD_API int rbd_mirror_image_disable(rbd_image_t image, bool force); CEPH_RBD_API int rbd_mirror_image_promote(rbd_image_t image, bool force); CEPH_RBD_API int rbd_mirror_image_demote(rbd_image_t image); CEPH_RBD_API int rbd_mirror_image_resync(rbd_image_t image); +CEPH_RBD_API int rbd_mirror_image_create_snapshot(rbd_image_t image, + uint64_t *snap_id); CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image, rbd_mirror_image_info_t *mirror_image_info, size_t info_size); diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index 5a6b801f6d1..40777b3af82 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -732,6 +732,7 @@ public: int mirror_image_promote(bool force); int mirror_image_demote(); int mirror_image_resync(); + int mirror_image_create_snapshot(uint64_t *snap_id); int mirror_image_get_info(mirror_image_info_t *mirror_image_info, size_t info_size); int mirror_image_get_global_status( diff --git a/src/librbd/api/Mirror.cc b/src/librbd/api/Mirror.cc index 2c31c895a15..76d0e7915dd 100644 --- a/src/librbd/api/Mirror.cc +++ b/src/librbd/api/Mirror.cc @@ -11,6 +11,7 @@ #include "librbd/ImageCtx.h" #include "librbd/ImageState.h" #include "librbd/Journal.h" +#include "librbd/MirroringWatcher.h" #include "librbd/Operations.h" #include "librbd/Utils.h" #include "librbd/api/Image.h" @@ -22,12 +23,15 @@ #include "librbd/mirror/PromoteRequest.h" #include "librbd/mirror/Types.h" #include "librbd/MirroringWatcher.h" -#include "librbd/mirror_snapshot/UnlinkPeerRequest.h" +#include "librbd/mirror/snapshot/CreatePrimaryRequest.h" +#include "librbd/mirror/snapshot/UnlinkPeerRequest.h" #include #include #include #include "json_spirit/json_spirit.h" +#include + #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::api::Mirror: " << __func__ << ": " @@ -1613,6 +1617,18 @@ int Mirror::image_instance_id_list( return 0; } +template +int Mirror::image_snapshot_create(I *ictx, uint64_t *snap_id) { + CephContext *cct = ictx->cct; + ldout(cct, 20) << "ictx=" << ictx << dendl; + + C_SaferCond on_finish; + auto req = mirror::snapshot::CreatePrimaryRequest::create( + ictx, false, false, snap_id, &on_finish); + req->send(); + return on_finish.wait(); +} + } // namespace api } // namespace librbd diff --git a/src/librbd/api/Mirror.h b/src/librbd/api/Mirror.h index c7d10662e5f..6391b37fb8e 100644 --- a/src/librbd/api/Mirror.h +++ b/src/librbd/api/Mirror.h @@ -87,6 +87,8 @@ struct Mirror { mirror_image_global_status_t *status, Context *on_finish); static int image_get_instance_id(ImageCtxT *ictx, std::string *instance_id); + + static int image_snapshot_create(ImageCtxT *ictx, uint64_t *snap_id); }; } // namespace api diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 661845ed0b0..5a7c0a5a3a7 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -2810,6 +2810,12 @@ namespace librbd { return librbd::api::Mirror<>::image_resync(ictx); } + int Image::mirror_image_create_snapshot(uint64_t *snap_id) + { + ImageCtx *ictx = (ImageCtx *)ctx; + return librbd::api::Mirror<>::image_snapshot_create(ictx, snap_id); + } + int Image::mirror_image_get_info(mirror_image_info_t *mirror_image_info, size_t info_size) { ImageCtx *ictx = (ImageCtx *)ctx; @@ -6163,6 +6169,13 @@ extern "C" int rbd_mirror_image_resync(rbd_image_t image) return librbd::api::Mirror<>::image_resync(ictx); } +extern "C" int rbd_mirror_image_create_snapshot(rbd_image_t image, + uint64_t *snap_id) +{ + librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; + return librbd::api::Mirror<>::image_snapshot_create(ictx, snap_id); +} + extern "C" int rbd_mirror_image_get_info(rbd_image_t image, rbd_mirror_image_info_t *mirror_image_info, size_t info_size) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index c0602af974f..2162fa60a3a 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -583,6 +583,7 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_mirror_image_promote(rbd_image_t image, bint force) int rbd_mirror_image_demote(rbd_image_t image) int rbd_mirror_image_resync(rbd_image_t image) + int rbd_mirror_image_create_snapshot(rbd_image_t image, uint64_t *snap_id) int rbd_mirror_image_get_info(rbd_image_t image, rbd_mirror_image_info_t *mirror_image_info, size_t info_size) @@ -4552,6 +4553,23 @@ written." % (self.name, ret, length)) if ret < 0: raise make_ex(ret, 'error to resync image %s' % self.name) + def mirror_image_create_snapshot(self): + """ + Create mirror snapshot. + + :param force: ignore mirror snapshot limit + :type force: bool + :returns: int - the snapshot Id + """ + cdef: + uint64_t snap_id + with nogil: + ret = rbd_mirror_image_create_snapshot(self.image, &snap_id) + if ret < 0: + raise make_ex(ret, 'error creating mirror snapshot for image %s' % + self.name) + return snap_id + def mirror_image_get_info(self): """ Get mirror info for the image. diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 2285a23eae7..d16f5f590f8 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -30,6 +30,8 @@ from rbd import (RBD, Group, Image, ImageNotFound, InvalidArgument, ImageExists, RBD_MIRROR_IMAGE_DISABLED, MIRROR_IMAGE_STATUS_STATE_UNKNOWN, RBD_LOCK_MODE_EXCLUSIVE, RBD_OPERATION_FEATURE_GROUP, RBD_SNAP_NAMESPACE_TYPE_TRASH, + RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY, + RBD_SNAP_NAMESPACE_TYPE_MIRROR_NON_PRIMARY, RBD_IMAGE_MIGRATION_STATE_PREPARED, RBD_CONFIG_SOURCE_CONFIG, RBD_CONFIG_SOURCE_POOL, RBD_CONFIG_SOURCE_IMAGE, RBD_MIRROR_PEER_ATTRIBUTE_NAME_MON_HOST, @@ -2048,6 +2050,50 @@ class TestMirroring(object): for i in range(N): self.rbd.remove(ioctx, image_name + str(i)) + def test_mirror_image_create_snapshot(self): + if self.image.features() & RBD_FEATURE_JOURNALING != 0: + self.image.update_features(RBD_FEATURE_JOURNALING, False) + + assert_raises(InvalidArgument, self.image.mirror_image_create_snapshot) + + peer1_uuid = self.rbd.mirror_peer_add(ioctx, "cluster1", "client") + peer2_uuid = self.rbd.mirror_peer_add(ioctx, "cluster2", "client") + self.rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE) + self.image.mirror_image_enable() + + snap_id = self.image.mirror_image_create_snapshot() + + snaps = list(self.image.list_snaps()) + eq(1, len(snaps)) + snap = snaps[0] + eq(snap['id'], snap_id) + eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY) + eq(False, snap['mirror_primary']['demoted']) + eq(sorted([peer1_uuid, peer2_uuid]), + sorted(snap['mirror_primary']['mirror_peer_uuids'])) + + eq(RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY, + self.image.snap_get_namespace_type(snap_id)) + mirror_snap = self.image.snap_get_mirror_primary_namespace(snap_id) + eq(mirror_snap, snap['mirror_primary']) + + self.image.mirror_image_demote() + + assert_raises(InvalidArgument, self.image.mirror_image_create_snapshot) + + snaps = list(self.image.list_snaps()) + eq(2, len(snaps)) + snap = snaps[0] + eq(snap['id'], snap_id) + eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY) + snap = snaps[1] + eq(snap['namespace'], RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY) + eq(True, snap['mirror_primary']['demoted']) + eq(sorted([peer1_uuid, peer2_uuid]), + sorted(snap['mirror_primary']['mirror_peer_uuids'])) + + self.rbd.mirror_peer_remove(ioctx, peer1_uuid) + self.rbd.mirror_peer_remove(ioctx, peer2_uuid) class TestTrash(object):