DualWriter: Error when folder+dashboard modes do not match when running mode4+ (#111286)

This commit is contained in:
Ryan McKinley
2025-09-18 16:43:39 +03:00
committed by GitHub
parent 9d822646dd
commit 9743e0c903
5 changed files with 79 additions and 36 deletions
@@ -77,7 +77,8 @@ func TestRuntime_Create(t *testing.T) {
tt.setupStorageFn(us.Mock, tt.input)
}
m := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), nil, kvstore.NewFakeKVStore(), nil)
m, err := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), kvstore.NewFakeKVStore(), nil)
require.NoError(t, err)
dw, err := m.NewStorage(kind, ls, us)
require.NoError(t, err)
@@ -149,7 +150,8 @@ func TestRuntime_Get(t *testing.T) {
tt.setupStorageFn(us.Mock, name)
}
m := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), nil, kvstore.NewFakeKVStore(), nil)
m, err := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), kvstore.NewFakeKVStore(), nil)
require.NoError(t, err)
dw, err := m.NewStorage(kind, ls, us)
require.NoError(t, err)
status, err := m.Status(context.Background(), kind)
@@ -233,7 +235,8 @@ func TestRuntime_CreateWhileMigrating(t *testing.T) {
}
// Shared provider across all tests
dual := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), nil, kvstore.NewFakeKVStore(), nil)
dual, err := ProvideService(featuremgmt.WithFeatures(featuremgmt.FlagManagedDualWriter), kvstore.NewFakeKVStore(), nil)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+21 -22
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"time"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/grafana/grafana-app-sdk/logging"
@@ -24,39 +23,39 @@ func ProvideStaticServiceForTests(cfg *setting.Cfg) Service {
func ProvideService(
features featuremgmt.FeatureToggles,
reg prometheus.Registerer,
kv kvstore.KVStore,
cfg *setting.Cfg,
) Service {
) (Service, error) {
enabled := features.IsEnabledGlobally(featuremgmt.FlagManagedDualWriter) ||
features.IsEnabledGlobally(featuremgmt.FlagProvisioning) // required for git provisioning
if cfg != nil {
// Avoid dynamic behavior when things are explicitly configured to mode5
allMode5 := true
for _, gr := range []string{
"dashboards.dashboard.grafana.app",
"folders.folder.grafana.app",
} {
if cfg.UnifiedStorage[gr].DualWriterMode != rest.Mode5 {
allMode5 = false
break
if !enabled {
return &staticService{cfg}, nil
}
if cfg != nil {
foldersMode := cfg.UnifiedStorage["folders.folder.grafana.app"].DualWriterMode
dashboardsMode := cfg.UnifiedStorage["dashboards.dashboard.grafana.app"].DualWriterMode
// If both are fully on unified (Mode5), the dynamic service is not needed.
if foldersMode == rest.Mode5 && dashboardsMode == rest.Mode5 {
return &staticService{cfg}, nil
}
if (foldersMode >= rest.Mode4 || dashboardsMode >= rest.Mode4) && foldersMode != dashboardsMode {
return nil, fmt.Errorf("dashboards and folders must use the same mode when reading from unified storage")
}
}
if allMode5 || !enabled {
return &staticService{cfg} // fallback to using the dual write flags from cfg
}
}
db := &keyvalueDB{
db: kv,
logger: logging.DefaultLogger.With("logger", "dualwrite.kv"),
}
return &service{
db: db,
db: &keyvalueDB{
db: kv,
logger: logging.DefaultLogger.With("logger", "dualwrite.kv"),
},
enabled: enabled,
}
}, nil
}
type service struct {
@@ -17,7 +17,8 @@ import (
func TestService(t *testing.T) {
t.Run("dynamic", func(t *testing.T) {
ctx := context.Background()
mode := ProvideService(featuremgmt.WithFeatures(), nil, kvstore.NewFakeKVStore(), nil)
mode, err := ProvideService(featuremgmt.WithFeatures(), kvstore.NewFakeKVStore(), nil)
require.NoError(t, err)
gr := schema.GroupResource{Group: "ggg", Resource: "rrr"}
status, err := mode.Status(ctx, gr)
@@ -69,6 +70,7 @@ func TestService(t *testing.T) {
isStatic bool
foldersFromUnified bool
dashboardsFromUnified bool
error string
}
for _, tc := range []testCase{{
@@ -93,14 +95,40 @@ func TestService(t *testing.T) {
cfg: setting.Cfg{
UnifiedStorage: map[string]setting.UnifiedStorageConfig{
"dashboards.dashboard.grafana.app": {
DualWriterMode: rest.Mode5,
DualWriterMode: rest.Mode3,
},
},
}}, {
name: "invalid folder mode4",
flags: featuremgmt.WithFeatures(featuremgmt.FlagProvisioning),
error: "must use the same mode",
cfg: setting.Cfg{
UnifiedStorage: map[string]setting.UnifiedStorageConfig{
"folders.folder.grafana.app": {
DualWriterMode: rest.Mode4,
},
},
}}, {
name: "invalid dashboards mode4",
flags: featuremgmt.WithFeatures(featuremgmt.FlagProvisioning),
error: "must use the same mode",
cfg: setting.Cfg{
UnifiedStorage: map[string]setting.UnifiedStorageConfig{
"dashboards.dashboard.grafana.app": {
DualWriterMode: rest.Mode4,
},
},
}},
} {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
svc := ProvideService(tc.flags, nil, kvstore.NewFakeKVStore(), &tc.cfg)
svc, err := ProvideService(tc.flags, kvstore.NewFakeKVStore(), &tc.cfg)
if tc.error != "" {
require.ErrorContains(t, err, tc.error)
require.Nil(t, svc, "expect a nil service when an error exts")
return
}
require.NoError(t, err)
_, isStatic := svc.(*staticService)
require.Equal(t, tc.isStatic, isStatic)