Repository: ceph/go-ceph
Pull request #448 (2021-01-25 09:17:59)

rbd: add functions to fetch mirroring status of a RBD image
Added two functions:
1. GetMirrorImageInfo()
2. GetImageMirrorMode()

Signed-off-by: Mudit Agarwal <muagarwa@redhat.com>

Fixes: #379 

## Checklist
- [ ] Added tests for features and functional changes
- [ ] Public functions and types are documented
- [ ] Standard formatting is applied to Go code



Patch:
diff --git a/rbd/mirror.go b/rbd/mirror.go
index 46f2740..1087494 100644
--- a/rbd/mirror.go
+++ b/rbd/mirror.go
@@ -165,3 +165,71 @@ func (image *Image) MirrorInstanceID() (string, error) {
 	}
 	return string(buf[:cSize]), nil
 }
+
+// MirrorImageState represents the mirroring state of a RBD image.
+type MirrorImageState C.rbd_mirror_image_state_t
+
+const (
+	// MirrorImageDisabling is the representation of
+	// RBD_MIRROR_IMAGE_DISABLING from librbd.
+	MirrorImageDisabling = MirrorImageState(C.RBD_MIRROR_IMAGE_DISABLING)
+	// MirrorImageEnabled is the representation of
+	// RBD_MIRROR_IMAGE_ENABLED from librbd.
+	MirrorImageEnabled = MirrorImageState(C.RBD_MIRROR_IMAGE_ENABLED)
+	// MirrorImageDisabled is the representation of
+	// RBD_MIRROR_IMAGE_DISABLED from librbd.
+	MirrorImageDisabled = MirrorImageState(C.RBD_MIRROR_IMAGE_DISABLED)
+)
+
+// MirrorImageInfo represents the mirroring status information of a RBD image.
+type MirrorImageInfo struct {
+	GlobalID string
+	State    MirrorImageState
+	Primary  bool
+}
+
+// GetMirrorImageInfo fetches the mirroring status information of a RBD image.
+//
+// Implements:
+//  int rbd_mirror_image_get_info(rbd_image_t image,
+//                                rbd_mirror_image_info_t *mirror_image_info,
+//                                size_t info_size)
+func (image *Image) GetMirrorImageInfo() (*MirrorImageInfo, error) {
+	if err := image.validate(imageIsOpen); err != nil {
+		return nil, err
+	}
+
+	var cInfo C.rbd_mirror_image_info_t
+
+	ret := C.rbd_mirror_image_get_info(
+		image.image,
+		&cInfo,
+		C.sizeof_rbd_mirror_image_info_t)
+	if ret < 0 {
+		return nil, getError(ret)
+	}
+
+	mii := MirrorImageInfo{
+		GlobalID: C.GoString(cInfo.global_id),
+		State:    MirrorImageState(cInfo.state),
+		Primary:  bool(cInfo.primary),
+	}
+
+	// free C memory allocated by C.rbd_mirror_image_get_info call
+	C.rbd_mirror_image_get_info_cleanup(&cInfo)
+	return &mii, nil
+}
+
+// GetImageMirrorMode fetches the mirroring approach for an RBD image.
+//
+// Implements:
+//  int rbd_mirror_image_get_mode(rbd_image_t image, rbd_mirror_image_mode_t *mode);
+func (image *Image) GetImageMirrorMode() (ImageMirrorMode, error) {
+	var mode C.rbd_mirror_image_mode_t
+	if err := image.validate(imageIsOpen); err != nil {
+		return ImageMirrorMode(mode), err
+	}
+
+	ret := C.rbd_mirror_image_get_mode(image.image, &mode)
+	return ImageMirrorMode(mode), getError(ret)
+}


Test patch:
diff --git a/rbd/mirror_test.go b/rbd/mirror_test.go
index fed76cb..a8eb8e0 100644
--- a/rbd/mirror_test.go
+++ b/rbd/mirror_test.go
@@ -91,6 +91,11 @@ func TestMirroring(t *testing.T) {
 
 		err = img.MirrorEnable(ImageMirrorModeSnapshot)
 		assert.NoError(t, err)
+
+		mode, err := img.GetImageMirrorMode()
+		assert.NoError(t, err)
+		assert.Equal(t, mode, ImageMirrorModeSnapshot)
+
 		err = img.MirrorDisable(false)
 		assert.NoError(t, err)
 	})
@@ -103,6 +108,8 @@ func TestMirroring(t *testing.T) {
 		assert.Error(t, err)
 		err = img.MirrorDisable(false)
 		assert.Error(t, err)
+		_, err = img.GetImageMirrorMode()
+		assert.Error(t, err)
 	})
 	t.Run("promoteDemote", func(t *testing.T) {
 		img, err := OpenImage(ioctx, name1, NoSnapshot)
@@ -182,3 +189,53 @@ func TestMirroring(t *testing.T) {
 		assert.Error(t, err)
 	})
 }
+
+func TestGetMirrorImageInfo(t *testing.T) {
+	conn := radosConnect(t)
+	poolName := GetUUID()
+	err := conn.MakePool(poolName)
+	require.NoError(t, err)
+	defer func() {
+		assert.NoError(t, conn.DeletePool(poolName))
+		conn.Shutdown()
+	}()
+
+	ioctx, err := conn.OpenIOContext(poolName)
+	assert.NoError(t, err)
+	defer func() {
+		ioctx.Destroy()
+	}()
+
+	// enable per-image mirroring for this pool
+	err = SetMirrorMode(ioctx, MirrorModeImage)
+	require.NoError(t, err)
+
+	imgName := GetUUID()
+	options := NewRbdImageOptions()
+	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
+	err = CreateImage(ioctx, imgName, testImageSize, options)
+	require.NoError(t, err)
+
+	t.Run("closedImage", func(t *testing.T) {
+		img := GetImage(ioctx, imgName)
+		_, err = img.GetMirrorImageInfo()
+		assert.Error(t, err)
+	})
+
+	t.Run("getInfo", func(t *testing.T) {
+		// open image, enable, mirroring.
+		img, err := OpenImage(ioctx, imgName, NoSnapshot)
+		assert.NoError(t, err)
+		defer func() {
+			assert.NoError(t, img.Close())
+		}()
+
+		err = img.MirrorEnable(ImageMirrorModeSnapshot)
+		assert.NoError(t, err)
+		mii, err := img.GetMirrorImageInfo()
+		assert.NoError(t, err)
+		assert.NotNil(t, mii.GlobalID)
+		assert.Equal(t, mii.State, MirrorImageEnabled)
+		assert.Equal(t, mii.Primary, true)
+	})
+}