mirror of https://github.com/ceph/go-ceph
rbd: fix broken Image.Copy() and add an exhaustive test for it
The arguments passed to Copy() would normally be pointers, just like it is done with other similar functions. This never worked correctly, as the arguments were not validated correctly (not recognized) and the error "Must specify either destination pool or destination image" always got returned. Modifying Image.Copy() into something usable would result in a complete rewrite. Instead of a single Image.Copy() function that tries to cover rbd_copy() and rbd_copy2(), provide Image.Copy() and Image.Copy2() so that the API matches the librbd.so interface. Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
4589af9dfd
commit
2b2fcc121d
48
rbd/rbd.go
48
rbd/rbd.go
|
@ -597,37 +597,31 @@ func (image *Image) GetOverlap() (overlap uint64, err error) {
|
|||
}
|
||||
|
||||
// int rbd_copy(rbd_image_t image, rados_ioctx_t dest_io_ctx, const char *destname);
|
||||
// int rbd_copy2(rbd_image_t src, rbd_image_t dest);
|
||||
// int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p, const char *destname,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
// int rbd_copy_with_progress2(rbd_image_t src, rbd_image_t dest,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
func (image *Image) Copy(args ...interface{}) error {
|
||||
func (image *Image) Copy(ioctx *rados.IOContext, destname string) error {
|
||||
if err := image.validate(imageIsOpen); err != nil {
|
||||
return err
|
||||
} else if ioctx == nil {
|
||||
return ErrNoIOContext
|
||||
} else if len(destname) == 0 {
|
||||
return ErrNoName
|
||||
}
|
||||
|
||||
c_destname := C.CString(destname)
|
||||
defer C.free(unsafe.Pointer(c_destname))
|
||||
|
||||
return GetError(C.rbd_copy(image.image,
|
||||
C.rados_ioctx_t(ioctx.Pointer()), c_destname))
|
||||
}
|
||||
|
||||
// int rbd_copy2(rbd_image_t src, rbd_image_t dest);
|
||||
func (image *Image) Copy2(dest *Image) error {
|
||||
if err := image.validate(imageIsOpen); err != nil {
|
||||
return err
|
||||
} else if err := dest.validate(imageIsOpen); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch t := args[0].(type) {
|
||||
case rados.IOContext:
|
||||
switch t2 := args[1].(type) {
|
||||
case string:
|
||||
c_destname := C.CString(t2)
|
||||
defer C.free(unsafe.Pointer(c_destname))
|
||||
return GetError(C.rbd_copy(image.image,
|
||||
C.rados_ioctx_t(t.Pointer()),
|
||||
c_destname))
|
||||
default:
|
||||
return errors.New("Must specify destname")
|
||||
}
|
||||
case Image:
|
||||
var dest Image = t
|
||||
if dest.image == nil {
|
||||
return errors.New(fmt.Sprintf("RBD image %s is not open", dest.name))
|
||||
}
|
||||
return GetError(C.rbd_copy2(image.image, dest.image))
|
||||
default:
|
||||
return errors.New("Must specify either destination pool or destination image")
|
||||
}
|
||||
return GetError(C.rbd_copy2(image.image, dest.image))
|
||||
}
|
||||
|
||||
// int rbd_flatten(rbd_image_t image);
|
||||
|
|
|
@ -576,6 +576,94 @@ func TestIOReaderWriter(t *testing.T) {
|
|||
conn.Shutdown()
|
||||
}
|
||||
|
||||
func TestImageCopy(t *testing.T) {
|
||||
conn, _ := rados.NewConn()
|
||||
conn.ReadDefaultConfigFile()
|
||||
conn.Connect()
|
||||
|
||||
poolname := GetUUID()
|
||||
err := conn.MakePool(poolname)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ioctx, err := conn.OpenIOContext(poolname)
|
||||
require.NoError(t, err)
|
||||
|
||||
name := GetUUID()
|
||||
img, err := Create(ioctx, name, 1<<22, 22)
|
||||
require.NoError(t, err)
|
||||
|
||||
// img not open, should fail
|
||||
err = img.Copy(nil, "")
|
||||
assert.Equal(t, err, ErrImageNotOpen)
|
||||
|
||||
err = img.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
// pass invalid parameters
|
||||
err = img.Copy(nil, "")
|
||||
assert.Error(t, err) // order of errors not enforced
|
||||
|
||||
err = img.Copy(ioctx, "")
|
||||
assert.Equal(t, err, ErrNoName)
|
||||
|
||||
err = img.Copy(nil, "duplicate")
|
||||
assert.Equal(t, err, ErrNoIOContext)
|
||||
|
||||
// try successful copying
|
||||
name = GetUUID()
|
||||
err = img.Copy(ioctx, name)
|
||||
require.NoError(t, err)
|
||||
|
||||
img2 := GetImage(ioctx, name)
|
||||
err = img2.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = img2.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img2.Remove()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test with Image as parameter
|
||||
name = GetUUID()
|
||||
img2, err = Create(ioctx, name, 1<<22, 22)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = img.Copy2(img2)
|
||||
assert.Equal(t, err, ErrImageNotOpen)
|
||||
|
||||
err = img.Open()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img.Copy2(img2)
|
||||
assert.Equal(t, err, ErrImageNotOpen)
|
||||
|
||||
err = img2.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = img.Copy2(img2)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = img2.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img2.Remove()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = img.Remove()
|
||||
assert.NoError(t, err)
|
||||
|
||||
ioctx.Destroy()
|
||||
conn.DeletePool(poolname)
|
||||
conn.Shutdown()
|
||||
}
|
||||
|
||||
func TestCreateSnapshot(t *testing.T) {
|
||||
conn, _ := rados.NewConn()
|
||||
conn.ReadDefaultConfigFile()
|
||||
|
|
Loading…
Reference in New Issue