rbd: add GroupSnapList implementing rbd_group_snap_list

* Add GroupSnapList implementing rbd_group_snap_list

Adds tests for the above.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2021-01-25 14:44:05 -05:00 committed by mergify[bot]
parent fd08e791cc
commit ffeabf1436
2 changed files with 110 additions and 0 deletions

View File

@ -10,6 +10,7 @@ import "C"
import ( import (
"unsafe" "unsafe"
"github.com/ceph/go-ceph/internal/retry"
"github.com/ceph/go-ceph/rados" "github.com/ceph/go-ceph/rados"
) )
@ -64,3 +65,68 @@ func GroupSnapRename(ioctx *rados.IOContext, group, src, dest string) error {
cephIoctx(ioctx), cGroupName, cOldSnapName, cNewSnapName) cephIoctx(ioctx), cGroupName, cOldSnapName, cNewSnapName)
return getError(ret) return getError(ret)
} }
// GroupSnapState represents the state of a group snapshot in GroupSnapInfo.
type GroupSnapState int
const (
// GroupSnapStateIncomplete is equivalent to RBD_GROUP_SNAP_STATE_INCOMPLETE.
GroupSnapStateIncomplete = GroupSnapState(C.RBD_GROUP_SNAP_STATE_INCOMPLETE)
// GroupSnapStateComplete is equivalent to RBD_GROUP_SNAP_STATE_COMPLETE.
GroupSnapStateComplete = GroupSnapState(C.RBD_GROUP_SNAP_STATE_COMPLETE)
)
// GroupSnapInfo values are returned by GroupSnapList, representing the
// snapshots that are part of an rbd group.
type GroupSnapInfo struct {
Name string
State GroupSnapState
}
// GroupSnapList returns a slice of snapshots in a group.
//
// Implements:
// int rbd_group_snap_list(rados_ioctx_t group_p,
// const char *group_name,
// rbd_group_snap_info_t *snaps,
// size_t group_snap_info_size,
// size_t *num_entries);
func GroupSnapList(ioctx *rados.IOContext, group string) ([]GroupSnapInfo, error) {
cGroupName := C.CString(group)
defer C.free(unsafe.Pointer(cGroupName))
var (
cSnaps []C.rbd_group_snap_info_t
cSize C.size_t
err error
)
retry.WithSizes(1024, 262144, func(size int) retry.Hint {
cSize = C.size_t(size)
cSnaps = make([]C.rbd_group_snap_info_t, cSize)
ret := C.rbd_group_snap_list(
cephIoctx(ioctx),
cGroupName,
(*C.rbd_group_snap_info_t)(unsafe.Pointer(&cSnaps[0])),
C.sizeof_rbd_group_snap_info_t,
&cSize)
err = getErrorIfNegative(ret)
return retry.Size(int(cSize)).If(err == errRange)
})
if err != nil {
return nil, err
}
snaps := make([]GroupSnapInfo, cSize)
for i := range snaps {
snaps[i].Name = C.GoString(cSnaps[i].name)
snaps[i].State = GroupSnapState(cSnaps[i].state)
}
// free C memory allocated by C.rbd_group_snap_list call
ret := C.rbd_group_snap_list_cleanup(
(*C.rbd_group_snap_info_t)(unsafe.Pointer(&cSnaps[0])),
C.sizeof_rbd_group_snap_info_t,
cSize)
return snaps, getError(ret)
}

View File

@ -63,6 +63,47 @@ func TestGroupSnapshots(t *testing.T) {
err = GroupSnapRemove(ioctx, gname, "snap2b") err = GroupSnapRemove(ioctx, gname, "snap2b")
assert.NoError(t, err, "remove of current name: expect success") assert.NoError(t, err, "remove of current name: expect success")
}) })
t.Run("groupSnappList", func(t *testing.T) {
err := GroupSnapCreate(ioctx, gname, "snap1")
assert.NoError(t, err)
err = GroupSnapCreate(ioctx, gname, "snap2")
assert.NoError(t, err)
err = GroupSnapCreate(ioctx, gname, "snap3")
assert.NoError(t, err)
gsl, err := GroupSnapList(ioctx, gname)
assert.NoError(t, err)
if assert.Len(t, gsl, 3) {
names := []string{}
for _, gsi := range gsl {
assert.Equal(t, GroupSnapStateComplete, gsi.State)
names = append(names, gsi.Name)
}
assert.Contains(t, names, "snap1")
assert.Contains(t, names, "snap2")
assert.Contains(t, names, "snap3")
}
err = GroupSnapRemove(ioctx, gname, "snap3")
assert.NoError(t, err)
err = GroupSnapRemove(ioctx, gname, "snap2")
assert.NoError(t, err)
err = GroupSnapRename(ioctx, gname, "snap1", "snap1a")
gsl, err = GroupSnapList(ioctx, gname)
assert.NoError(t, err)
if assert.Len(t, gsl, 1) {
assert.Equal(t, GroupSnapStateComplete, gsl[0].State)
assert.Equal(t, "snap1a", gsl[0].Name)
}
err = GroupSnapRemove(ioctx, gname, "snap1a")
assert.NoError(t, err)
gsl, err = GroupSnapList(ioctx, gname)
assert.NoError(t, err)
assert.Len(t, gsl, 0)
})
t.Run("invalidIOContext", func(t *testing.T) { t.Run("invalidIOContext", func(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
GroupSnapCreate(nil, gname, "foo") GroupSnapCreate(nil, gname, "foo")
@ -73,5 +114,8 @@ func TestGroupSnapshots(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
GroupSnapRename(nil, gname, "foo", "bar") GroupSnapRename(nil, gname, "foo", "bar")
}) })
assert.Panics(t, func() {
GroupSnapList(nil, gname)
})
}) })
} }