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);
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(
#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__ << ": "
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
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
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;
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)
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)
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.
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,
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):