From ff1ce1347800bab7fa0721b62ae91bc06c2b0df2 Mon Sep 17 00:00:00 2001 From: Mudit Agarwal Date: Thu, 30 Jul 2020 09:10:00 +0530 Subject: [PATCH] rados: add wrappers for rados snapshot ID related functions Add wrappers for following three functions which involve snapshot ID: 1. rados_ioctx_snap_lookup() 2. rados_ioctx_snap_get_name() 3. rados_ioctx_snap_get_stamp() Signed-off-by: Mudit Agarwal --- rados/snapshot.go | 81 +++++++++++++++++++++++++++++++++++++++++- rados/snapshot_test.go | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/rados/snapshot.go b/rados/snapshot.go index 536478c..ff9200e 100644 --- a/rados/snapshot.go +++ b/rados/snapshot.go @@ -5,7 +5,12 @@ package rados // #include import "C" -import "unsafe" +import ( + "time" + "unsafe" + + "github.com/ceph/go-ceph/internal/retry" +) // CreateSnap creates a pool-wide snapshot. // @@ -38,3 +43,77 @@ func (ioctx *IOContext) RemoveSnap(snapName string) error { ret := C.rados_ioctx_snap_remove(ioctx.ioctx, cSnapName) return getError(ret) } + +// SnapID represents the ID of a rados snapshot. +type SnapID C.rados_snap_t + +// LookupSnap returns the ID of a pool snapshot. +// +// Implements: +// int rados_ioctx_snap_lookup(rados_ioctx_t io, const char *name, rados_snap_t *id) +func (ioctx *IOContext) LookupSnap(snapName string) (SnapID, error) { + var snapID SnapID + + if err := ioctx.validate(); err != nil { + return snapID, err + } + + cSnapName := C.CString(snapName) + defer C.free(unsafe.Pointer(cSnapName)) + + ret := C.rados_ioctx_snap_lookup( + ioctx.ioctx, + cSnapName, + (*C.rados_snap_t)(&snapID)) + return snapID, getError(ret) +} + +// GetSnapName returns the name of a pool snapshot with the given snapshot ID. +// +// Implements: +// int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char *name, int maxlen) +func (ioctx *IOContext) GetSnapName(snapID SnapID) (string, error) { + if err := ioctx.validate(); err != nil { + return "", err + } + + var ( + buf []byte + err error + ) + // range from 1k to 64KiB + retry.WithSizes(1024, 1<<16, func(len int) retry.Hint { + cLen := C.int(len) + buf = make([]byte, cLen) + ret := C.rados_ioctx_snap_get_name( + ioctx.ioctx, + (C.rados_snap_t)(snapID), + (*C.char)(unsafe.Pointer(&buf[0])), + cLen) + err = getError(ret) + return retry.Size(int(cLen)).If(err == errRange) + }) + + if err != nil { + return "", err + } + return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil +} + +// GetSnapStamp returns the time of the pool snapshot creation. +// +// Implements: +// int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t) +func (ioctx *IOContext) GetSnapStamp(snapID SnapID) (time.Time, error) { + var cTime C.time_t + + if err := ioctx.validate(); err != nil { + return time.Unix(int64(cTime), 0), err + } + + ret := C.rados_ioctx_snap_get_stamp( + ioctx.ioctx, + (C.rados_snap_t)(snapID), + &cTime) + return time.Unix(int64(cTime), 0), getError(ret) +} diff --git a/rados/snapshot_test.go b/rados/snapshot_test.go index 7a7c01c..cd2d2fe 100644 --- a/rados/snapshot_test.go +++ b/rados/snapshot_test.go @@ -64,3 +64,75 @@ func (suite *RadosTestSuite) TestCreateRemoveSnapshot() { assert.NoError(t, err) }) } + +func (suite *RadosTestSuite) TestSnapshotIDFunctions() { + suite.SetupConnection() + + suite.T().Run("invalidIOCtx", func(t *testing.T) { + ioctx := &IOContext{} + _, err := ioctx.LookupSnap("") + assert.Error(t, err) + assert.Equal(t, err, ErrInvalidIOContext) + + var snapID SnapID + snapID = 22 // some random number + _, err = ioctx.GetSnapName(snapID) + assert.Error(t, err) + assert.Equal(t, err, ErrInvalidIOContext) + + _, err = ioctx.GetSnapStamp(snapID) + assert.Error(t, err) + assert.Equal(t, err, ErrInvalidIOContext) + }) + + // Invalid args + suite.T().Run("InvalidArgs", func(t *testing.T) { + ioctx, err := suite.conn.OpenIOContext(suite.pool) + require.NoError(suite.T(), err) + + err = ioctx.CreateSnap("") + assert.NoError(t, err) + defer func() { + assert.NoError(t, ioctx.RemoveSnap("")) + }() + + // Again, this works!! + _, err = ioctx.LookupSnap("") + assert.NoError(t, err) + + // Non-existing Snap + _, err = ioctx.LookupSnap("someSnapName") + assert.Error(t, err) + + var snapID SnapID + snapID = 22 // some random number + _, err = ioctx.GetSnapName(snapID) + assert.Error(t, err) + + _, err = ioctx.GetSnapStamp(snapID) + assert.Error(t, err) + }) + + // Valid SnapID operations. + suite.T().Run("ValidSnapIDOps", func(t *testing.T) { + ioctx, err := suite.conn.OpenIOContext(suite.pool) + require.NoError(suite.T(), err) + + snapName := "mySnap" + err = ioctx.CreateSnap(snapName) + assert.NoError(t, err) + defer func() { + assert.NoError(t, ioctx.RemoveSnap(snapName)) + }() + + snapID, err := ioctx.LookupSnap(snapName) + assert.NoError(t, err) + + retName, err := ioctx.GetSnapName(snapID) + assert.NoError(t, err) + assert.Equal(t, snapName, retName) + + _, err = ioctx.GetSnapStamp(snapID) + assert.NoError(t, err) + }) +}