]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
librbd: add mirror image snapshot API
authorMykola Golub <mgolub@suse.com>
Thu, 19 Sep 2019 13:07:16 +0000 (14:07 +0100)
committerMykola Golub <mgolub@suse.com>
Tue, 10 Dec 2019 15:45:30 +0000 (15:45 +0000)
Signed-off-by: Mykola Golub <mgolub@suse.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/pybind/test_rbd.py

index 31976d98e9a6d515ab1354d13bddf146978c3c0b..c5bdd8ae838e5c7ba924292a76125a0c0810f424 100644 (file)
@@ -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);
index 5a6b801f6d13bd46a9c1358ebdaf763b204b5fb2..40777b3af8275bf0356329115eda021a9e9f05f8 100644 (file)
@@ -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(
index 2c31c895a156c9dd61ada870fcf67ee48c7ed289..76d0e7915ddfdfe73759a48bc27f22482ee28a96 100644 (file)
@@ -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"
 #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 <boost/algorithm/string/trim.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/scope_exit.hpp>
 #include "json_spirit/json_spirit.h"
 
+#include <algorithm>
+
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
 #define dout_prefix *_dout << "librbd::api::Mirror: " << __func__ << ": "
@@ -1613,6 +1617,18 @@ int Mirror<I>::image_instance_id_list(
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::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<I>::create(
+    ictx, false, false, snap_id, &on_finish);
+  req->send();
+  return on_finish.wait();
+}
+
 } // namespace api
 } // namespace librbd
 
index c7d10662e5fc1ad890b85ac10d633f0eaa7d1b3d..6391b37fb8e20cbd2ac3ef08ee2d87e52699943e 100644 (file)
@@ -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
index 661845ed0b08bae09b66d2641cd5a4355eebc737..5a7c0a5a3a77b1621f8d547675f6df89d4efa0e2 100644 (file)
@@ -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)
index c0602af974f2cfa8bfd2f79fb1ffa013e7b9533c..2162fa60a3a72438fc228739a722ba21fba95cb0 100644 (file)
@@ -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.
index 2285a23eae705a9683494ffbab529fb70b1987c0..d16f5f590f80860c5aabd4ed6c82500b58845158 100644 (file)
@@ -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):