From: Mykola Golub Date: Fri, 15 Apr 2016 05:42:17 +0000 (+0300) Subject: librbd: API to retrieve image mirroring status X-Git-Tag: v11.0.0~795^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a2045d61874f9e418b5b3c3136af4482603c8e7f;p=ceph.git librbd: API to retrieve image mirroring status Signed-off-by: Mykola Golub --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 49ed98e9d7d8..03c85b7185f6 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -113,6 +113,23 @@ typedef struct { bool primary; } rbd_mirror_image_info_t; +typedef enum { + MIRROR_IMAGE_STATUS_STATE_UNKNOWN = 0, + MIRROR_IMAGE_STATUS_STATE_ERROR = 1, + MIRROR_IMAGE_STATUS_STATE_SYNCING = 2, + MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY = 3, + MIRROR_IMAGE_STATUS_STATE_REPLAYING = 4, + MIRROR_IMAGE_STATUS_STATE_STOPPING_REPLAY = 5, + MIRROR_IMAGE_STATUS_STATE_STOPPED = 6, +} rbd_mirror_image_status_state_t; + +typedef struct { + rbd_mirror_image_status_state_t state; + char *description; + time_t last_update; + bool up; +} rbd_mirror_image_status_t; + CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra); /* image options */ @@ -208,6 +225,12 @@ CEPH_RBD_API int rbd_mirror_peer_set_client(rados_ioctx_t io_ctx, CEPH_RBD_API int rbd_mirror_peer_set_cluster(rados_ioctx_t io_ctx, const char *uuid, const char *cluster_name); +CEPH_RBD_API int rbd_mirror_image_status_list(rados_ioctx_t io_ctx, + const char *start, size_t max, char **image_names, + rbd_mirror_image_info_t *images, rbd_mirror_image_status_t *image_statuses, + size_t *len); +CEPH_RBD_API int rbd_mirror_image_status_summary(rados_ioctx_t io_ctx, + rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen); CEPH_RBD_API int rbd_open(rados_ioctx_t io, const char *name, rbd_image_t *image, const char *snap_name); @@ -607,6 +630,8 @@ CEPH_RBD_API int rbd_mirror_image_resync(rbd_image_t image); 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); +CEPH_RBD_API int rbd_mirror_image_get_status(rbd_image_t image, + rbd_mirror_image_status_t *mirror_image_status, size_t info_size); #ifdef __cplusplus } diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index f328c424a24a..3cba391d3ebb 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -60,6 +60,15 @@ namespace librbd { bool primary; } mirror_image_info_t; + typedef rbd_mirror_image_status_state_t mirror_image_status_state_t; + + typedef struct { + mirror_image_status_state_t state; + std::string description; + time_t last_update; + bool up; + } mirror_image_status_t; + typedef rbd_image_info_t image_info_t; class CEPH_RBD_API ProgressContext @@ -132,6 +141,11 @@ public: const std::string &client_name); int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid, const std::string &cluster_name); + int mirror_image_status_list(IoCtx& io_ctx, const std::string &start, + size_t max, std::map *images, + std::map *statuses); + int mirror_image_status_summary(IoCtx& io_ctx, + std::map *states); private: /* We don't allow assignment or copying */ @@ -337,6 +351,8 @@ public: int mirror_image_resync(); int mirror_image_get_info(mirror_image_info_t *mirror_image_info, size_t info_size); + int mirror_image_get_status(mirror_image_status_t *mirror_image_status, + size_t status_size); private: friend class RBD; diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 5276052c5190..4556880161f7 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -2877,6 +2877,43 @@ remove_mirroring_image: return 0; } + int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status, + size_t status_size) { + CephContext *cct = ictx->cct; + ldout(cct, 20) << __func__ << ": ictx=" << ictx << dendl; + if (status_size < sizeof(mirror_image_status_t)) { + return -ERANGE; + } + + cls::rbd::MirrorImageStatus + s(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found"); + + cls::rbd::MirrorImage image; + int r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id, &image); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to retrieve mirroring state: " << cpp_strerror(r) + << dendl; + return r; + } + + if (r == 0) { + r = cls_client::mirror_image_status_get(&ictx->md_ctx, + image.global_image_id, &s); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "failed to retrieve image mirror status: " + << cpp_strerror(r) << dendl; + return r; + } + } + + *status = mirror_image_status_t{ + static_cast(s.state), + s.description, + s.last_update.sec(), + s.up}; + return 0; + } + int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) { CephContext *cct = reinterpret_cast(io_ctx.cct()); ldout(cct, 20) << __func__ << dendl; @@ -3242,6 +3279,80 @@ remove_mirroring_image: return 0; } + int mirror_image_status_list(IoCtx& io_ctx, const std::string &start, + size_t max, std::map *images, + std::map *statuses) { + CephContext *cct = reinterpret_cast(io_ctx.cct()); + int r; + + map id_to_name; + { + map name_to_id; + r = list_images_v2(io_ctx, name_to_id); + if (r < 0) { + return r; + } + for (auto it : name_to_id) { + id_to_name[it.second] = it.first; + } + } + + map images_; + map statuses_; + + r = librbd::cls_client::mirror_image_status_list(&io_ctx, start, max, + &images_, &statuses_); + if (r < 0) { + lderr(cct) << "Failed to list mirror image statuses: " + << cpp_strerror(r) << dendl; + return r; + } + + cls::rbd::MirrorImageStatus + unknown_status(cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "status not found"); + + for (auto it = images_.begin(); it != images_.end(); ++it) { + auto &image_id = it->first; + auto &info = it->second; + auto &image_name = id_to_name[image_id]; + if (image_name.empty()) { + lderr(cct) << "Failed to find image name for image " << image_id + << ", using image id as name" << dendl; + image_name = image_id; + } + (*images)[image_name] = mirror_image_info_t{ + info.global_image_id, + static_cast(info.state), + false}; // XXX: To set "primary" properly would require additional call. + auto s_it = statuses_.find(image_id); + auto &s = s_it != statuses_.end() ? s_it->second : unknown_status; + (*statuses)[image_name] = mirror_image_status_t{ + static_cast(s.state), + s.description, + s.last_update.sec(), + s.up}; + } + + return 0; + } + + int mirror_image_status_summary(IoCtx& io_ctx, + std::map *states) { + CephContext *cct = reinterpret_cast(io_ctx.cct()); + + std::map states_; + int r = cls_client::mirror_image_status_get_summary(&io_ctx, &states_); + if (r < 0) { + lderr(cct) << "Failed to get mirror status summary: " + << cpp_strerror(r) << dendl; + return r; + } + for (auto &s : states_) { + (*states)[static_cast(s.first)] = s.second; + } + return 0; + } + void rbd_req_cb(completion_t cb, void *arg) { AioObjectRequest *req = reinterpret_cast(arg); diff --git a/src/librbd/internal.h b/src/librbd/internal.h index c2413f4e0695..c58c5f2c3d27 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -189,6 +189,11 @@ namespace librbd { const std::string &client_name); int mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid, const std::string &cluster_name); + int mirror_image_status_list(IoCtx& io_ctx, const std::string &start, + size_t max, std::map *images, + std::map *statuses); + int mirror_image_status_summary(IoCtx& io_ctx, + std::map *states); int mirror_image_enable(ImageCtx *ictx); int mirror_image_disable(ImageCtx *ictx, bool force); @@ -197,6 +202,8 @@ namespace librbd { int mirror_image_resync(ImageCtx *ictx); int mirror_image_get_info(ImageCtx *ictx, mirror_image_info_t *mirror_image_info, size_t info_size); + int mirror_image_get_status(ImageCtx *ictx, mirror_image_status_t *status, + size_t status_size); } #endif diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 0cc3f9521650..339bbf367f6d 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -132,6 +132,21 @@ struct C_CloseComplete : public Context { } }; +void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info, + rbd_mirror_image_info_t *c_info) { + c_info->global_id = strdup(cpp_info.global_id.c_str()); + c_info->state = cpp_info.state; + c_info->primary = cpp_info.primary; +} + +void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_status, + rbd_mirror_image_status_t *c_status) { + c_status->state = cpp_status.state; + c_status->description = strdup(cpp_status.description.c_str()); + c_status->last_update = cpp_status.last_update; + c_status->up = cpp_status.up; +} + } // anonymous namespace namespace librbd { @@ -411,6 +426,18 @@ namespace librbd { return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name); } + int RBD::mirror_image_status_list(IoCtx& io_ctx, const std::string &start, + size_t max, std::map *images, + std::map *statuses) { + return librbd::mirror_image_status_list(io_ctx, start, max, images, + statuses); + } + + int RBD::mirror_image_status_summary(IoCtx& io_ctx, + std::map *states) { + return librbd::mirror_image_status_summary(io_ctx, states); + } + RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb) { pc = reinterpret_cast(librbd::AioCompletion::create( @@ -1258,6 +1285,13 @@ namespace librbd { return librbd::mirror_image_get_info(ictx, mirror_image_info, info_size); } + int Image::mirror_image_get_status(mirror_image_status_t *mirror_image_status, + size_t status_size) { + ImageCtx *ictx = (ImageCtx *)ctx; + return librbd::mirror_image_get_status(ictx, mirror_image_status, + status_size); + } + } // namespace librbd extern "C" void rbd_version(int *major, int *minor, int *extra) @@ -1425,6 +1459,58 @@ extern "C" int rbd_mirror_peer_set_cluster(rados_ioctx_t p, const char *uuid, return librbd::mirror_peer_set_cluster(io_ctx, uuid, cluster_name); } +extern "C" int rbd_mirror_image_status_list(rados_ioctx_t p, const char *start, + size_t max, char **image_names, rbd_mirror_image_info_t *images, + rbd_mirror_image_status_t *statuses, size_t *len) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(p, io_ctx); + std::map cpp_images; + std::map cpp_statuses; + + int r = librbd::mirror_image_status_list(io_ctx, start, max, &cpp_images, + &cpp_statuses); + if (r < 0) { + return r; + } + + size_t i = 0; + for (auto &it : cpp_images) { + assert(i < max); + const std::string &image_name = it.first; + image_names[i] = strdup(image_name.c_str()); + mirror_image_info_cpp_to_c(it.second, &images[i]); + mirror_image_status_cpp_to_c(cpp_statuses[image_name], &statuses[i]); + i++; + } + *len = i; + return 0; +} + +extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p, + rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) { + + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(p, io_ctx); + + std::map states_; + int r = librbd::mirror_image_status_summary(io_ctx, &states_); + if (r < 0) { + return r; + } + + size_t i = 0; + for (auto &it : states_) { + if (i == *maxlen) { + return -ERANGE; + } + states[i] = it.first; + counts[i] = it.second; + i++; + } + *maxlen = i; + return 0; +} + /* images */ extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size) { @@ -2628,9 +2714,24 @@ extern "C" int rbd_mirror_image_get_info(rbd_image_t image, return r; } - mirror_image_info->global_id = strdup(cpp_mirror_image.global_id.c_str()); - mirror_image_info->state = cpp_mirror_image.state; - mirror_image_info->primary = cpp_mirror_image.primary; + mirror_image_info_cpp_to_c(cpp_mirror_image, mirror_image_info); + return 0; +} + +extern "C" int rbd_mirror_image_get_status(rbd_image_t image, + rbd_mirror_image_status_t *status, + size_t status_size) +{ + librbd::ImageCtx *ictx = (librbd::ImageCtx *)image; + + librbd::mirror_image_status_t cpp_status; + int r = librbd::mirror_image_get_status(ictx, &cpp_status, + sizeof(cpp_status)); + if (r < 0) { + return r; + } + + mirror_image_status_cpp_to_c(cpp_status, status); return 0; } diff --git a/src/test/librbd/test_mirroring.cc b/src/test/librbd/test_mirroring.cc index e7ccf3f8473c..75514dd0e888 100644 --- a/src/test/librbd/test_mirroring.cc +++ b/src/test/librbd/test_mirroring.cc @@ -68,6 +68,10 @@ public: ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); ASSERT_EQ(mirror_state, mirror_image.state); + librbd::mirror_image_status_t status; + ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); + ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -93,17 +97,42 @@ public: ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); ASSERT_EQ(mirror_state, mirror_image.state); + librbd::mirror_image_status_t status; + ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); + ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); } + void check_mirroring_status(size_t *images_count) { + std::map images; + std::map statuses; + ASSERT_EQ(0, m_rbd.mirror_image_status_list(m_ioctx, "", 4096, &images, + &statuses)); + ASSERT_EQ(images.size(), statuses.size()); + + std::map states; + ASSERT_EQ(0, m_rbd.mirror_image_status_summary(m_ioctx, &states)); + size_t states_count = 0; + for (auto &s : states) { + states_count += s.second; + } + ASSERT_EQ(images.size(), states_count); + + *images_count = images.size(); + } + void check_mirroring_on_create(uint64_t features, rbd_mirror_mode_t mirror_mode, rbd_mirror_image_state_t mirror_state) { ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, mirror_mode)); + size_t mirror_images_count = 0; + check_mirroring_status(&mirror_images_count); + int order = 20; ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 4096, features, &order)); librbd::Image image; @@ -113,9 +142,25 @@ public: ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); ASSERT_EQ(mirror_state, mirror_image.state); + librbd::mirror_image_status_t status; + ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); + ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + + size_t mirror_images_new_count = 0; + check_mirroring_status(&mirror_images_new_count); + if (mirror_mode == RBD_MIRROR_MODE_POOL && + mirror_state == RBD_MIRROR_IMAGE_ENABLED) { + ASSERT_EQ(mirror_images_new_count, mirror_images_count + 1); + } else { + ASSERT_EQ(mirror_images_new_count, mirror_images_count); + } + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); + + check_mirroring_status(&mirror_images_new_count); + ASSERT_EQ(mirror_images_new_count, mirror_images_count); } void check_mirroring_on_update_features(uint64_t init_features, @@ -141,6 +186,10 @@ public: ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); ASSERT_EQ(mirror_state, mirror_image.state); + librbd::mirror_image_status_t status; + ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); + ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str())); ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED)); @@ -180,6 +229,10 @@ public: ASSERT_EQ(0, image.mirror_image_get_info(&mirror_image, sizeof(mirror_image))); ASSERT_EQ(mirror_state, mirror_image.state); + librbd::mirror_image_status_t status; + ASSERT_EQ(0, image.mirror_image_get_status(&status, sizeof(status))); + ASSERT_EQ(MIRROR_IMAGE_STATUS_STATE_UNKNOWN, status.state); + ASSERT_EQ(0, image.close()); ASSERT_EQ(0, m_rbd.remove(m_ioctx, img_name_str.c_str())); }