rbd: add CloneImage as a wrapper for rbd_clone3 func

Add a new CloneImage that makes use of rbd_clone3 and thus behaves like
the new CreateImage function.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2020-01-03 15:35:15 -05:00 committed by Niels de Vos
parent ea016c420a
commit c662d6fb2e
2 changed files with 150 additions and 0 deletions

View File

@ -1457,3 +1457,47 @@ func RemoveImage(ioctx *rados.IOContext, name string) error {
defer C.free(unsafe.Pointer(c_name)) defer C.free(unsafe.Pointer(c_name))
return getError(C.rbd_remove(C.rados_ioctx_t(ioctx.Pointer()), c_name)) return getError(C.rbd_remove(C.rados_ioctx_t(ioctx.Pointer()), c_name))
} }
// CloneImage creates a clone of the image from the named snapshot in the
// provided io-context with the given name and image options.
//
// Implements:
// int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
// const char *p_snapname, rados_ioctx_t c_ioctx,
// const char *c_name, rbd_image_options_t c_opts);
func CloneImage(ioctx *rados.IOContext, parentName, snapName string,
destctx *rados.IOContext, name string, rio *RbdImageOptions) error {
if rio == nil {
return RBDError(C.EINVAL)
}
cParentName := C.CString(parentName)
defer C.free(unsafe.Pointer(cParentName))
cParentSnapName := C.CString(snapName)
defer C.free(unsafe.Pointer(cParentSnapName))
cCloneName := C.CString(name)
defer C.free(unsafe.Pointer(cCloneName))
ret := C.rbd_clone3(
C.rados_ioctx_t(ioctx.Pointer()),
cParentName,
cParentSnapName,
C.rados_ioctx_t(destctx.Pointer()),
cCloneName,
C.rbd_image_options_t(rio.options))
return getError(ret)
}
// CloneFromImage creates a clone of the image from the named snapshot in the
// provided io-context with the given name and image options.
// This function is a convenience wrapper around CloneImage to support cloning
// from an existing Image.
func CloneFromImage(parent *Image, snapName string,
destctx *rados.IOContext, name string, rio *RbdImageOptions) error {
if err := parent.validate(imageNeedsIOContext); err != nil {
return err
}
return CloneImage(parent.ioctx, parent.name, snapName, destctx, name, rio)
}

View File

@ -1413,6 +1413,112 @@ func TestRemoveImage(t *testing.T) {
conn.Shutdown() conn.Shutdown()
} }
func TestCloneImage(t *testing.T) {
conn := radosConnect(t)
poolname := GetUUID()
err := conn.MakePool(poolname)
assert.NoError(t, err)
ioctx, err := conn.OpenIOContext(poolname)
require.NoError(t, err)
imageName := "parent1"
snapName := "snap1"
cloneName := "clone1"
options := NewRbdImageOptions()
defer options.Destroy()
err = options.SetUint64(RbdImageOptionOrder, uint64(testImageOrder))
assert.NoError(t, err)
err = options.SetUint64(RbdImageOptionFeatures, 1)
assert.NoError(t, err)
err = CreateImage(ioctx, imageName, testImageSize, options)
assert.NoError(t, err)
image, err := OpenImage(ioctx, imageName, NoSnapshot)
assert.NoError(t, err)
snapshot, err := image.CreateSnapshot(snapName)
assert.NoError(t, err)
err = snapshot.Protect()
assert.NoError(t, err)
t.Run("cloneImage", func(t *testing.T) {
imageNames, err := GetImageNames(ioctx)
assert.NoError(t, err)
assert.Contains(t, imageNames, imageName)
assert.NotContains(t, imageNames, cloneName)
options := NewRbdImageOptions()
defer options.Destroy()
err = options.SetUint64(RbdImageOptionFormat, uint64(2))
assert.NoError(t, err)
err = CloneImage(ioctx, imageName, snapName, ioctx, cloneName, options)
assert.NoError(t, err)
imageNames, err = GetImageNames(ioctx)
assert.NoError(t, err)
assert.Contains(t, imageNames, imageName)
assert.Contains(t, imageNames, cloneName)
err = RemoveImage(ioctx, cloneName)
assert.NoError(t, err)
})
t.Run("cloneFromImage", func(t *testing.T) {
imageNames, err := GetImageNames(ioctx)
assert.NoError(t, err)
assert.Contains(t, imageNames, imageName)
assert.NotContains(t, imageNames, cloneName)
options := NewRbdImageOptions()
defer options.Destroy()
err = options.SetUint64(RbdImageOptionFormat, uint64(2))
assert.NoError(t, err)
err = CloneFromImage(image, snapName, ioctx, cloneName, options)
assert.NoError(t, err)
imageNames, err = GetImageNames(ioctx)
assert.NoError(t, err)
assert.Contains(t, imageNames, imageName)
assert.Contains(t, imageNames, cloneName)
err = RemoveImage(ioctx, cloneName)
assert.NoError(t, err)
})
t.Run("cloneFromImageInvalidCtx", func(t *testing.T) {
options := NewRbdImageOptions()
defer options.Destroy()
err = options.SetUint64(RbdImageOptionFormat, uint64(2))
assert.NoError(t, err)
badImage := GetImage(nil, image.name)
err = CloneFromImage(badImage, snapName, ioctx, cloneName, options)
assert.Error(t, err)
})
t.Run("cloneImageNilOpts", func(t *testing.T) {
err = CloneImage(ioctx, imageName, snapName, ioctx, cloneName, nil)
assert.Error(t, err)
})
err = snapshot.Unprotect()
assert.NoError(t, err)
err = snapshot.Remove()
assert.NoError(t, err)
err = image.Close()
assert.NoError(t, err)
err = image.Remove()
assert.NoError(t, err)
ioctx.Destroy()
conn.DeletePool(poolname)
conn.Shutdown()
}
// quickCreate creates an image similar to Create but uses CreateImage. // quickCreate creates an image similar to Create but uses CreateImage.
// If possible, avoid using this function for new code/tests. It mainly exists // If possible, avoid using this function for new code/tests. It mainly exists
// to help with refactoring of existing tests. // to help with refactoring of existing tests.