-
Notifications
You must be signed in to change notification settings - Fork 257
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rbd: add support for CloneImageByID()
RBD image groups can be used to create consistent snapshots of all images that are part of the group. The new rbd_clone4() API makes it possible to create a new RBD image from a single snapshot that was created as part of the group snapshot. Signed-off-by: Niels de Vos <[email protected]>
- Loading branch information
Showing
4 changed files
with
208 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
//go:build !(nautilus || octopus || pacific || quincy || reef) && ceph_preview | ||
|
||
package rbd | ||
|
||
// #cgo LDFLAGS: -lrbd | ||
// #include <errno.h> | ||
// #include <stdlib.h> | ||
// #include <rados/librados.h> | ||
// #include <rbd/librbd.h> | ||
import "C" | ||
|
||
import ( | ||
"unsafe" | ||
|
||
"github.com/ceph/go-ceph/rados" | ||
) | ||
|
||
// CloneImageByID creates a clone of the image from a snapshot with the given | ||
// ID in the provided io-context with the given name and image options. | ||
// | ||
// Implements: | ||
// | ||
// int rbd_clone4(rados_ioctx_t p_ioctx, const char *p_name, | ||
// uint64_t p_snap_id, rados_ioctx_t c_ioctx, | ||
// const char *c_name, rbd_image_options_t c_opts); | ||
func CloneImageByID(ioctx *rados.IOContext, parentName string, snapID uint64, | ||
destctx *rados.IOContext, name string, rio *ImageOptions) error { | ||
|
||
if rio == nil { | ||
return rbdError(C.EINVAL) | ||
} | ||
|
||
cParentName := C.CString(parentName) | ||
defer C.free(unsafe.Pointer(cParentName)) | ||
cCloneName := C.CString(name) | ||
defer C.free(unsafe.Pointer(cCloneName)) | ||
|
||
ret := C.rbd_clone4( | ||
cephIoctx(ioctx), | ||
cParentName, | ||
C.uint64_t(snapID), | ||
cephIoctx(destctx), | ||
cCloneName, | ||
C.rbd_image_options_t(rio.options)) | ||
return getError(ret) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
//go:build !(nautilus || octopus || pacific || quincy || reef) && ceph_preview | ||
|
||
package rbd | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestCloneImageByID(t *testing.T) { | ||
// tests are done as subtests to avoid creating pools, images, etc | ||
// over and over again. | ||
conn := radosConnect(t) | ||
require.NotNil(t, conn) | ||
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() | ||
|
||
// create a group, some images, and add images to the group | ||
gname := "snapme" | ||
err = GroupCreate(ioctx, gname) | ||
assert.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, GroupRemove(ioctx, gname)) | ||
}() | ||
|
||
options := NewRbdImageOptions() | ||
assert.NoError(t, | ||
options.SetUint64(ImageOptionOrder, uint64(testImageOrder))) | ||
defer options.Destroy() | ||
|
||
name1 := GetUUID() | ||
err = CreateImage(ioctx, name1, testImageSize, options) | ||
require.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, RemoveImage(ioctx, name1)) | ||
}() | ||
|
||
name2 := GetUUID() | ||
err = CreateImage(ioctx, name2, testImageSize, options) | ||
require.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, RemoveImage(ioctx, name2)) | ||
}() | ||
|
||
err = GroupImageAdd(ioctx, gname, ioctx, name1) | ||
assert.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, GroupImageRemove(ioctx, gname, ioctx, name1)) | ||
}() | ||
|
||
err = GroupImageAdd(ioctx, gname, ioctx, name2) | ||
assert.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, GroupImageRemove(ioctx, gname, ioctx, name2)) | ||
}() | ||
|
||
t.Run("CloneFromSnapshot", func(t *testing.T) { | ||
cloneName := "child" | ||
optionsClone := NewRbdImageOptions() | ||
defer optionsClone.Destroy() | ||
err := optionsClone.SetUint64(ImageOptionCloneFormat, 2) | ||
assert.NoError(t, err) | ||
|
||
// Get the snapID | ||
img, err := OpenImage(ioctx, name1, NoSnapshot) | ||
assert.NoError(t, err) | ||
defer img.Close() | ||
|
||
snapName := "mysnap" | ||
snapshot, err := img.CreateSnapshot(snapName) | ||
assert.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, snapshot.Remove()) | ||
}() | ||
|
||
snapInfos, err := img.GetSnapshotNames() | ||
assert.NoError(t, err) | ||
require.Equal(t, 1, len(snapInfos)) | ||
|
||
snapID := snapInfos[0].Id | ||
|
||
// Create a clone of the image using the snapshot. | ||
err = CloneImageByID(ioctx, name1, snapID, ioctx, cloneName, optionsClone) | ||
assert.NoError(t, err) | ||
defer func() { assert.NoError(t, RemoveImage(ioctx, cloneName)) }() | ||
|
||
imgNew, err := OpenImage(ioctx, cloneName, NoSnapshot) | ||
defer func() { | ||
assert.NoError(t, imgNew.Close()) | ||
}() | ||
assert.NoError(t, err) | ||
|
||
parentInfo, err := imgNew.GetParent() | ||
assert.NoError(t, err) | ||
assert.Equal(t, parentInfo.Image.ImageName, name1) | ||
assert.Equal(t, parentInfo.Image.PoolName, poolname) | ||
assert.False(t, parentInfo.Image.Trash) | ||
assert.Equal(t, parentInfo.Snap.SnapName, snapName) | ||
assert.Equal(t, parentInfo.Snap.ID, snapID) | ||
}) | ||
|
||
t.Run("CloneFromGroupSnap", func(t *testing.T) { | ||
err := GroupSnapCreate(ioctx, gname, "groupsnap") | ||
assert.NoError(t, err) | ||
|
||
cloneName := "img-clone" | ||
optionsClone := NewRbdImageOptions() | ||
defer optionsClone.Destroy() | ||
err = optionsClone.SetUint64(ImageOptionCloneFormat, 2) | ||
assert.NoError(t, err) | ||
|
||
// Get the snapID of the image | ||
img, err := OpenImageReadOnly(ioctx, name1, NoSnapshot) | ||
assert.NoError(t, err) | ||
defer img.Close() | ||
|
||
snapInfos, err := img.GetSnapshotNames() | ||
assert.NoError(t, err) | ||
require.Equal(t, 1, len(snapInfos)) | ||
|
||
snapID := snapInfos[0].Id | ||
|
||
// Create a clone of the image using the snapshot. | ||
err = CloneImageByID(ioctx, name1, snapID, ioctx, cloneName, optionsClone) | ||
assert.NoError(t, err) | ||
defer func() { assert.NoError(t, RemoveImage(ioctx, cloneName)) }() | ||
|
||
imgNew, err := OpenImage(ioctx, cloneName, NoSnapshot) | ||
defer func() { | ||
assert.NoError(t, imgNew.Close()) | ||
}() | ||
assert.NoError(t, err) | ||
|
||
parentInfo, err := imgNew.GetParent() | ||
assert.NoError(t, err) | ||
assert.Equal(t, parentInfo.Image.ImageName, name1) | ||
assert.Equal(t, parentInfo.Snap.ID, snapID) | ||
assert.Equal(t, parentInfo.Image.PoolName, poolname) | ||
assert.False(t, parentInfo.Image.Trash) | ||
|
||
err = GroupSnapRemove(ioctx, gname, "groupsnap") | ||
assert.NoError(t, err) | ||
}) | ||
} |