mirror of
https://github.com/ceph/go-ceph
synced 2024-12-25 15:42:30 +00:00
rbd: add MirrorImageStatusSummary implementing rbd_mirror_image_status_summary
The MirrorImageStatusSummary returns a map of image mirroring states to the number of images in those states or an error. Tests of both the basic conditions and actual mirrored images are added. Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
parent
c45fa95b32
commit
d37951f7cd
@ -421,3 +421,49 @@ func (image *Image) CreateMirrorSnapshot() (uint64, error) {
|
||||
&snapID)
|
||||
return uint64(snapID), getError(ret)
|
||||
}
|
||||
|
||||
// MirrorImageStatusSummary returns a map of images statuses and the count
|
||||
// of images with said status.
|
||||
//
|
||||
// Implements:
|
||||
// int rbd_mirror_image_status_summary(
|
||||
// rados_ioctx_t io_ctx, rbd_mirror_image_status_state_t *states, int *counts,
|
||||
// size_t *maxlen);
|
||||
func MirrorImageStatusSummary(
|
||||
ioctx *rados.IOContext) (map[MirrorImageStatusState]uint, error) {
|
||||
// ideally, we already know the size of the arrays - they should be
|
||||
// the size of all the values of the rbd_mirror_image_status_state_t
|
||||
// enum. But the C api doesn't enforce this so we give a little
|
||||
// wiggle room in case the server returns values outside the enum
|
||||
// we know about. This is the only case I can think of that we'd
|
||||
// be able to get -ERANGE.
|
||||
var (
|
||||
cioctx = cephIoctx(ioctx)
|
||||
err error
|
||||
cStates []C.rbd_mirror_image_status_state_t
|
||||
cCounts []C.int
|
||||
cSize C.size_t
|
||||
)
|
||||
retry.WithSizes(16, 1<<16, func(size int) retry.Hint {
|
||||
cSize = C.size_t(size)
|
||||
cStates = make([]C.rbd_mirror_image_status_state_t, cSize)
|
||||
cCounts = make([]C.int, cSize)
|
||||
ret := C.rbd_mirror_image_status_summary(
|
||||
cioctx,
|
||||
(*C.rbd_mirror_image_status_state_t)(&cStates[0]),
|
||||
(*C.int)(&cCounts[0]),
|
||||
&cSize)
|
||||
err = getErrorIfNegative(ret)
|
||||
return retry.Size(int(cSize)).If(err == errRange)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := map[MirrorImageStatusState]uint{}
|
||||
for i := 0; i < int(cSize); i++ {
|
||||
s := MirrorImageStatusState(cStates[i])
|
||||
m[s] = uint(cCounts[i])
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
@ -463,3 +463,127 @@ func TestGetGlobalMirrorStatusMirroredPool(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMirrorImageStatusSummary(t *testing.T) {
|
||||
t.Run("ioctxNil", func(t *testing.T) {
|
||||
assert.Panics(t, func() {
|
||||
MirrorImageStatusSummary(nil)
|
||||
})
|
||||
})
|
||||
t.Run("emptyPool", func(t *testing.T) {
|
||||
conn := radosConnect(t)
|
||||
poolName := GetUUID()
|
||||
err := conn.MakePool(poolName)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, conn.DeletePool(poolName))
|
||||
conn.Shutdown()
|
||||
}()
|
||||
|
||||
ioctx, err := conn.OpenIOContext(poolName)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
ioctx.Destroy()
|
||||
}()
|
||||
|
||||
ssum, err := MirrorImageStatusSummary(ioctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, ssum, 0)
|
||||
})
|
||||
t.Run("mirroredPool", testMirrorImageStatusSummaryMirroredPool)
|
||||
}
|
||||
|
||||
func testMirrorImageStatusSummaryMirroredPool(t *testing.T) {
|
||||
mconfig := mirrorConfig()
|
||||
if mconfig == "" {
|
||||
t.Skip("no mirror config env var set")
|
||||
}
|
||||
conn := radosConnect(t)
|
||||
// this test assumes the rbd pool already exists and is mirrored
|
||||
// this must be set up previously by the CI or manually
|
||||
poolName := "rbd"
|
||||
|
||||
ioctx, err := conn.OpenIOContext(poolName)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
ioctx.Destroy()
|
||||
}()
|
||||
|
||||
imgBase := GetUUID()
|
||||
imgName1 := imgBase + "a"
|
||||
imgName2 := imgBase + "b"
|
||||
imgName3 := imgBase + "c"
|
||||
imgName4 := imgBase + "d"
|
||||
|
||||
options := NewRbdImageOptions()
|
||||
assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
|
||||
|
||||
for _, n := range []string{imgName1, imgName2, imgName3, imgName4} {
|
||||
err = CreateImage(ioctx, n, testImageSize, options)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func(n string) {
|
||||
err = RemoveImage(ioctx, n)
|
||||
assert.NoError(t, err)
|
||||
}(n)
|
||||
}
|
||||
|
||||
mkMirror := func(n string) {
|
||||
img, err := OpenImage(ioctx, n, NoSnapshot)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, img.Close())
|
||||
}()
|
||||
|
||||
err = img.MirrorEnable(ImageMirrorModeSnapshot)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mid, err := img.CreateMirrorSnapshot()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, mid)
|
||||
}
|
||||
|
||||
checkMirror := func(n string) {
|
||||
img, err := OpenImage(ioctx, n, NoSnapshot)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, img.Close())
|
||||
}()
|
||||
|
||||
// wait for site statuses to get updated
|
||||
for i := 0; i < 30; i++ {
|
||||
gms, err := img.GetGlobalMirrorStatus()
|
||||
assert.NoError(t, err)
|
||||
if len(gms.SiteStatuses) > 1 {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for _, n := range []string{imgName1, imgName3} {
|
||||
mkMirror(n)
|
||||
}
|
||||
for _, n := range []string{imgName1, imgName3} {
|
||||
checkMirror(n)
|
||||
}
|
||||
|
||||
ssum, err := MirrorImageStatusSummary(ioctx)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, ssum, 1) {
|
||||
assert.Contains(t, ssum, MirrorImageStatusStateReplaying)
|
||||
assert.GreaterOrEqual(t, ssum[MirrorImageStatusStateReplaying], uint(2))
|
||||
}
|
||||
|
||||
// immediately going for status right after enabling mirroring and not
|
||||
// waiting for things to settle should give us one unknown status
|
||||
mkMirror(imgName2)
|
||||
ssum, err = MirrorImageStatusSummary(ioctx)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, ssum, 2) {
|
||||
assert.Contains(t, ssum, MirrorImageStatusStateReplaying)
|
||||
assert.GreaterOrEqual(t, ssum[MirrorImageStatusStateReplaying], uint(2))
|
||||
assert.Contains(t, ssum, MirrorImageStatusStateUnknown)
|
||||
assert.GreaterOrEqual(t, ssum[MirrorImageStatusStateUnknown], uint(1))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user