From a5da5e308bfd5cb8e6a87bbc41c545d5759e4710 Mon Sep 17 00:00:00 2001 From: Mudit Agarwal Date: Wed, 24 Jun 2020 19:46:18 +0530 Subject: [PATCH] rbd: add functions and constants related to snapshot namespace. Added few constants used for determining snapshot namespace. Added wrapper for function rbd_snap_get_namespace_type() which returns namespace type for a given snapshot. Signed-off-by: Mudit Agarwal --- rbd/snapshot_namespace.go | 42 +++++++++++++ rbd/snapshot_namespace_test.go | 111 +++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 rbd/snapshot_namespace.go create mode 100644 rbd/snapshot_namespace_test.go diff --git a/rbd/snapshot_namespace.go b/rbd/snapshot_namespace.go new file mode 100644 index 0000000..a4c5348 --- /dev/null +++ b/rbd/snapshot_namespace.go @@ -0,0 +1,42 @@ +// +build !luminous +// +// Ceph Mimic introduced rbd_snap_get_namespace_type(). + +package rbd + +// #cgo LDFLAGS: -lrbd +// #include +import "C" + +// SnapNamespaceType indicates the namespace to which the snapshot belongs to. +type SnapNamespaceType C.rbd_snap_namespace_type_t + +const ( + // SnapNamespaceTypeUser indicates that the snapshot belongs to user namespace. + SnapNamespaceTypeUser = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_USER) + + // SnapNamespaceTypeGroup indicates that the snapshot belongs to group namespace. + // Such snapshots will have associated group information. + SnapNamespaceTypeGroup = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_GROUP) + + // SnapNamespaceTypeTrash indicates that the snapshot belongs to trash namespace. + SnapNamespaceTypeTrash = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_TRASH) +) + +// GetSnapNamespaceType gets the type of namespace to which the snapshot belongs to, +// returns error on failure. +// +// Implements: +// int rbd_snap_get_namespace_type(rbd_image_t image, uint64_t snap_id, rbd_snap_namespace_type_t *namespace_type) +func (image *Image) GetSnapNamespaceType(snapID uint64) (SnapNamespaceType, error) { + var nsType SnapNamespaceType + + if err := image.validate(imageIsOpen); err != nil { + return nsType, err + } + + ret := C.rbd_snap_get_namespace_type(image.image, + C.uint64_t(snapID), + (*C.rbd_snap_namespace_type_t)(&nsType)) + return nsType, getError(ret) +} diff --git a/rbd/snapshot_namespace_test.go b/rbd/snapshot_namespace_test.go new file mode 100644 index 0000000..1799257 --- /dev/null +++ b/rbd/snapshot_namespace_test.go @@ -0,0 +1,111 @@ +// +build !luminous + +package rbd + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetSnapNamespaceType(t *testing.T) { + conn := radosConnect(t) + defer conn.Shutdown() + + poolname := GetUUID() + err := conn.MakePool(poolname) + require.NoError(t, err) + defer conn.DeletePool(poolname) + + ioctx, err := conn.OpenIOContext(poolname) + require.NoError(t, err) + defer ioctx.Destroy() + + imageName := "parent" + snapName := "mySnap" + options := NewRbdImageOptions() + defer options.Destroy() + err = options.SetUint64(ImageOptionOrder, uint64(testImageOrder)) + assert.NoError(t, err) + err = options.SetUint64(ImageOptionFeatures, 1) + assert.NoError(t, err) + + err = CreateImage(ioctx, imageName, testImageSize, options) + assert.NoError(t, err) + + img, err := OpenImage(ioctx, imageName, NoSnapshot) + assert.NoError(t, err) + + defer func() { + assert.NoError(t, img.Close()) + assert.NoError(t, img.Remove()) + }() + + snapshot, err := img.CreateSnapshot(snapName) + assert.NoError(t, err) + + snapInfoList, err := img.GetSnapshotNames() + assert.NoError(t, err) + + snapInfo := snapInfoList[0] + assert.Equal(t, snapInfo.Name, snapName) + + t.Run("SnapNamespaceTypeInvalidArgs", func(t *testing.T) { + validImageName := GetUUID() + validImg, err := Create(ioctx, validImageName, testImageSize, testImageOrder, 1) + assert.NoError(t, err) + defer func() { + assert.NoError(t, validImg.Remove()) + }() + + validImg = GetImage(ioctx, validImageName) + // Closed image and a snapshot ID which doesn't belong to this image. + _, err = validImg.GetSnapNamespaceType(snapInfo.Id) + assert.Error(t, err) + + // Open image but invalid snap ID. + validImg, err = OpenImage(ioctx, validImageName, NoSnapshot) + assert.NoError(t, err) + defer func() { + assert.NoError(t, validImg.Close()) + }() + + _, err = validImg.GetSnapNamespaceType(uint64(22)) + assert.Error(t, err) + + // With non-existing image. + invalidImageName := GetUUID() + invalidImg := GetImage(ioctx, invalidImageName) + _, err = invalidImg.GetSnapNamespaceType(snapInfo.Id) + assert.Error(t, err) + }) + + t.Run("SnapNamespaceTypeUser", func(t *testing.T) { + nsType, err := img.GetSnapNamespaceType(snapInfo.Id) + assert.NoError(t, err) + assert.Equal(t, nsType, SnapNamespaceTypeUser) + }) + + t.Run("SnapNamespaceTypeTrash", func(t *testing.T) { + cloneName := "myClone" + optionsClone := NewRbdImageOptions() + defer optionsClone.Destroy() + err := optionsClone.SetUint64(ImageOptionCloneFormat, 2) + assert.NoError(t, err) + + // Create a clone of the image using the same snapshot. + err = CloneImage(ioctx, imageName, snapName, ioctx, cloneName, optionsClone) + assert.NoError(t, err) + defer func() { assert.NoError(t, RemoveImage(ioctx, cloneName)) }() + + // Once clone is created, remove the snapshot. + err = snapshot.Remove() + assert.NoError(t, err) + + // Snapshot would move to the trash because linked clone is still there. + nsType, err := img.GetSnapNamespaceType(snapInfo.Id) + assert.NoError(t, err) + assert.Equal(t, nsType, SnapNamespaceTypeTrash) + }) +}