From 65fd15bbf988b83fabd545b5bb33c4ae1fb9f8fc Mon Sep 17 00:00:00 2001 From: Rafael Bortolon Paulovic Date: Thu, 20 Nov 2025 15:47:44 +0100 Subject: [PATCH] feat: define unified disable migrations flag (#114120) chore: add US data migrations config --- pkg/setting/setting.go | 4 +- pkg/setting/setting_unified_storage.go | 57 +++++++++++++++++++- pkg/storage/unified/migrations/migrations.go | 8 ++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index fb69aa60259..a8b48c67f29 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -578,7 +578,9 @@ type Cfg struct { ShortLinkExpiration int // Unified Storage - UnifiedStorage map[string]UnifiedStorageConfig + UnifiedStorage map[string]UnifiedStorageConfig + // DisableDataMigrations will disable resources data migration to unified storage at startup + DisableDataMigrations bool MaxPageSizeBytes int IndexPath string IndexWorkers int diff --git a/pkg/setting/setting_unified_storage.go b/pkg/setting/setting_unified_storage.go index 15bed66b6bb..29cb5d0270a 100644 --- a/pkg/setting/setting_unified_storage.go +++ b/pkg/setting/setting_unified_storage.go @@ -5,8 +5,15 @@ import ( "time" "github.com/grafana/grafana/pkg/apiserver/rest" + "github.com/grafana/grafana/pkg/util/osutil" ) +var migratedUnifiedResources = []string{ + //"playlists.playlist.grafana.app", + "folders.folder.grafana.app", + "dashboards.dashboard.grafana.app", +} + // read storage configs from ini file. They look like: // [unified_storage..] // = @@ -51,8 +58,14 @@ func (cfg *Cfg) setUnifiedStorageConfig() { // Set indexer config for unified storage section := cfg.Raw.Section("unified_storage") - - cfg.EnableSearch = section.Key("enable_search").MustBool(false) + // TODO: Re-enable once migrations are ready and disabled on cloud + //cfg.DisableDataMigrations = section.Key("disable_data_migrations").MustBool(false) + cfg.DisableDataMigrations = true + if !cfg.DisableDataMigrations && cfg.getUnifiedStorageType() == "unified" { + cfg.enforceMigrationToUnifiedConfigs() + } else { + cfg.EnableSearch = section.Key("enable_search").MustBool(false) + } cfg.MaxPageSizeBytes = section.Key("max_page_size_bytes").MustInt(0) cfg.IndexPath = section.Key("index_path").String() cfg.IndexWorkers = section.Key("index_workers").MustInt(10) @@ -84,3 +97,43 @@ func (cfg *Cfg) setUnifiedStorageConfig() { cfg.MaxFileIndexAge = section.Key("max_file_index_age").MustDuration(0) cfg.MinFileIndexBuildVersion = section.Key("min_file_index_build_version").MustString("") } + +// enforceMigrationToUnifiedConfigs enforces configurations required to run migrated resources in mode 5 +// All migrated resources in MigratedUnifiedResources are set to mode 5 and unified search is enabled +func (cfg *Cfg) enforceMigrationToUnifiedConfigs() { + section := cfg.Raw.Section("unified_storage") + cfg.EnableSearch = section.Key("enable_search").MustBool(true) + if !cfg.EnableSearch { + cfg.Logger.Info("Enforcing enable_search for unified storage") + section.Key("enable_search").SetValue("true") + cfg.EnableSearch = true + } + for _, resource := range migratedUnifiedResources { + cfg.Logger.Info("Enforcing mode 5 for resource in unified storage", "resource", resource) + if oldCfg, ok := cfg.UnifiedStorage[resource]; ok { + cfg.Logger.Info("Overriding unified storage config for migrated resource", "resource", resource, "old_config", oldCfg) + } + cfg.UnifiedStorage[resource] = UnifiedStorageConfig{ + DualWriterMode: 5, + DualWriterMigrationDataSyncDisabled: true, + } + } +} + +// getUnifiedStorageType returns the configured storage type without creating or mutating keys. +// Precedence: env > ini > default ("unified"). +// Used to decide unified storage behavior early without side effects. +func (cfg *Cfg) getUnifiedStorageType() string { + const ( + grafanaAPIServerSectionName = "grafana-apiserver" + storageTypeKeyName = "storage_type" + defaultStorageType = "unified" + ) + if envStorageType := (osutil.RealEnv{}).Getenv(EnvKey(grafanaAPIServerSectionName, storageTypeKeyName)); envStorageType != "" { + return envStorageType + } + if cfg.Raw.Section(grafanaAPIServerSectionName).HasKey(storageTypeKeyName) { + return cfg.Raw.Section(grafanaAPIServerSectionName).Key(storageTypeKeyName).Value() + } + return defaultStorageType +} diff --git a/pkg/storage/unified/migrations/migrations.go b/pkg/storage/unified/migrations/migrations.go index 195b7f5d154..a30777e308a 100644 --- a/pkg/storage/unified/migrations/migrations.go +++ b/pkg/storage/unified/migrations/migrations.go @@ -17,6 +17,7 @@ import ( ) var tracer = otel.Tracer("github.com/grafana/grafana/pkg/storage/unified/migrations") +var logger = log.New("storage.unified.migrations") // UnifiedStorageMigrationProvider provides unified storage migrations as a background service type UnifiedStorageMigrationProvider interface { @@ -56,7 +57,11 @@ func (p *UnifiedStorageMigrationProviderImpl) Run(ctx context.Context) error { if os.Getenv("GRAFANA_TEST_DB") != "" { return nil } - + // skip migrations if disabled in config + if p.cfg.DisableDataMigrations { + logger.Info("Data migrations are disabled, skipping") + return nil + } // TODO: Re-enable once migrations are ready // return RegisterMigrations(p.legacyMigrator, p.cfg, p.client, p.sqlStore) return nil @@ -74,7 +79,6 @@ func RegisterMigrations( ) error { ctx, span := tracer.Start(context.Background(), "storage.unified.RegisterMigrations") defer span.End() - logger := log.New("storage.unified.migrations.folders-dashboards") mg := migrator.NewScopedMigrator(sqlStore.GetEngine(), cfg, "unified_storage") mg.AddCreateMigration()