diff --git a/rados/ioctx.go b/rados/ioctx.go index 518f7eb..4229bde 100644 --- a/rados/ioctx.go +++ b/rados/ioctx.go @@ -36,6 +36,11 @@ type IOContext struct { ioctx C.rados_ioctx_t } +// Pointer returns a uintptr representation of the IOContext. +func (ioctx *IOContext) Pointer() uintptr { + return uintptr(ioctx.ioctx) +} + // Write writes len(data) bytes to the object with key oid starting at byte // offset offset. It returns an error, if any. func (ioctx *IOContext) Write(oid string, data []byte, offset uint64) error { diff --git a/rbd/rbd.go b/rbd/rbd.go new file mode 100644 index 0000000..c869f67 --- /dev/null +++ b/rbd/rbd.go @@ -0,0 +1,66 @@ +package rbd + +// #cgo LDFLAGS: -lrbd +// #include +// #include +// #include +import "C" + +import ( + "github.com/noahdesu/go-rados/rados" + "fmt" + "unsafe" + "bytes" +) + +// +type RBDError int + +// +func (e RBDError) Error() string { + return fmt.Sprintf("rbd: ret=%d", e) +} + +// +func Version() (int, int, int) { + var c_major, c_minor, c_patch C.int + C.rbd_version(&c_major, &c_minor, &c_patch) + return int(c_major), int(c_minor), int(c_patch) +} + +// Create +func Create(ioctx *rados.IOContext, name string, size uint64) error { + var c_order C.int + c_name := C.CString(name) + defer C.free(unsafe.Pointer(c_name)) + ret := C.rbd_create(C.rados_ioctx_t(ioctx.Pointer()), c_name, C.uint64_t(size), &c_order) + if ret < 0 { + return RBDError(ret) + } else { + return nil + } +} + +// GetImageNames returns the list of current RBD images. +func GetImageNames(ioctx *rados.IOContext) (names []string, err error) { + buf := make([]byte, 4096) + for { + size := C.size_t(len(buf)) + ret := C.rbd_list(C.rados_ioctx_t(ioctx.Pointer()), + (*C.char)(unsafe.Pointer(&buf[0])), &size) + if ret == -34 { // FIXME + buf = make([]byte, size) + continue + } else if ret < 0 { + return nil, RBDError(ret) + } + tmp := bytes.Split(buf[:size-1], []byte{0}) + for _, s := range tmp { + if len(s) > 0 { + name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) + names = append(names, name) + } + } + return names, nil + } +} diff --git a/rbd/rbd_test.go b/rbd/rbd_test.go new file mode 100644 index 0000000..f8c4a81 --- /dev/null +++ b/rbd/rbd_test.go @@ -0,0 +1,53 @@ +package rbd_test + +import ( + "testing" + "github.com/noahdesu/go-rados/rados" + "github.com/noahdesu/go-rados/rbd" + "github.com/stretchr/testify/assert" + "os/exec" + "sort" +) + +func GetUUID() string { + out, _ := exec.Command("uuidgen").Output() + return string(out[:36]) +} + +func TestVersion(t *testing.T) { + var major, minor, patch = rbd.Version() + assert.False(t, major < 0 || major > 1000, "invalid major") + assert.False(t, minor < 0 || minor > 1000, "invalid minor") + assert.False(t, patch < 0 || patch > 1000, "invalid patch") +} + +func TestGetImageNames(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) + assert.NoError(t, err) + + createdList := []string{} + for i := 0; i < 10; i++ { + name := GetUUID() + err = rbd.Create(ioctx, name, 1<<22) + assert.NoError(t, err) + createdList = append(createdList, name) + } + + imageNames, err := rbd.GetImageNames(ioctx) + assert.NoError(t, err) + + sort.Strings(createdList) + sort.Strings(imageNames) + assert.Equal(t, createdList, imageNames) + + ioctx.Destroy() + conn.Shutdown() +}