mirror of https://github.com/ceph/go-ceph
rbd: add ListMetadata implementing rbd_metadata_list
The function is named ListMetadata but returns a map of all the metadata assigned to the rbd image. It is named ListMetadata to match the C librbd api call. Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
parent
6bc6c7c3b1
commit
e7791c9e06
|
@ -8,6 +8,7 @@ import "C"
|
|||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/ceph/go-ceph/internal/cutil"
|
||||
"github.com/ceph/go-ceph/internal/retry"
|
||||
)
|
||||
|
||||
|
@ -84,3 +85,65 @@ func (image *Image) RemoveMetadata(key string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListMetadata returns a map containing all metadata assigned to the RBD image.
|
||||
//
|
||||
// Implements:
|
||||
// int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
|
||||
// char *keys, size_t *key_len, char *values, size_t *vals_len);
|
||||
func (image *Image) ListMetadata() (map[string]string, error) {
|
||||
if err := image.validate(imageIsOpen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
keysbuf []byte
|
||||
keysSize C.size_t
|
||||
valsbuf []byte
|
||||
valsSize C.size_t
|
||||
)
|
||||
retry.WithSizes(4096, 262144, func(size int) retry.Hint {
|
||||
keysbuf = make([]byte, size)
|
||||
keysSize = C.size_t(size)
|
||||
valsbuf = make([]byte, size)
|
||||
valsSize = C.size_t(size)
|
||||
// the rbd_metadata_list function can use a start point and a limit.
|
||||
// we do not use it and prefer our retry helper and just allocating
|
||||
// buffers large enough to take all the keys and values
|
||||
ret := C.rbd_metadata_list(
|
||||
image.image,
|
||||
(*C.char)(unsafe.Pointer(&empty[0])), // always start at the beginning (no paging)
|
||||
0, // fetch all key-value pairs
|
||||
(*C.char)(unsafe.Pointer(&keysbuf[0])),
|
||||
&keysSize,
|
||||
(*C.char)(unsafe.Pointer(&valsbuf[0])),
|
||||
&valsSize)
|
||||
|
||||
err = getError(ret)
|
||||
nextSize := valsSize
|
||||
if keysSize > nextSize {
|
||||
nextSize = keysSize
|
||||
}
|
||||
return retry.Size(int(nextSize)).If(err == errRange)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := map[string]string{}
|
||||
keys := cutil.SplitBuffer(keysbuf[:keysSize])
|
||||
vals := cutil.SplitBuffer(valsbuf[:valsSize])
|
||||
if len(keys) != len(vals) {
|
||||
// this should not happen (famous last words)
|
||||
return nil, errRange
|
||||
}
|
||||
for i := range keys {
|
||||
m[keys[i]] = vals[i]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// rather than allocate memory every time that ListMetadata is called,
|
||||
// define a static byte slice to stand in for the C "empty string"
|
||||
var empty = []byte{0}
|
||||
|
|
|
@ -39,6 +39,9 @@ func TestImageMetadata(t *testing.T) {
|
|||
value, err = image.GetMetadata(metadataKey)
|
||||
assert.Equal(t, "", value)
|
||||
assert.Equal(t, err, ErrImageNotOpen)
|
||||
// check ListMetadata for unopened image
|
||||
_, err = image.ListMetadata()
|
||||
assert.Equal(t, err, ErrImageNotOpen)
|
||||
|
||||
image, err = OpenImage(ioctx, name, NoSnapshot)
|
||||
assert.NoError(t, err)
|
||||
|
@ -50,6 +53,13 @@ func TestImageMetadata(t *testing.T) {
|
|||
value, err = image.GetMetadata(metadataKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, metadataValue, value)
|
||||
// List metadata
|
||||
mm, err := image.ListMetadata()
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, mm, 1)
|
||||
if assert.Contains(t, mm, metadataKey) {
|
||||
assert.Equal(t, mm[metadataKey], metadataValue)
|
||||
}
|
||||
// Remove the metadata key
|
||||
err = image.RemoveMetadata(metadataKey)
|
||||
assert.NoError(t, err)
|
||||
|
@ -58,6 +68,27 @@ func TestImageMetadata(t *testing.T) {
|
|||
assert.Equal(t, "", value)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Set some additional metadata values
|
||||
m1 := map[string]string{
|
||||
metadataKey: metadataValue,
|
||||
"k2": "himalayas",
|
||||
"matterhorn": "alps",
|
||||
"aconcagua": "andes",
|
||||
}
|
||||
for k, v := range m1 {
|
||||
err = image.SetMetadata(k, v)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
// Get the metadata value
|
||||
value, err = image.GetMetadata(metadataKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, metadataValue, value)
|
||||
// List metadata
|
||||
mm, err = image.ListMetadata()
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, mm, 4)
|
||||
assert.Equal(t, m1, mm)
|
||||
|
||||
err = image.Close()
|
||||
assert.NoError(t, err)
|
||||
err = image.Remove()
|
||||
|
|
Loading…
Reference in New Issue