Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rbd_image_options_t #111

Merged
merged 3 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \
uuid-runtime \
wget

ARG CEPH_REPO_URL=https://download.ceph.com/debian-luminous/
ARG CEPH_REPO_URL=https://download.ceph.com/debian-nautilus/
nixpanic marked this conversation as resolved.
Show resolved Hide resolved
RUN wget -q -O- 'https://download.ceph.com/keys/release.asc' | apt-key add -
RUN apt-add-repository "deb ${CEPH_REPO_URL} xenial main"

Expand Down
122 changes: 122 additions & 0 deletions rbd/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package rbd

// #cgo LDFLAGS: -lrbd
// #include <stdlib.h>
// #include <rbd/librbd.h>
import "C"

import (
"fmt"
"unsafe"
)

const (
// RBD image options.
RbdImageOptionFormat = C.RBD_IMAGE_OPTION_FORMAT
RbdImageOptionFeatures = C.RBD_IMAGE_OPTION_FEATURES
RbdImageOptionOrder = C.RBD_IMAGE_OPTION_ORDER
RbdImageOptionStripeUnit = C.RBD_IMAGE_OPTION_STRIPE_UNIT
RbdImageOptionStripeCount = C.RBD_IMAGE_OPTION_STRIPE_COUNT
RbdImageOptionJournalOrder = C.RBD_IMAGE_OPTION_JOURNAL_ORDER
RbdImageOptionJournalSplayWidth = C.RBD_IMAGE_OPTION_JOURNAL_SPLAY_WIDTH
RbdImageOptionJournalPool = C.RBD_IMAGE_OPTION_JOURNAL_POOL
RbdImageOptionFeaturesSet = C.RBD_IMAGE_OPTION_FEATURES_SET
RbdImageOptionFeaturesClear = C.RBD_IMAGE_OPTION_FEATURES_CLEAR
RbdImageOptionDataPool = C.RBD_IMAGE_OPTION_DATA_POOL
// introduced with Ceph Mimic
//RbdImageOptionFlatten = C.RBD_IMAGE_OPTION_FLATTEN
)

type RbdImageOptions struct {
options C.rbd_image_options_t
}

type RbdImageOption C.int

func NewRbdImageOptions() *RbdImageOptions {
rio := &RbdImageOptions{}
C.rbd_image_options_create(&rio.options)
return rio
}

func (rio *RbdImageOptions) Destroy() {
C.rbd_image_options_destroy(rio.options)
}

func (rio *RbdImageOptions) SetString(option RbdImageOption, value string) error {
c_value := C.CString(value)
defer C.free(unsafe.Pointer(c_value))

ret := C.rbd_image_options_set_string(rio.options, C.int(option), c_value)
if ret != 0 {
return fmt.Errorf("%v, could not set option %v to \"%v\"",
GetError(ret), option, value)
}

return nil
}

func (rio *RbdImageOptions) GetString(option RbdImageOption) (string, error) {
value := make([]byte, 4096)

ret := C.rbd_image_options_get_string(rio.options, C.int(option),
(*C.char)(unsafe.Pointer(&value[0])),
C.size_t(len(value)))
if ret != 0 {
return "", fmt.Errorf("%v, could not get option %v", GetError(ret), option)
}

return C.GoString((*C.char)(unsafe.Pointer(&value[0]))), nil
}

func (rio *RbdImageOptions) SetUint64(option RbdImageOption, value uint64) error {
c_value := C.uint64_t(value)

ret := C.rbd_image_options_set_uint64(rio.options, C.int(option), c_value)
if ret != 0 {
return fmt.Errorf("%v, could not set option %v to \"%v\"",
GetError(ret), option, value)
}

return nil
}

func (rio *RbdImageOptions) GetUint64(option RbdImageOption) (uint64, error) {
var c_value C.uint64_t

ret := C.rbd_image_options_get_uint64(rio.options, C.int(option), &c_value)
if ret != 0 {
return 0, fmt.Errorf("%v, could not get option %v", GetError(ret), option)
}

return uint64(c_value), nil
}

func (rio *RbdImageOptions) IsSet(option RbdImageOption) (bool, error) {
var c_set C.bool

ret := C.rbd_image_options_is_set(rio.options, C.int(option), &c_set)
if ret != 0 {
return false, fmt.Errorf("%v, could not check option %v", GetError(ret), option)
}

return bool(c_set), nil
}

func (rio *RbdImageOptions) Unset(option RbdImageOption) error {
ret := C.rbd_image_options_unset(rio.options, C.int(option))
if ret != 0 {
return fmt.Errorf("%v, could not unset option %v", GetError(ret), option)
}

return nil
}

func (rio *RbdImageOptions) Clear() {
C.rbd_image_options_clear(rio.options)
}

func (rio *RbdImageOptions) IsEmpty() bool {
ret := C.rbd_image_options_is_empty(rio.options)
return ret != 0
}
155 changes: 155 additions & 0 deletions rbd/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package rbd_test

import (
"github.com/ceph/go-ceph/rbd"
"github.com/stretchr/testify/assert"
"testing"
)

