From 5dfda932b2012bb11a1860d8a81de3208b17f622 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 23 Jul 2021 15:18:12 -0400 Subject: [PATCH 1/3] rbd: Fix mirror_image_get_status in rbd python bindings When retrieving the status of a mirrored image from the Python rbd library, a TypeError is raised. *To Reproduce:* Set up two Ceph clusters for block storage, and configure image mirroring between their pools. Create a least one image with mirroring enabled, then run the following script on either cluster (once the image exists everywhere): ```python import rados, rbd CONF_PATH = "YOUR-CONF-PATH" POOL_NAME = "YOUR-POOL-NAME" IMAGE_LABEL = "YOUR-IMAGE-LABEL" with rados.Rados(conffile=CONF_PATH) as cluster: with cluster.open_ioctx(POOL_NAME) as ioctx: with rbd.Image(ioctx, IMAGE_LABEL) as image: image.mirror_image_get_status() ``` This will result in the following stack trace: ``` Traceback (most recent call last): File "repo-bug.py", line 10, in image.mirror_image_get_status() File "rbd.pyx", line 3363, in rbd.requires_not_closed.wrapper File "rbd.pyx", line 5209, in rbd.Image.mirror_image_get_status TypeError: list indices must be integers or slices, not str ``` Fixes: https://tracker.ceph.com/issues/51867 Signed-off-by: Will Smith --- src/pybind/rbd/rbd.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index 82dd0b47fce..b05422c5542 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -4642,7 +4642,7 @@ written." % (self.name, ret, length)) if mirror_uuid == '': local_status = site_status else: - site_statuses['mirror_uuid'] = mirror_uuid + site_status['mirror_uuid'] = mirror_uuid site_statuses += site_status status = { 'name': decode_cstr(c_status.name), From 89888beb1266be5a661fef8643bb6bef0c720f5f Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 27 Jul 2021 17:20:08 +0200 Subject: [PATCH 2/3] pybind/rbd: actually append site_status dict to remote_statuses Using += operator is wrong -- only site_status keys get appended (and repeatedly at that in case there is more than one remote site as the keys are added one by one). Signed-off-by: Ilya Dryomov --- src/pybind/rbd/rbd.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index b05422c5542..fa9197a5f99 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -2270,7 +2270,7 @@ cdef class MirrorImageStatusIterator(object): local_status = site_status else: site_status['mirror_uuid'] = mirror_uuid - site_statuses += site_status + site_statuses.append(site_status) status = { 'name' : decode_cstr(self.images[i].name), @@ -4643,7 +4643,7 @@ written." % (self.name, ret, length)) local_status = site_status else: site_status['mirror_uuid'] = mirror_uuid - site_statuses += site_status + site_statuses.append(site_status) status = { 'name': decode_cstr(c_status.name), 'id' : self.id(), From 1d2a142108b2aa102103e62ccdf3bd17688b783b Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 27 Jul 2021 18:45:20 +0200 Subject: [PATCH 3/3] pybind/rbd: explain why "primary" isn't exposed in mirror_image_status_list() "primary" is part of mirror image info (rbd_mirror_image_info_t) and is exposed in mirror_image_get_status(). mirror_image_status_list(), even though it is often thought of as an equivalent of repeated calls to mirror_image_get_status(), doesn't actually fetch the mirror image info. Signed-off-by: Ilya Dryomov --- src/pybind/rbd/rbd.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pybind/rbd/rbd.pyx b/src/pybind/rbd/rbd.pyx index fa9197a5f99..16014f1409c 100644 --- a/src/pybind/rbd/rbd.pyx +++ b/src/pybind/rbd/rbd.pyx @@ -2278,6 +2278,8 @@ cdef class MirrorImageStatusIterator(object): 'info' : { 'global_id' : decode_cstr(self.images[i].info.global_id), 'state' : self.images[i].info.state, + # primary isn't added here because it is unknown (always + # false, see XXX in Mirror::image_global_status_list()) }, 'remote_statuses': site_statuses, }