From c06593eef75ecb26a51bb58f8b926e14eb4463a5 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 26 Nov 2019 10:08:56 +0100 Subject: [PATCH] rbd: add support for RbdImageOptions There are several RbdImageOptions that can be used to configure features of an RBD image while creating, cloning, migrating and copying. A follow-up patch will add Create4() where the RbdImageOptions can be used. Signed-off-by: Niels de Vos --- rbd/options.go | 122 ++++++++++++++++++++++++++++++++++ rbd/options_test.go | 155 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 rbd/options.go create mode 100644 rbd/options_test.go diff --git a/rbd/options.go b/rbd/options.go new file mode 100644 index 0000000..b5aa179 --- /dev/null +++ b/rbd/options.go @@ -0,0 +1,122 @@ +package rbd + +// #cgo LDFLAGS: -lrbd +// #include +// #include +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 +} diff --git a/rbd/options_test.go b/rbd/options_test.go new file mode 100644 index 0000000..2f16ce2 --- /dev/null +++ b/rbd/options_test.go @@ -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() +}