Alerting: Change rule migration to be based on feature flag (#33792)

makes it so the feature flag can be turned on off, and the migration will be cleared and rerun. All existing NG alert rules, configuration settings, etc are removed when disabling the feature flag.
for https://github.com/grafana/alerting-squad/issues/142

Co-authored-by: Sofia Papagiannaki <sofia@grafana.com>
pull/33758/head^2
Kyle Brandt 5 years ago committed by GitHub
parent ac44a679a7
commit dc3e17ba5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      pkg/services/sqlstore/migrations/migrations_test.go
  2. 5
      pkg/services/sqlstore/migrations/ualert/permissions.go
  3. 76
      pkg/services/sqlstore/migrations/ualert/ualert.go
  4. 15
      pkg/services/sqlstore/migrator/migrator.go
  5. 2
      pkg/services/sqlstore/sqlstore.go

@ -5,6 +5,7 @@ import (
. "github.com/grafana/grafana/pkg/services/sqlstore/migrator" . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"xorm.io/xorm" "xorm.io/xorm"
) )
@ -23,7 +24,7 @@ func TestMigrations(t *testing.T) {
_, err = x.SQL(query).Get(&result) _, err = x.SQL(query).Get(&result)
require.Error(t, err) require.Error(t, err)
mg := NewMigrator(x) mg := NewMigrator(x, &setting.Cfg{})
AddMigrations(mg) AddMigrations(mg)
expectedMigrations := mg.MigrationsCount() expectedMigrations := mg.MigrationsCount()
@ -36,7 +37,7 @@ func TestMigrations(t *testing.T) {
require.Equal(t, expectedMigrations, result.Count) require.Equal(t, expectedMigrations, result.Count)
mg = NewMigrator(x) mg = NewMigrator(x, &setting.Cfg{})
AddMigrations(mg) AddMigrations(mg)
err = mg.Start() err = mg.Start()

@ -44,7 +44,6 @@ func (m *migration) createFolder(orgID int64, title string) (*dashboard, error)
}), }),
} }
dash := cmd.getDashboardModel() dash := cmd.getDashboardModel()
var userId int64 = -1
uid, err := m.generateNewDashboardUid(dash.OrgId) uid, err := m.generateNewDashboardUid(dash.OrgId)
if err != nil { if err != nil {
@ -55,9 +54,9 @@ func (m *migration) createFolder(orgID int64, title string) (*dashboard, error)
parentVersion := dash.Version parentVersion := dash.Version
dash.setVersion(1) dash.setVersion(1)
dash.Created = time.Now() dash.Created = time.Now()
dash.CreatedBy = userId dash.CreatedBy = FOLDER_CREATED_BY
dash.Updated = time.Now() dash.Updated = time.Now()
dash.UpdatedBy = userId dash.UpdatedBy = FOLDER_CREATED_BY
metrics.MApiDashboardInsert.Inc() metrics.MApiDashboardInsert.Inc()
if _, err = m.sess.Insert(dash); err != nil { if _, err = m.sess.Insert(dash); err != nil {

@ -11,6 +11,14 @@ import (
const GENERAL_FOLDER = "General Alerting" const GENERAL_FOLDER = "General Alerting"
const DASHBOARD_FOLDER = "Migrated %s" const DASHBOARD_FOLDER = "Migrated %s"
// FOLDER_CREATED_BY us used to track folders created by this migration
// during alert migration cleanup.
const FOLDER_CREATED_BY = -8
var migTitle = "move dashboard alerts to unified alerting"
var rmMigTitle = "remove unified alerting data"
type MigrationError struct { type MigrationError struct {
AlertId int64 AlertId int64
Err error Err error
@ -26,7 +34,31 @@ func AddMigration(mg *migrator.Migrator) {
if os.Getenv("UALERT_MIG") == "iDidBackup" { if os.Getenv("UALERT_MIG") == "iDidBackup" {
// TODO: unified alerting DB needs to be extacted into ../migrations.go // TODO: unified alerting DB needs to be extacted into ../migrations.go
// so it runs and creates the tables before this migration runs. // so it runs and creates the tables before this migration runs.
mg.AddMigration("move dashboard alerts to unified alerting", &migration{}) logs, err := mg.GetMigrationLog()
if err != nil {
mg.Logger.Crit("alert migration failure: could not get migration log", "error", err)
os.Exit(1)
}
_, migrationRun := logs[migTitle]
ngEnabled := mg.Cfg.IsNgAlertEnabled()
switch {
case ngEnabled && !migrationRun:
// clear the entry of the migration that
err = mg.ClearMigrationEntry(rmMigTitle)
if err != nil {
mg.Logger.Error("alert migration error: could not clear alert migration for removing data", "error", err)
}
mg.AddMigration(migTitle, &migration{})
case !ngEnabled && migrationRun:
err = mg.ClearMigrationEntry(migTitle)
if err != nil {
mg.Logger.Error("alert migration error: could not clear alert migration", "error", err)
}
mg.AddMigration(rmMigTitle, &rmMigration{})
}
} }
} }
@ -184,3 +216,45 @@ func (m *migration) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
return nil return nil
} }
type rmMigration struct {
migrator.MigrationBase
}
func (m *rmMigration) SQL(dialect migrator.Dialect) string {
return "code migration"
}
func (m *rmMigration) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
_, err := sess.Exec("delete from alert_rule")
if err != nil {
return err
}
_, err = sess.Exec("delete from alert_rule_version")
if err != nil {
return err
}
_, err = sess.Exec("delete from dashboard_acl where dashboard_id IN (select id from dashboard where created_by = ?)", FOLDER_CREATED_BY)
if err != nil {
return err
}
_, err = sess.Exec("delete from dashboard where created_by = ?", FOLDER_CREATED_BY)
if err != nil {
return err
}
_, err = sess.Exec("delete from alert_configuration")
if err != nil {
return err
}
_, err = sess.Exec("delete from alert_instance")
if err != nil {
return err
}
return nil
}

@ -6,6 +6,7 @@ import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil" "github.com/grafana/grafana/pkg/util/errutil"
_ "github.com/lib/pq" _ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -17,6 +18,7 @@ type Migrator struct {
Dialect Dialect Dialect Dialect
migrations []Migration migrations []Migration
Logger log.Logger Logger log.Logger
Cfg *setting.Cfg
} }
type MigrationLog struct { type MigrationLog struct {
@ -28,12 +30,13 @@ type MigrationLog struct {
Timestamp time.Time Timestamp time.Time
} }
func NewMigrator(engine *xorm.Engine) *Migrator { func NewMigrator(engine *xorm.Engine, cfg *setting.Cfg) *Migrator {
mg := &Migrator{} mg := &Migrator{}
mg.x = engine mg.x = engine
mg.Logger = log.New("migrator") mg.Logger = log.New("migrator")
mg.migrations = make([]Migration, 0) mg.migrations = make([]Migration, 0)
mg.Dialect = NewDialect(mg.x) mg.Dialect = NewDialect(mg.x)
mg.Cfg = cfg
return mg return mg
} }
@ -168,6 +171,16 @@ func (mg *Migrator) exec(m Migration, sess *xorm.Session) error {
return nil return nil
} }
func (mg *Migrator) ClearMigrationEntry(id string) error {
sess := mg.x.NewSession()
defer sess.Close()
_, err := sess.SQL(`DELETE from migration_log where migration_id = ?`, id).Query()
if err != nil {
return fmt.Errorf("failed to clear migration entry %v: %w", id, err)
}
return nil
}
type dbTransactionFunc func(sess *xorm.Session) error type dbTransactionFunc func(sess *xorm.Session) error
func (mg *Migrator) inTransaction(callback dbTransactionFunc) error { func (mg *Migrator) inTransaction(callback dbTransactionFunc) error {

@ -85,7 +85,7 @@ func (ss *SQLStore) Init() error {
dialect = ss.Dialect dialect = ss.Dialect
if !ss.dbCfg.SkipMigrations { if !ss.dbCfg.SkipMigrations {
migrator := migrator.NewMigrator(ss.engine) migrator := migrator.NewMigrator(ss.engine, ss.Cfg)
migrations.AddMigrations(migrator) migrations.AddMigrations(migrator)
for _, descriptor := range registry.GetServices() { for _, descriptor := range registry.GetServices() {

Loading…
Cancel
Save