mirror of https://github.com/ceph/go-ceph
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:
parent
fd08e791cc
commit
ffeabf1436
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue