cls_method_handle_t h_old_snapshot_add;
cls_method_handle_t h_old_snapshot_remove;
cls_method_handle_t h_old_snapshot_rename;
+cls_method_handle_t h_mirror_uuid_get;
+cls_method_handle_t h_mirror_uuid_set;
cls_method_handle_t h_mirror_mode_get;
cls_method_handle_t h_mirror_mode_set;
cls_method_handle_t h_mirror_peer_list;
return 0;
}
+static int remove_key(cls_method_context_t hctx, const string &key) {
+ int r = cls_cxx_map_remove_key(hctx, key);
+ if (r < 0 && r != -ENOENT) {
+ CLS_ERR("failed to remove key: %s", key.c_str());
+ return r;
+ }
+ return 0;
+}
+
static bool is_valid_id(const string &id) {
if (!id.size())
return false;
namespace mirror {
+static const std::string UUID("mirror_uuid");
static const std::string MODE("mirror_mode");
static const std::string PEER_KEY_PREFIX("mirror_peer_");
static const std::string IMAGE_KEY_PREFIX("image_");
return IMAGE_KEY_PREFIX + image_id;
}
+int uuid_get(cls_method_context_t hctx, std::string *mirror_uuid) {
+ bufferlist mirror_uuid_bl;
+ int r = cls_cxx_map_get_val(hctx, mirror::UUID, &mirror_uuid_bl);
+ if (r < 0) {
+ if (r != -ENOENT) {
+ CLS_ERR("error reading mirror uuid: %s", cpp_strerror(r).c_str());
+ }
+ return r;
+ }
+
+ *mirror_uuid = std::string(mirror_uuid_bl.c_str(), mirror_uuid_bl.length());
+ return 0;
+}
+
int read_peers(cls_method_context_t hctx,
std::vector<cls::rbd::MirrorPeer> *peers) {
std::string last_read = PEER_KEY_PREFIX;
} // namespace mirror
+/**
+ * Input:
+ * none
+ *
+ * Output:
+ * @param uuid (std::string)
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_uuid_get(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string mirror_uuid;
+ int r = mirror::uuid_get(hctx, &mirror_uuid);
+ if (r < 0) {
+ return r;
+ }
+
+ ::encode(mirror_uuid, *out);
+ return 0;
+}
+
+/**
+ * Input:
+ * @param mirror_uuid (std::string)
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ */
+int mirror_uuid_set(cls_method_context_t hctx, bufferlist *in,
+ bufferlist *out) {
+ std::string mirror_uuid;
+ try {
+ bufferlist::iterator bl_it = in->begin();
+ ::decode(mirror_uuid, bl_it);
+ } catch (const buffer::error &err) {
+ return -EINVAL;
+ }
+
+ if (mirror_uuid.empty()) {
+ CLS_ERR("cannot set empty mirror uuid");
+ return -EINVAL;
+ }
+
+ uint32_t mirror_mode;
+ int r = read_key(hctx, mirror::MODE, &mirror_mode);
+ if (r < 0 && r != -ENOENT) {
+ return r;
+ } else if (r == 0 && mirror_mode != cls::rbd::MIRROR_MODE_DISABLED) {
+ CLS_ERR("cannot set mirror uuid while mirroring enabled");
+ return -EINVAL;
+ }
+
+ bufferlist mirror_uuid_bl;
+ mirror_uuid_bl.append(mirror_uuid);
+ r = cls_cxx_map_set_val(hctx, mirror::UUID, &mirror_uuid_bl);
+ if (r < 0) {
+ CLS_ERR("failed to set mirror uuid");
+ return r;
+ }
+ return 0;
+}
+
/**
* Input:
* none
int r;
if (enabled) {
+ std::string mirror_uuid;
+ r = mirror::uuid_get(hctx, &mirror_uuid);
+ if (r == -ENOENT) {
+ return -EINVAL;
+ } else if (r < 0) {
+ return r;
+ }
+
bufferlist bl;
::encode(mirror_mode_decode, bl);
return -EBUSY;
}
- r = cls_cxx_map_remove_key(hctx, mirror::MODE);
- if (r < 0 && r != -ENOENT) {
- CLS_ERR("error disabling mirroring: %s", cpp_strerror(r).c_str());
+ r = remove_key(hctx, mirror::MODE);
+ if (r < 0) {
+ return r;
+ }
+
+ r = remove_key(hctx, mirror::UUID);
+ if (r < 0) {
return r;
}
}
mirror_mode_decode == cls::rbd::MIRROR_MODE_DISABLED) {
CLS_ERR("mirroring must be enabled on the pool");
return -EINVAL;
+ } else if (!mirror_peer.is_valid()) {
+ CLS_ERR("mirror peer is not valid");
+ return -EINVAL;
+ }
+
+ std::string mirror_uuid;
+ r = mirror::uuid_get(hctx, &mirror_uuid);
+ if (mirror_peer.uuid == mirror_uuid) {
+ CLS_ERR("peer uuid '%s' matches pool mirroring uuid",
+ mirror_uuid.c_str());
+ return -EINVAL;
}
std::vector<cls::rbd::MirrorPeer> peers;
old_snapshot_rename, &h_old_snapshot_rename);
/* methods for the rbd_mirroring object */
+ cls_register_cxx_method(h_class, "mirror_uuid_get", CLS_METHOD_RD,
+ mirror_uuid_get, &h_mirror_uuid_get);
+ cls_register_cxx_method(h_class, "mirror_uuid_set",
+ CLS_METHOD_RD | CLS_METHOD_WR,
+ mirror_uuid_set, &h_mirror_uuid_set);
cls_register_cxx_method(h_class, "mirror_mode_get", CLS_METHOD_RD,
mirror_mode_get, &h_mirror_mode_get);
cls_register_cxx_method(h_class, "mirror_mode_set",
std::vector<cls::rbd::MirrorPeer> peers;
ASSERT_EQ(-ENOENT, mirror_peer_list(&ioctx, &peers));
+ std::string uuid;
+ ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, "uuid1", "cluster1", "client"));
cls::rbd::MirrorMode mirror_mode;
ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED, mirror_mode);
+ ASSERT_EQ(-EINVAL, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_IMAGE));
+ ASSERT_EQ(-EINVAL, mirror_uuid_set(&ioctx, ""));
+ ASSERT_EQ(0, mirror_uuid_set(&ioctx, "mirror-uuid"));
+ ASSERT_EQ(0, mirror_uuid_get(&ioctx, &uuid));
+ ASSERT_EQ("mirror-uuid", uuid);
+
ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_IMAGE));
ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
ASSERT_EQ(cls::rbd::MIRROR_MODE_IMAGE, mirror_mode);
+ ASSERT_EQ(-EINVAL, mirror_uuid_set(&ioctx, "new-mirror-uuid"));
+
ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_POOL));
ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
ASSERT_EQ(cls::rbd::MIRROR_MODE_POOL, mirror_mode);
+ ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, "mirror-uuid", "cluster1", "client"));
ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid1", "cluster1", "client"));
ASSERT_EQ(0, mirror_peer_add(&ioctx, "uuid2", "cluster2", "admin"));
ASSERT_EQ(-ESTALE, mirror_peer_add(&ioctx, "uuid2", "cluster3", "foo"));
ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_DISABLED));
ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED, mirror_mode);
+ ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
}
TEST_F(TestClsRbd, mirror_image) {