mirror of https://github.com/ceph/go-ceph
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:
parent
ea016c420a
commit
c662d6fb2e
44
rbd/rbd.go
44
rbd/rbd.go
|
@ -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)
|
||||||
|
}
|
||||||
|
|
106
rbd/rbd_test.go
106
rbd/rbd_test.go
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue