From: Jason Dillaman Date: Fri, 28 Apr 2017 18:51:41 +0000 (-0400) Subject: librbd: added trash_get API method to retrieve image status X-Git-Tag: v12.0.3~115^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4939ff707b5a68522fef03f95e39900e84012a0a;p=ceph.git librbd: added trash_get API method to retrieve image status Signed-off-by: Jason Dillaman --- diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 289640a499da..87d04eb44706 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -255,8 +255,14 @@ CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name); CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name, librbd_progress_fn_t cb, void *cbdata); +CEPH_RBD_API int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname, + const char *destname); + CEPH_RBD_API int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay); +CEPH_RBD_API int rbd_trash_get(rados_ioctx_t io, const char *id, + rbd_trash_image_info_t *info); +CEPH_RBD_API void rbd_trash_get_cleanup(rbd_trash_image_info_t *info); CEPH_RBD_API int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries, size_t *num_entries); @@ -268,8 +274,6 @@ CEPH_RBD_API int rbd_trash_remove_with_progress(rados_ioctx_t io, const char *id void *cbdata); CEPH_RBD_API int rbd_trash_restore(rados_ioctx_t io, const char *id, const char *name); -CEPH_RBD_API int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname, - const char *destname); /* pool mirroring */ CEPH_RBD_API int rbd_mirror_mode_get(rados_ioctx_t io_ctx, diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index d774b9d10ae6..f03ca9f36220 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -158,15 +158,16 @@ public: IoCtx& c_ioctx, const char *c_name, ImageOptions& opts); int remove(IoCtx& io_ctx, const char *name); int remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx); + int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname); + int trash_move(IoCtx &io_ctx, const char *name, uint64_t delay); + int trash_get(IoCtx &io_ctx, const char *id, trash_image_info_t *info); int trash_list(IoCtx &io_ctx, std::vector &entries); int trash_remove(IoCtx &io_ctx, const char *image_id, bool force); - int trash_remove_with_progress(IoCtx &io_ctx, const char *image_id, bool force, - ProgressContext &pctx); + int trash_remove_with_progress(IoCtx &io_ctx, const char *image_id, + bool force, ProgressContext &pctx); int trash_restore(IoCtx &io_ctx, const char *id, const char *name); - int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname); - // RBD pool mirroring support functions int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode); int mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode); diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 1168afac7f73..bfdd5fb7fbc1 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -1433,6 +1433,28 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) { return 0; } + int trash_get(IoCtx &io_ctx, const std::string &id, + trash_image_info_t *info) { + CephContext *cct((CephContext *)io_ctx.cct()); + ldout(cct, 20) << __func__ << " " << &io_ctx << dendl; + + cls::rbd::TrashImageSpec spec; + int r = cls_client::trash_get(&io_ctx, id, &spec); + if (r == -ENOENT) { + return r; + } else if (r < 0) { + lderr(cct) << "error retrieving trash entry: " << cpp_strerror(r) + << dendl; + return r; + } + + rbd_trash_image_source_t source = static_cast( + spec.source); + *info = trash_image_info_t{id, spec.name, source, spec.deletion_time.sec(), + spec.deferment_end_time.sec()}; + return 0; + } + int trash_list(IoCtx &io_ctx, vector &entries) { CephContext *cct((CephContext *)io_ctx.cct()); ldout(cct, 20) << "trash_list " << &io_ctx << dendl; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index cf07472b1af0..deeaf9455957 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -143,8 +143,10 @@ namespace librbd { int remove(librados::IoCtx& io_ctx, const std::string &image_name, const std::string &image_id, ProgressContext& prog_ctx, bool force=false, bool from_trash_remove=false); + int trash_move(librados::IoCtx &io_ctx, rbd_trash_image_source_t source, const std::string &image_name, uint64_t delay); + int trash_get(IoCtx &io_ctx, const std::string &id, trash_image_info_t *info); int trash_list(librados::IoCtx &io_ctx, std::vector &entries); int trash_remove(librados::IoCtx &io_ctx, const std::string &image_id, diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index a2180170cf3e..8094433ee5f0 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -184,6 +184,15 @@ void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_statu c_status->up = cpp_status.up; } +void trash_image_info_cpp_to_c(const librbd::trash_image_info_t &cpp_info, + rbd_trash_image_info_t *c_info) { + c_info->id = strdup(cpp_info.id.c_str()); + c_info->name = strdup(cpp_info.name.c_str()); + c_info->source = cpp_info.source; + c_info->deletion_time = cpp_info.deletion_time; + c_info->deferment_end_time = cpp_info.deferment_end_time; +} + struct C_MirrorImageGetInfo : public Context { rbd_mirror_image_info_t *mirror_image_info; Context *on_finish; @@ -551,6 +560,10 @@ namespace librbd { return r; } + int RBD::trash_get(IoCtx &io_ctx, const char *id, trash_image_info_t *info) { + return librbd::trash_get(io_ctx, id, info); + } + int RBD::trash_list(IoCtx &io_ctx, vector &entries) { TracepointProvider::initialize(get_cct(io_ctx)); tracepoint(librbd, trash_list_enter, @@ -2295,6 +2308,26 @@ extern "C" int rbd_trash_move(rados_ioctx_t p, const char *name, return r; } +extern "C" int rbd_trash_get(rados_ioctx_t io, const char *id, + rbd_trash_image_info_t *info) { + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(io, io_ctx); + + librbd::trash_image_info_t cpp_info; + int r = librbd::trash_get(io_ctx, id, &cpp_info); + if (r < 0) { + return r; + } + + trash_image_info_cpp_to_c(cpp_info, info); + return 0; +} + +extern "C" void rbd_trash_get_cleanup(rbd_trash_image_info_t *info) { + free(info->id); + free(info->name); +} + extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries, size_t *num_entries) { librados::IoCtx io_ctx; @@ -2318,12 +2351,7 @@ extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries, int i=0; for (const auto &entry : cpp_entries) { - entries[i].id = strdup(entry.id.c_str()); - entries[i].name = strdup(entry.name.c_str()); - entries[i].source = entry.source; - entries[i].deletion_time = entry.deletion_time; - entries[i].deferment_end_time = entry.deferment_end_time; - i++; + trash_image_info_cpp_to_c(entry, &entries[i++]); } *num_entries = cpp_entries.size(); @@ -2333,8 +2361,7 @@ extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries, extern "C" void rbd_trash_list_cleanup(rbd_trash_image_info_t *entries, size_t num_entries) { for (size_t i=0; i < num_entries; i++) { - free(entries[i].id); - free(entries[i].name); + rbd_trash_get_cleanup(&entries[i]); } } diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 3457fcc0a675..aa212cced86f 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -180,6 +180,9 @@ cdef extern from "rbd/librbd.h" nogil: const char *destname) int rbd_trash_move(rados_ioctx_t io, const char *name, uint64_t delay) + int rbd_trash_get(rados_ioctx_t io, const char *id, + rbd_trash_image_info_t *info) + void rbd_trash_get_cleanup(rbd_trash_image_info_t *info) int rbd_trash_list(rados_ioctx_t io, rbd_trash_image_info_t *trash_entries, size_t *num_entries) void rbd_trash_list_cleanup(rbd_trash_image_info_t *trash_entries, @@ -920,6 +923,49 @@ class RBD(object): if ret != 0: raise make_ex(ret, 'error deleting image from trash') + def trash_get(self, ioctx, image_id): + """ + Retrieve RBD image info from trash + :param ioctx: determines which RADOS pool the image is in + :type ioctx: :class:`rados.Ioctx` + :param image_id: the id of the image to restore + :type image_id: str + :returns: dict - contains the following keys: + + * ``id`` (str) - image id + + * ``name`` (str) - image name + + * ``source`` (str) - source of deletion + + * ``deletion_time`` (datetime) - time of deletion + + * ``deferment_end_time`` (datetime) - time that an image is allowed + to be removed from trash + + :raises: :class:`ImageNotFound` + """ + image_id = cstr(image_id, 'image_id') + cdef: + rados_ioctx_t _ioctx = convert_ioctx(ioctx) + char *_image_id = image_id + rbd_trash_image_info_t c_info + with nogil: + ret = rbd_trash_get(_ioctx, _image_id, &c_info) + if ret != 0: + raise make_ex(ret, 'error restoring image from trash') + + __source_string = ['USER', 'MIRRORING'] + info = { + 'id' : decode_cstr(c_info.id), + 'name' : decode_cstr(c_info.name), + 'source' : __source_string[c_info.source], + 'deletion_time' : datetime.fromtimestamp(c_info.deletion_time), + 'deferment_end_time' : datetime.fromtimestamp(c_info.deferment_end_time) + } + rbd_trash_get_cleanup(&c_info) + return info + def trash_list(self, ioctx): """ Lists all entries from trash. diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 3d2089480922..e00bfba9b1a6 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -5738,6 +5738,11 @@ TEST_F(TestLibRBD, TestTrashMoveAndPurge) { ASSERT_TRUE(image != name); } + librbd::trash_image_info_t info; + ASSERT_EQ(-ENOENT, rbd.trash_get(ioctx, "dummy image id", &info)); + ASSERT_EQ(0, rbd.trash_get(ioctx, image_id.c_str(), &info)); + ASSERT_EQ(image_id, info.id); + std::vector entries; ASSERT_EQ(0, rbd.trash_list(ioctx, entries)); ASSERT_FALSE(entries.empty()); diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 57c35fd82c81..b01b7390bfdf 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -1501,6 +1501,21 @@ class TestTrash(object): RBD().trash_move(ioctx, image_name, 0) RBD().trash_remove(ioctx, image_id) + def test_get(self): + create_image() + with Image(ioctx, image_name) as image: + image_id = image.id() + + RBD().trash_move(ioctx, image_name, 1000) + + info = RBD().trash_get(ioctx, image_id) + eq(image_id, info['id']) + eq(image_name, info['name']) + eq('USER', info['source']) + assert(info['deferment_end_time'] > info['deletion_time']) + + RBD().trash_remove(ioctx, image_id, True) + def test_list(self): create_image() with Image(ioctx, image_name) as image: