From d25a2073b1938d7571b984bc39ecf75d84c44cf9 Mon Sep 17 00:00:00 2001 From: Ramana Raja Date: Sun, 20 Oct 2024 19:50:04 -0400 Subject: [PATCH] librbd: add python and C bindings for group_list2 ... that lists IDs and names of groups in a pool. Signed-off-by: Ramana Raja --- src/include/rbd/librbd.h | 10 +++++++ src/librbd/librbd.cc | 46 +++++++++++++++++++++++++++++++++ src/pybind/rbd/c_rbd.pxd | 9 +++++++ src/pybind/rbd/rbd.pyx | 56 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) diff --git a/src/include/rbd/librbd.h b/src/include/rbd/librbd.h index 900e60c4fff9a..079710f5dcfaf 100644 --- a/src/include/rbd/librbd.h +++ b/src/include/rbd/librbd.h @@ -292,6 +292,11 @@ typedef struct { int64_t pool; } rbd_group_info_t; +typedef struct { + char *id; + char *name; +} rbd_group_spec_t; + typedef enum { RBD_GROUP_SNAP_STATE_INCOMPLETE, RBD_GROUP_SNAP_STATE_COMPLETE @@ -1507,12 +1512,17 @@ CEPH_RBD_API int rbd_aio_mirror_image_create_snapshot(rbd_image_t image, CEPH_RBD_API int rbd_group_create(rados_ioctx_t p, const char *name); CEPH_RBD_API int rbd_group_remove(rados_ioctx_t p, const char *name); CEPH_RBD_API int rbd_group_list(rados_ioctx_t p, char *names, size_t *size); +CEPH_RBD_API int rbd_group_list2(rados_ioctx_t p, rbd_group_spec_t *groups, + size_t *size); CEPH_RBD_API int rbd_group_get_id(rados_ioctx_t p, const char *group_name, char *group_id, size_t *size); CEPH_RBD_API int rbd_group_rename(rados_ioctx_t p, const char *src_name, const char *dest_name); CEPH_RBD_API int rbd_group_info_cleanup(rbd_group_info_t *group_info, size_t group_info_size); +CEPH_RBD_API int rbd_group_spec_list_cleanup(rbd_group_spec_t *groups, + size_t group_spec_size, + size_t num_groups); /** * Register an image metadata change watcher. diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 88df7d089e31e..51cfa3db39269 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -7425,6 +7425,36 @@ extern "C" int rbd_group_list(rados_ioctx_t p, char *names, size_t *size) return (int)expected_size; } +extern "C" int rbd_group_list2(rados_ioctx_t p, rbd_group_spec_t *groups, + size_t *size) +{ + librados::IoCtx io_ctx; + librados::IoCtx::from_rados_ioctx_t(p, io_ctx); + + std::map cpp_group_name_to_id_map; + int r = librbd::api::Group<>::list(io_ctx, &cpp_group_name_to_id_map); + if (r < 0) { + return r; + } + + size_t expected_size = cpp_group_name_to_id_map.size(); + if (*size < expected_size) { + *size = expected_size; + return -ERANGE; + } + + *size = expected_size; + // FIPS zeroization audit 20191117: this memset is not security related. + memset(groups, 0, sizeof(*groups) * *size); + size_t idx = 0; + for (const auto& [group_name, group_id] : cpp_group_name_to_id_map) { + groups[idx].name = strdup(group_name.c_str()); + groups[idx].id = strdup(group_id.c_str()); + idx++; + } + return 0; +} + extern "C" int rbd_group_rename(rados_ioctx_t p, const char *src_name, const char *dest_name) { @@ -7600,6 +7630,22 @@ extern "C" int rbd_group_info_cleanup(rbd_group_info_t *group_info, return 0; } +extern "C" int rbd_group_spec_list_cleanup(rbd_group_spec_t *groups, + size_t group_spec_size, + size_t num_groups) +{ + if (group_spec_size != sizeof(rbd_group_spec_t)) { + return -ERANGE; + } + + for (size_t i = 0; i < num_groups; ++i) { + free(groups[i].id); + free(groups[i].name); + } + + return 0; +} + extern "C" int rbd_group_image_list_cleanup(rbd_group_image_info_t *images, size_t group_image_info_size, size_t len) { diff --git a/src/pybind/rbd/c_rbd.pxd b/src/pybind/rbd/c_rbd.pxd index 790fcd89e45fe..b8ee4d9f59822 100644 --- a/src/pybind/rbd/c_rbd.pxd +++ b/src/pybind/rbd/c_rbd.pxd @@ -112,6 +112,10 @@ cdef extern from "rbd/librbd.h" nogil: char *name int64_t pool + ctypedef struct rbd_group_spec_t: + char *id + char *name + ctypedef struct rbd_image_spec_t: char *id char *name @@ -731,6 +735,8 @@ cdef extern from "rbd/librbd.h" nogil: int rbd_group_create(rados_ioctx_t p, const char *name) int rbd_group_remove(rados_ioctx_t p, const char *name) int rbd_group_list(rados_ioctx_t p, char *names, size_t *size) + int rbd_group_list2(rados_ioctx_t p, rbd_group_spec_t *groups, + size_t *size); int rbd_group_get_id(rados_ioctx_t p, const char *group_name, char *group_id, size_t *size) int rbd_group_rename(rados_ioctx_t p, const char *src, const char *dest) @@ -750,6 +756,9 @@ cdef extern from "rbd/librbd.h" nogil: size_t *image_size) void rbd_group_image_list_cleanup(rbd_group_image_info_t *images, size_t group_image_info_size, size_t len) + int rbd_group_spec_list_cleanup(rbd_group_spec_t *groups, + size_t group_spec_size, + size_t num_groups); int rbd_group_snap_create2(rados_ioctx_t group_p, const char *group_name, const char *snap_name, uint32_t flags) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 342e0506c1426..a98c10b98fb2e 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -1969,6 +1969,16 @@ class RBD(object): finally: free(c_names) + def group_list2(self, ioctx): + """ + Iterate over the groups in the pool. + + :param ioctx: determines which RADOS pool the group is in + :type ioctx: :class:`rados.Ioctx` + :returns: :class:`GroupIterator` + """ + return GroupIterator(ioctx) + def group_rename(self, ioctx, src, dest): """ Rename an RBD group. @@ -6119,6 +6129,52 @@ cdef class ConfigImageIterator(object): rbd_config_image_list_cleanup(self.options, self.num_options) free(self.options) +cdef class GroupIterator(object): + """ + Iterator over RBD groups in a pool + + Yields a dictionary containing information about the groups + + Keys are: + + * ``id`` (str) - group id + + * ``name`` (str) - group name + """ + cdef rados_ioctx_t ioctx + cdef rbd_group_spec_t *groups + cdef size_t num_groups + + def __init__(self, ioctx): + self.ioctx = convert_ioctx(ioctx) + self.groups = NULL + self.num_groups = 1024 + while True: + self.groups = realloc_chk( + self.groups, self.num_groups * sizeof(rbd_group_spec_t)) + with nogil: + ret = rbd_group_list2(self.ioctx, self.groups, &self.num_groups) + if ret >= 0: + break + elif ret == -errno.ERANGE: + self.num_groups *= 2 + else: + raise make_ex(ret, 'error listing groups.') + + def __iter__(self): + for i in range(self.num_groups): + yield { + 'id' : decode_cstr(self.groups[i].id), + 'name' : decode_cstr(self.groups[i].name) + } + + def __dealloc__(self): + if self.groups: + rbd_group_spec_list_cleanup(self.groups, + sizeof(rbd_group_spec_t), + self.num_groups) + free(self.groups) + cdef class GroupImageIterator(object): """ Iterator over image info for a group. -- 2.39.5