diff --git a/pkg/apiserver/rest/dualwriter.go b/pkg/apiserver/rest/dualwriter.go index 75d2d76565f..e803849ddbc 100644 --- a/pkg/apiserver/rest/dualwriter.go +++ b/pkg/apiserver/rest/dualwriter.go @@ -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 } diff --git a/pkg/apiserver/rest/dualwriter_test.go b/pkg/apiserver/rest/dualwriter_test.go index 198d66fa028..583aa284832 100644 --- a/pkg/apiserver/rest/dualwriter_test.go +++ b/pkg/apiserver/rest/dualwriter_test.go @@ -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 }