Allow downgrade from any mode to mode 1 or 2. Allow setting all dual writer combinations (#95968)

* Allow downgrade from any mode to mode 1 or 2

* Allow for all combinations of dual writer setting

* Add all cases

* Include mode3
This commit is contained in:
Leonor Oliveira
2024-11-11 10:52:36 +01:00
committed by GitHub
parent ee7f521c08
commit a1de4cc5fc
2 changed files with 36 additions and 42 deletions
+13 -27
View File
@@ -169,6 +169,7 @@ func SetDualWritingMode(
"2": Mode2,
"3": Mode3,
"4": Mode4,
"5": Mode5,
}
errDualWriterSetCurrentMode := errors.New("failed to set current dual writing mode")
@@ -195,33 +196,14 @@ func SetDualWritingMode(
}
}
// Desired mode is 2 and current mode is 1
if (desiredMode == Mode2) && (currentMode == Mode1) {
// This is where we go through the different gates to allow the instance to migrate from mode 1 to mode 2.
// There are none between mode 1 and mode 2
currentMode = Mode2
switch {
case desiredMode == Mode2 || desiredMode == Mode1:
currentMode = desiredMode
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
if err != nil {
return Mode0, errDualWriterSetCurrentMode
}
}
if (desiredMode == Mode1) && (currentMode == Mode2) {
// This is where we go through the different gates to allow the instance to migrate from mode 2 to mode 1.
// There are none between mode 1 and mode 2
currentMode = Mode1
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
if err != nil {
return Mode0, errDualWriterSetCurrentMode
}
}
if (desiredMode == Mode3) && (currentMode == Mode2) {
// This is where we go through the different gates to allow the instance to migrate from mode 2 to mode 3.
// gate #1: ensure the data is 100% in sync
case desiredMode >= Mode3 && currentMode < Mode3:
syncOk, err := runDataSyncer(ctx, currentMode, legacy, storage, entity, reg, serverLockService, requestInfo)
if err != nil {
klog.Info("data syncer failed for mode:", m)
@@ -236,12 +218,16 @@ func SetDualWritingMode(
if err != nil {
return currentMode, errDualWriterSetCurrentMode
}
return desiredMode, nil
case desiredMode >= Mode3 && currentMode >= Mode3:
currentMode = desiredMode
err := kvs.Set(ctx, entity, fmt.Sprint(currentMode))
if err != nil {
return currentMode, errDualWriterSetCurrentMode
}
default:
return Mode0, errDualWriterSetCurrentMode
}
// #TODO add support for other combinations of desired and current modes
return currentMode, nil
}
+23 -15
View File
@@ -2,7 +2,6 @@ package rest
import (
"context"
"fmt"
"testing"
"time"
@@ -17,25 +16,42 @@ import (
func TestSetDualWritingMode(t *testing.T) {
type testCase struct {
name string
stackID string
kvStore *fakeNamespacedKV
desiredMode DualWriterMode
expectedMode DualWriterMode
}
tests :=
// #TODO add test cases for kv store failures. Requires adding support in kvstore test_utils.go
[]testCase{
{
name: "should return a mode 2 dual writer when mode 2 is set as the desired mode",
stackID: "stack-1",
kvStore: &fakeNamespacedKV{data: map[string]string{"playlist.grafana.app/playlists": "2"}, namespace: "storage.dualwriting"},
desiredMode: Mode2,
expectedMode: Mode2,
},
{
name: "should return a mode 1 dual writer when mode 1 is set as the desired mode",
stackID: "stack-1",
kvStore: &fakeNamespacedKV{data: map[string]string{"playlist.grafana.app/playlists": "2"}, namespace: "storage.dualwriting"},
desiredMode: Mode1,
expectedMode: Mode1,
},
{
name: "should return mode 3 as desired mode when current mode is > 3",
kvStore: &fakeNamespacedKV{data: map[string]string{"playlist.grafana.app/playlists": "5"}, namespace: "storage.dualwriting"},
desiredMode: Mode3,
expectedMode: Mode3,
},
{
name: "should return mode 3 as desired mode when current mode is 2",
kvStore: &fakeNamespacedKV{data: map[string]string{"playlist.grafana.app/playlists": "2"}, namespace: "storage.dualwriting"},
desiredMode: Mode3,
expectedMode: Mode3,
},
{
name: "should default to mode 0 if there is no desired mode",
kvStore: &fakeNamespacedKV{data: map[string]string{}, namespace: "storage.dualwriting"},
desiredMode: Mode0,
expectedMode: Mode0,
},
}
for _, tt := range tests {
@@ -49,17 +65,9 @@ func TestSetDualWritingMode(t *testing.T) {
ls := legacyStoreMock{m, l}
us := storageMock{m, s}
kvStore := &fakeNamespacedKV{data: make(map[string]string), namespace: "storage.dualwriting." + tt.stackID}
dwMode, err := SetDualWritingMode(context.Background(), kvStore, ls, us, "playlist.grafana.app/v0alpha1", tt.desiredMode, p, &fakeServerLock{}, &request.RequestInfo{})
dwMode, err := SetDualWritingMode(context.Background(), tt.kvStore, ls, us, "playlist.grafana.app/playlists", tt.desiredMode, p, &fakeServerLock{}, &request.RequestInfo{})
assert.NoError(t, err)
assert.Equal(t, tt.expectedMode, dwMode)
// check kv store
val, ok, err := kvStore.Get(context.Background(), "playlist.grafana.app/v0alpha1")
assert.True(t, ok)
assert.NoError(t, err)
assert.Equal(t, val, fmt.Sprint(tt.expectedMode))
}
}
@@ -113,7 +121,7 @@ type fakeNamespacedKV struct {
}
func (f *fakeNamespacedKV) Get(ctx context.Context, key string) (string, bool, error) {
val, ok := f.data[f.namespace+key]
val, ok := f.data[key]
return val, ok, nil
}