mirror of https://github.com/ceph/go-ceph
rbd: add minimal support for listing watchers on an RBD image
Checking if there are other clients interested in changes to an RBD image is important for certain actions. For example, the Ceph-CSI project would not want to remove an image in case it is still mounted somewhere. Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
a65e39ca3d
commit
d0943906f7
|
@ -0,0 +1,57 @@
|
|||
// +build !luminous
|
||||
//
|
||||
// Ceph Mimic is the first version that supports watchers through librbd.
|
||||
|
||||
package rbd
|
||||
|
||||
// #cgo LDFLAGS: -lrbd
|
||||
// #include <errno.h>
|
||||
// #include <rbd/librbd.h>
|
||||
import "C"
|
||||
|
||||
// ImageWatcher is a representation of the rbd_image_watcher_t from librbd.h
|
||||
type ImageWatcher struct {
|
||||
Addr string
|
||||
Id int64
|
||||
Cookie uint64
|
||||
}
|
||||
|
||||
// ListWatchers returns the watchers on an RBD image. In case of an error, nil
|
||||
// and an error are returned.
|
||||
//
|
||||
// Note:
|
||||
// Only supported in Ceph Mimic and newer.
|
||||
//
|
||||
// Implements:
|
||||
// int rbd_watchers_list(rbd_image_t image,
|
||||
// rbd_image_watcher_t *watchers, size_t *max_watchers)
|
||||
func (image *Image) ListWatchers() ([]ImageWatcher, error) {
|
||||
if err := image.validate(imageIsOpen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := C.ulong(0)
|
||||
ret := C.rbd_watchers_list(image.image, nil, &count)
|
||||
if ret != 0 && ret != -C.ERANGE {
|
||||
return nil, getError(ret)
|
||||
}
|
||||
if ret == 0 && count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
watchers := make([]C.rbd_image_watcher_t, count)
|
||||
ret = C.rbd_watchers_list(image.image, &watchers[0], &count)
|
||||
if ret != 0 && ret != -C.ERANGE {
|
||||
return nil, getError(ret)
|
||||
}
|
||||
defer C.rbd_watchers_list_cleanup(&watchers[0], count)
|
||||
|
||||
imageWatchers := make([]ImageWatcher, len(watchers))
|
||||
for i, watcher := range watchers {
|
||||
imageWatchers[i].Addr = C.GoString(watcher.addr)
|
||||
imageWatchers[i].Id = int64(watcher.id)
|
||||
imageWatchers[i].Cookie = uint64(watcher.cookie)
|
||||
}
|
||||
|
||||
return imageWatchers, nil
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// +build !luminous
|
||||
//
|
||||
// Ceph Mimic is the first version that supports watchers through librbd.
|
||||
|
||||
package rbd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListWatchers(t *testing.T) {
|
||||
conn := radosConnect(t)
|
||||
require.NotNil(t, conn)
|
||||
defer conn.Shutdown()
|
||||
|
||||
poolname := GetUUID()
|
||||
err := conn.MakePool(poolname)
|
||||
require.NoError(t, err)
|
||||
defer conn.DeletePool(poolname)
|
||||
|
||||
ioctx, err := conn.OpenIOContext(poolname)
|
||||
require.NoError(t, err)
|
||||
defer ioctx.Destroy()
|
||||
|
||||
name := GetUUID()
|
||||
options := NewRbdImageOptions()
|
||||
err = CreateImage(ioctx, name, 1<<22, options)
|
||||
require.NoError(t, err)
|
||||
defer func() { assert.NoError(t, RemoveImage(ioctx, name)) }()
|
||||
|
||||
t.Run("imageNotOpen", func(t *testing.T) {
|
||||
image, err := OpenImageReadOnly(ioctx, name, NoSnapshot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, image)
|
||||
|
||||
err = image.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = image.ListWatchers()
|
||||
assert.Equal(t, ErrImageNotOpen, err)
|
||||
})
|
||||
|
||||
t.Run("noWatchers", func(t *testing.T) {
|
||||
// open image read-only, as OpenImage() automatically adds a watcher
|
||||
image, err := OpenImageReadOnly(ioctx, name, NoSnapshot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, image)
|
||||
defer func() { assert.NoError(t, image.Close()) }()
|
||||
|
||||
watchers, err := image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(watchers))
|
||||
})
|
||||
|
||||
t.Run("addWatchers", func(t *testing.T) {
|
||||
// open image read-only, as OpenImage() automatically adds a watcher
|
||||
image, err := OpenImageReadOnly(ioctx, name, NoSnapshot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, image)
|
||||
defer func() { assert.NoError(t, image.Close()) }()
|
||||
|
||||
watchers, err := image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(watchers))
|
||||
|
||||
// opening an image writable adds a watcher automatically
|
||||
image2, err := OpenImage(ioctx, name, NoSnapshot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, image2)
|
||||
|
||||
watchers, err = image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(watchers))
|
||||
|
||||
watchers, err = image2.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(watchers))
|
||||
|
||||
image3, err := OpenImage(ioctx, name, NoSnapshot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, image3)
|
||||
|
||||
watchers, err = image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(watchers))
|
||||
|
||||
watchers, err = image2.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(watchers))
|
||||
|
||||
watchers, err = image3.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(watchers))
|
||||
|
||||
// closing an image removes the watchers
|
||||
err = image3.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
watchers, err = image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(watchers))
|
||||
|
||||
watchers, err = image2.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(watchers))
|
||||
|
||||
err = image2.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
watchers, err = image.ListWatchers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(watchers))
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue