From: Mykola Golub Date: Sat, 27 Oct 2018 16:25:36 +0000 (+0300) Subject: cls/rbd: new methods to get image mirror instance info X-Git-Tag: v14.1.0~992^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=31453519eef64b4228838807f94c4850331dd898;p=ceph.git cls/rbd: new methods to get image mirror instance info Signed-off-by: Mykola Golub --- diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index 2c4c13ea0083..843223577971 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -4993,6 +4993,93 @@ int image_status_remove_down(cls_method_context_t hctx) { return 0; } +int image_instance_get(cls_method_context_t hctx, + const string &global_image_id, + const std::set &watchers, + entity_inst_t *instance) { + bufferlist bl; + int r = cls_cxx_map_get_val(hctx, status_global_key(global_image_id), &bl); + if (r < 0) { + if (r != -ENOENT) { + CLS_ERR("error reading status for mirrored image, global id '%s': '%s'", + global_image_id.c_str(), cpp_strerror(r).c_str()); + } + return r; + } + + MirrorImageStatusOnDisk ondisk_status; + try { + auto it = bl.cbegin(); + decode(ondisk_status, it); + } catch (const buffer::error &err) { + CLS_ERR("could not decode status for mirrored image, global id '%s'", + global_image_id.c_str()); + return -EIO; + } + + if (watchers.find(ondisk_status.origin) == watchers.end()) { + return -ESTALE; + } + + *instance = ondisk_status.origin; + return 0; +} + +int image_instance_list(cls_method_context_t hctx, + const std::string &start_after, + uint64_t max_return, + map *instances) { + std::string last_read = image_key(start_after); + int max_read = RBD_MAX_KEYS_READ; + bool more = true; + + std::set watchers; + int r = list_watchers(hctx, &watchers); + if (r < 0) { + return r; + } + + while (more && instances->size() < max_return) { + std::map vals; + CLS_LOG(20, "last_read = '%s'", last_read.c_str()); + r = cls_cxx_map_get_vals(hctx, last_read, IMAGE_KEY_PREFIX, max_read, &vals, + &more); + if (r < 0) { + CLS_ERR("error reading mirror image directory by name: %s", + cpp_strerror(r).c_str()); + return r; + } + + for (auto it = vals.begin(); it != vals.end() && + instances->size() < max_return; ++it) { + const std::string &image_id = it->first.substr(IMAGE_KEY_PREFIX.size()); + cls::rbd::MirrorImage mirror_image; + auto iter = it->second.cbegin(); + try { + decode(mirror_image, iter); + } catch (const buffer::error &err) { + CLS_ERR("could not decode mirror image payload of image '%s'", + image_id.c_str()); + return -EIO; + } + + entity_inst_t instance; + r = image_instance_get(hctx, mirror_image.global_image_id, watchers, + &instance); + if (r < 0) { + continue; + } + + (*instances)[image_id] = instance; + } + if (!vals.empty()) { + last_read = vals.rbegin()->first; + } + } + + return 0; +} + int instances_list(cls_method_context_t hctx, std::vector *instance_ids) { std::string last_read = INSTANCE_KEY_PREFIX; @@ -5766,6 +5853,73 @@ int mirror_image_status_remove_down(cls_method_context_t hctx, bufferlist *in, return 0; } +/** + * Input: + * @param global_image_id (std::string) + * + * Output: + * @param entity_inst_t - instance + * @returns 0 on success, negative error code on failure + */ +int mirror_image_instance_get(cls_method_context_t hctx, bufferlist *in, + bufferlist *out) { + string global_image_id; + try { + auto it = in->cbegin(); + decode(global_image_id, it); + } catch (const buffer::error &err) { + return -EINVAL; + } + + std::set watchers; + int r = mirror::list_watchers(hctx, &watchers); + if (r < 0) { + return r; + } + + entity_inst_t instance; + r = mirror::image_instance_get(hctx, global_image_id, watchers, &instance); + if (r < 0) { + return r; + } + + encode(instance, *out, cls_get_features(hctx)); + return 0; +} + +/** + * Input: + * @param start_after which name to begin listing after + * (use the empty string to start at the beginning) + * @param max_return the maximum number of names to list + * + * Output: + * @param std::map: image id to instance map + * @returns 0 on success, negative error code on failure + */ +int mirror_image_instance_list(cls_method_context_t hctx, bufferlist *in, + bufferlist *out) { + std::string start_after; + uint64_t max_return; + try { + auto iter = in->cbegin(); + decode(start_after, iter); + decode(max_return, iter); + } catch (const buffer::error &err) { + return -EINVAL; + } + + map instances; + int r = mirror::image_instance_list(hctx, start_after, max_return, + &instances); + if (r < 0) { + return r; + } + + encode(instances, *out, cls_get_features(hctx)); + return 0; +} + /** * Input: * none @@ -7190,6 +7344,8 @@ CLS_INIT(rbd) cls_method_handle_t h_mirror_image_status_list; cls_method_handle_t h_mirror_image_status_get_summary; cls_method_handle_t h_mirror_image_status_remove_down; + cls_method_handle_t h_mirror_image_instance_get; + cls_method_handle_t h_mirror_image_instance_list; cls_method_handle_t h_mirror_instances_list; cls_method_handle_t h_mirror_instances_add; cls_method_handle_t h_mirror_instances_remove; @@ -7513,6 +7669,12 @@ CLS_INIT(rbd) CLS_METHOD_RD | CLS_METHOD_WR, mirror_image_status_remove_down, &h_mirror_image_status_remove_down); + cls_register_cxx_method(h_class, "mirror_image_instance_get", CLS_METHOD_RD, + mirror_image_instance_get, + &h_mirror_image_instance_get); + cls_register_cxx_method(h_class, "mirror_image_instance_list", CLS_METHOD_RD, + mirror_image_instance_list, + &h_mirror_image_instance_list); cls_register_cxx_method(h_class, "mirror_instances_list", CLS_METHOD_RD, mirror_instances_list, &h_mirror_instances_list); cls_register_cxx_method(h_class, "mirror_instances_add", diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index 8dca588fd7f8..78bd6f013d59 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -2170,6 +2170,84 @@ void mirror_image_status_remove_down(librados::ObjectWriteOperation *op) { op->exec("rbd", "mirror_image_status_remove_down", bl); } +int mirror_image_instance_get(librados::IoCtx *ioctx, + const std::string &global_image_id, + entity_inst_t *instance) { + librados::ObjectReadOperation op; + mirror_image_instance_get_start(&op, global_image_id); + + bufferlist out_bl; + int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl); + if (r < 0) { + return r; + } + + auto iter = out_bl.cbegin(); + r = mirror_image_instance_get_finish(&iter, instance); + if (r < 0) { + return r; + } + return 0; +} + +void mirror_image_instance_get_start(librados::ObjectReadOperation *op, + const std::string &global_image_id) { + bufferlist bl; + encode(global_image_id, bl); + op->exec("rbd", "mirror_image_instance_get", bl); +} + +int mirror_image_instance_get_finish(bufferlist::const_iterator *iter, + entity_inst_t *instance) { + try { + decode(*instance, *iter); + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; +} + +int mirror_image_instance_list( + librados::IoCtx *ioctx, const std::string &start, uint64_t max_return, + std::map *instances) { + librados::ObjectReadOperation op; + mirror_image_instance_list_start(&op, start, max_return); + + bufferlist out_bl; + int r = ioctx->operate(RBD_MIRRORING, &op, &out_bl); + if (r < 0) { + return r; + } + + auto iter = out_bl.cbegin(); + r = mirror_image_instance_list_finish(&iter, instances); + if (r < 0) { + return r; + } + return 0; +} + +void mirror_image_instance_list_start(librados::ObjectReadOperation *op, + const std::string &start, + uint64_t max_return) { + bufferlist bl; + encode(start, bl); + encode(max_return, bl); + op->exec("rbd", "mirror_image_instance_list", bl); +} + +int mirror_image_instance_list_finish( + bufferlist::const_iterator *iter, + std::map *instances) { + instances->clear(); + try { + decode(*instances, *iter); + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; +} + void mirror_instances_list_start(librados::ObjectReadOperation *op) { bufferlist bl; op->exec("rbd", "mirror_instances_list", bl); diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 5f476c5f1d2e..833d58bad930 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -474,6 +474,22 @@ int mirror_image_status_get_summary_finish(bufferlist::const_iterator *iter, int mirror_image_status_remove_down(librados::IoCtx *ioctx); void mirror_image_status_remove_down(librados::ObjectWriteOperation *op); +int mirror_image_instance_get(librados::IoCtx *ioctx, + const std::string &global_image_id, + entity_inst_t *instance); +void mirror_image_instance_get_start(librados::ObjectReadOperation *op, + const std::string &global_image_id); +int mirror_image_instance_get_finish(bufferlist::const_iterator *iter, + entity_inst_t *instance); +int mirror_image_instance_list(librados::IoCtx *ioctx, + const std::string &start, uint64_t max_return, + std::map *instances); +void mirror_image_instance_list_start(librados::ObjectReadOperation *op, + const std::string &start, + uint64_t max_return); +int mirror_image_instance_list_finish(bufferlist::const_iterator *iter, + std::map *instances); + void mirror_instances_list_start(librados::ObjectReadOperation *op); int mirror_instances_list_finish(bufferlist::const_iterator *iter, std::vector *instance_ids); diff --git a/src/test/cls_rbd/test_cls_rbd.cc b/src/test/cls_rbd/test_cls_rbd.cc index 1783866dc946..756d64d31beb 100644 --- a/src/test/cls_rbd/test_cls_rbd.cc +++ b/src/test/cls_rbd/test_cls_rbd.cc @@ -1638,7 +1638,7 @@ TEST_F(TestClsRbd, mirror_image_status) { explicit WatchCtx(librados::IoCtx *ioctx) : m_ioctx(ioctx) {} void handle_notify(uint64_t notify_id, uint64_t cookie, - uint64_t notifier_id, bufferlist& bl_) override { + uint64_t notifier_id, bufferlist& bl_) override { bufferlist bl; m_ioctx->notify_ack(RBD_MIRRORING, notify_id, cookie, bl); } @@ -1648,13 +1648,17 @@ TEST_F(TestClsRbd, mirror_image_status) { map images; map statuses; std::map states; + std::map instances; cls::rbd::MirrorImageStatus read_status; + entity_inst_t read_instance; uint64_t watch_handle; librados::IoCtx ioctx; ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx)); ioctx.remove(RBD_MIRRORING); + int64_t instance_id = librados::Rados(ioctx).get_instance_id(); + // Test list fails on nonexistent RBD_MIRRORING object ASSERT_EQ(-ENOENT, mirror_image_status_list(&ioctx, "", 1024, &images, @@ -1694,10 +1698,18 @@ TEST_F(TestClsRbd, mirror_image_status) { ASSERT_EQ(1U, states.size()); ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]); + // Test get instance return -ESTALE due to down. + + ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance)); + instances.clear(); + ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances)); + ASSERT_TRUE(instances.empty()); + // Test remove_down removes stale statuses ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx)); ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status)); + ASSERT_EQ(-ENOENT, mirror_image_instance_get(&ioctx, "uuid1", &read_instance)); ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses)); ASSERT_EQ(3U, images.size()); ASSERT_TRUE(statuses.empty()); @@ -1734,6 +1746,16 @@ TEST_F(TestClsRbd, mirror_image_status) { ASSERT_EQ(statuses["image_id2"], status2); ASSERT_EQ(statuses["image_id3"], status3); + read_instance = {}; + ASSERT_EQ(0, mirror_image_instance_get(&ioctx, "uuid1", &read_instance)); + ASSERT_EQ(read_instance.name.num(), instance_id); + instances.clear(); + ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances)); + ASSERT_EQ(3U, instances.size()); + ASSERT_EQ(instances["image_id1"].name.num(), instance_id); + ASSERT_EQ(instances["image_id2"].name.num(), instance_id); + ASSERT_EQ(instances["image_id3"].name.num(), instance_id); + ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx)); ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status)); ASSERT_EQ(read_status, status1); @@ -1819,6 +1841,11 @@ TEST_F(TestClsRbd, mirror_image_status) { ASSERT_EQ(1U, states.size()); ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]); + ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance)); + instances.clear(); + ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances)); + ASSERT_TRUE(instances.empty()); + ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx)); ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status));