rbd: add OpenImageById and OpenImageByIdReadOnly functions

Add OpenImageById and OpenImageByIdReadOnly that wrap rbd_open_by_id and
rbd_open_by_id_read_only respectively.
The added test case can not currently test trivial error conditions due
to a known bug in ceph, these tests are skipped for meanwhile.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2019-12-29 19:31:49 -05:00 committed by Niels de Vos
parent a1f2aefcf9
commit f72828c5b2
2 changed files with 171 additions and 0 deletions

View File

@ -1356,6 +1356,79 @@ func OpenImageReadOnly(ioctx *rados.IOContext, name, snapName string) (*Image, e
}, nil
}
// OpenImageById will open an existing rbd image by ID and snapshot name,
// returning a new opened image. Pass the NoSnapshot sentinel value as the
// snapName to explicitly indicate that no snapshot name is being provided.
// Error handling will fail & segfault unless compiled with a version of ceph
// that fixes https://tracker.ceph.com/issues/43178
//
// Implements:
// int rbd_open_by_id(rados_ioctx_t io, const char *id,
// rbd_image_t *image, const char *snap_name);
func OpenImageById(ioctx *rados.IOContext, id, snapName string) (*Image, error) {
cid := C.CString(id)
defer C.free(unsafe.Pointer(cid))
var cSnapName *C.char
if snapName != NoSnapshot {
cSnapName = C.CString(snapName)
defer C.free(unsafe.Pointer(cSnapName))
}
var cImage C.rbd_image_t
ret := C.rbd_open_by_id(
C.rados_ioctx_t(ioctx.Pointer()),
cid,
&cImage,
cSnapName)
if ret != 0 {
return nil, getError(ret)
}
return &Image{
ioctx: ioctx,
image: cImage,
}, nil
}
// OpenImageByIdReadOnly will open an existing rbd image by ID and snapshot
// name, returning a new opened-for-read image. Pass the NoSnapshot sentinel
// value as the snapName to explicitly indicate that no snapshot name is being
// provided.
// Error handling will fail & segfault unless compiled with a version of ceph
// that fixes https://tracker.ceph.com/issues/43178
//
// Implements:
// int rbd_open_by_id_read_only(rados_ioctx_t io, const char *id,
// rbd_image_t *image, const char *snap_name);
func OpenImageByIdReadOnly(ioctx *rados.IOContext, id, snapName string) (*Image, error) {
cid := C.CString(id)
defer C.free(unsafe.Pointer(cid))
var cSnapName *C.char
if snapName != NoSnapshot {
cSnapName = C.CString(snapName)
defer C.free(unsafe.Pointer(cSnapName))
}
var cImage C.rbd_image_t
ret := C.rbd_open_by_id_read_only(
C.rados_ioctx_t(ioctx.Pointer()),
cid,
&cImage,
cSnapName)
if ret != 0 {
return nil, getError(ret)
}
return &Image{
ioctx: ioctx,
image: cImage,
}, nil
}
// CreateImage creates a new rbd image using provided image options.
//
// Implements:

View File

@ -1463,3 +1463,101 @@ func TestGetId(t *testing.T) {
conn.DeletePool(poolname)
conn.Shutdown()
}
func TestOpenImageById(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)
name := GetUUID()
options := NewRbdImageOptions()
assert.NoError(t,
options.SetUint64(RbdImageOptionOrder, uint64(testImageOrder)))
err = CreateImage(ioctx, name, testImageSize, options)
assert.NoError(t, err)
workingImage, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
id, err := workingImage.GetId()
assert.NoError(t, err)
err = workingImage.Close()
assert.NoError(t, err)
t.Run("ReadWriteBadId", func(t *testing.T) {
t.Skip("segfaults due to https://tracker.ceph.com/issues/43178")
// phony id
img, err := OpenImageById(ioctx, "102f00aaabbbccd", NoSnapshot)
require.Error(t, err)
require.Nil(t, img)
})
t.Run("ReadOnlyBadId", func(t *testing.T) {
t.Skip("segfaults due to https://tracker.ceph.com/issues/43178")
// phony id
img, err := OpenImageByIdReadOnly(ioctx, "blubb", NoSnapshot)
require.Error(t, err)
require.Nil(t, img)
})
t.Run("ReadWrite", func(t *testing.T) {
img, err := OpenImageById(ioctx, id, NoSnapshot)
require.NoError(t, err)
require.NotNil(t, img)
defer func() { assert.NoError(t, img.Close()) }()
data := []byte("input data")
_, err = img.Write(data)
assert.NoError(t, err)
})
t.Run("ReadOnly", func(t *testing.T) {
img, err := OpenImageByIdReadOnly(ioctx, id, NoSnapshot)
require.NoError(t, err)
require.NotNil(t, img)
defer func() { assert.NoError(t, img.Close()) }()
data := []byte("input data")
_, err = img.Write(data)
// writing should fail in read-only mode
assert.Error(t, err)
})
t.Run("Snapshot", func(t *testing.T) {
img, err := OpenImageById(ioctx, id, NoSnapshot)
require.NoError(t, err)
require.NotNil(t, img)
defer func() { assert.NoError(t, img.Close()) }()
snapshot, err := img.CreateSnapshot("snerpshort")
assert.NoError(t, err)
defer func() { assert.NoError(t, snapshot.Remove()) }()
snapImage, err := OpenImageById(ioctx, id, "snerpshort")
require.NoError(t, err)
require.NotNil(t, snapImage)
assert.NoError(t, snapImage.Close())
})
t.Run("ReadOnlySnapshot", func(t *testing.T) {
img, err := OpenImageById(ioctx, id, NoSnapshot)
require.NoError(t, err)
require.NotNil(t, img)
defer func() { assert.NoError(t, img.Close()) }()
snapshot, err := img.CreateSnapshot("snerpshort2")
assert.NoError(t, err)
defer func() { assert.NoError(t, snapshot.Remove()) }()
snapImage, err := OpenImageByIdReadOnly(ioctx, id, "snerpshort2")
require.NoError(t, err)
require.NotNil(t, snapImage)
assert.NoError(t, snapImage.Close())
})
err = workingImage.Remove()
assert.NoError(t, err)
ioctx.Destroy()
conn.DeletePool(poolname)
conn.Shutdown()
}