func TestRbdOptions(t *testing.T) {
var i uint64
var s string
var err error

options := rbd.NewRbdImageOptions()
defer options.Destroy()

err = options.SetUint64(rbd.RbdImageOptionFormat, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionFormat, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionFormat)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionFormat)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionFeatures, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionFeatures, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionFeatures)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionFeatures)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionOrder, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionOrder, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionOrder)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionOrder)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionStripeUnit, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionStripeUnit, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionStripeUnit)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionStripeUnit)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionStripeCount, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionStripeCount, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionStripeCount)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionStripeCount)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionJournalOrder, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionJournalOrder, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionJournalOrder)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionJournalOrder)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionJournalSplayWidth, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionJournalSplayWidth, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionJournalSplayWidth)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionJournalSplayWidth)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionJournalPool, 1)
assert.Error(t, err)
err = options.SetString(rbd.RbdImageOptionJournalPool, "journal")
assert.NoError(t, err)
_, err = options.GetUint64(rbd.RbdImageOptionJournalPool)
assert.Error(t, err)
s, err = options.GetString(rbd.RbdImageOptionJournalPool)
assert.NoError(t, err)
assert.True(t, s == "journal")

err = options.SetUint64(rbd.RbdImageOptionFeaturesSet, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionFeaturesSet, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionFeaturesSet)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionFeaturesSet)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionFeaturesClear, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionFeaturesClear, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionFeaturesClear)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionFeaturesClear)
assert.Error(t, err)

err = options.SetUint64(rbd.RbdImageOptionDataPool, 1)
assert.Error(t, err)
err = options.SetString(rbd.RbdImageOptionDataPool, "data")
assert.NoError(t, err)
_, err = options.GetUint64(rbd.RbdImageOptionDataPool)
assert.Error(t, err)
s, err = options.GetString(rbd.RbdImageOptionDataPool)
assert.NoError(t, err)
assert.True(t, s == "data")

/* introduced with Ceph Mimic, can not be tested on Luminous
err = options.SetUint64(rbd.RbdImageOptionFlatten, 1)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionFlatten, "string not allowed")
assert.Error(t, err)
i, err = options.GetUint64(rbd.RbdImageOptionFlatten)
assert.NoError(t, err)
assert.True(t, i == 1)
_, err = options.GetString(rbd.RbdImageOptionFlatten)
assert.Error(t, err)
*/
}

func TestRbdOptionsClear(t *testing.T) {
options := rbd.NewRbdImageOptions()

// set at least one option
err := options.SetUint64(rbd.RbdImageOptionFormat, 1)
assert.NoError(t, err)

empty := options.IsEmpty()
assert.False(t, empty)

options.Clear()
empty = options.IsEmpty()
assert.True(t, empty)

options.Destroy()
}
23 changes: 23 additions & 0 deletions rbd/rbd.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,29 @@ func Create3(ioctx *rados.IOContext, name string, size uint64, features uint64,
}, nil
}

// int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
// rbd_image_options_t opts);
func Create4(ioctx *rados.IOContext, name string, size uint64, rio *RbdImageOptions) (image *Image, err error) {
if rio == nil {
return nil, RBDError(C.EINVAL)
}

c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))

ret := C.rbd_create4(C.rados_ioctx_t(ioctx.Pointer()), c_name,
C.uint64_t(size), C.rbd_image_options_t(rio.options))

if ret < 0 {
return nil, RBDError(ret)
}

return &Image{
ioctx: ioctx,
name: name,
}, nil
}

// int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
// const char *p_snapname, rados_ioctx_t c_ioctx,
// const char *c_name, uint64_t features, int *c_order);
Expand Down
56 changes: 56 additions & 0 deletions rbd/rbd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,62 @@ func TestImageCreate3(t *testing.T) {
conn.Shutdown()
}

func TestCreateImageWithOptions(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)

// nil options, causes a panic if not handled correctly
name := GetUUID()
image, err := rbd.Create4(ioctx, name, 1<<22, nil)
assert.Error(t, err)

options := rbd.NewRbdImageOptions()

// empty/default options
name = GetUUID()
image, err = rbd.Create4(ioctx, name, 1<<22, options)
assert.NoError(t, err)
err = image.Remove()
assert.NoError(t, err)

// create image with RbdImageOptionOrder
err = options.SetUint64(rbd.RbdImageOptionOrder, 22)
assert.NoError(t, err)
name = GetUUID()
image, err = rbd.Create4(ioctx, name, 1<<22, options)
assert.NoError(t, err)
err = image.Remove()
assert.NoError(t, err)
options.Clear()

// create image with a different data pool
datapool := GetUUID()
err = conn.MakePool(datapool)
assert.NoError(t, err)
err = options.SetString(rbd.RbdImageOptionDataPool, datapool)
assert.NoError(t, err)
name = GetUUID()
image, err = rbd.Create4(ioctx, name, 1<<22, options)
assert.NoError(t, err)
err = image.Remove()
assert.NoError(t, err)
conn.DeletePool(datapool)

// cleanup
options.Destroy()
ioctx.Destroy()
conn.DeletePool(poolname)
conn.Shutdown()
}

func TestGetImageNames(t *testing.T) {
conn, _ := rados.NewConn()
conn.ReadDefaultConfigFile()
Expand Down