Alerting: Update migration to put alerts to the default folder if dashboard folder is missing (#65577)

* extract function

* use context logger

* put alert to general folder if folder is missing

* move folderHelper init

* add test

* Update pkg/services/sqlstore/migrations/ualert/ualert.go

Co-authored-by: Matthew Jacobson <matthew.jacobson@grafana.com>

---------

Co-authored-by: Matthew Jacobson <matthew.jacobson@grafana.com>
35486_ts_time_regions
Yuri Tseretyan 2 years ago committed by GitHub
parent da4832724e
commit 7b2f44762e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      pkg/services/sqlstore/migrations/ualert/migration_test.go
  2. 61
      pkg/services/sqlstore/migrations/ualert/ualert.go

@ -573,6 +573,43 @@ func TestDashAlertMigration(t *testing.T) {
}
}
})
t.Run("when folder is missing put alert in General folder", func(t *testing.T) {
o := createOrg(t, 1)
folder1 := createDashboard(t, 1, o.ID, "folder-1")
folder1.IsFolder = true
dash1 := createDashboard(t, 3, o.ID, "dash1")
dash1.FolderID = folder1.ID
dash2 := createDashboard(t, 4, o.ID, "dash2")
dash2.FolderID = 22 // missing folder
a1 := createAlert(t, o.ID, dash1.ID, int64(1), "alert-1", []string{})
a2 := createAlert(t, o.ID, dash2.ID, int64(1), "alert-2", []string{})
_, err := x.Insert(o, folder1, dash1, dash2, a1, a2)
require.NoError(t, err)
runDashAlertMigrationTestRun(t, x)
rules := getAlertRules(t, x, o.ID)
require.Len(t, rules, 2)
var generalFolder dashboards.Dashboard
_, err = x.Table(&dashboards.Dashboard{}).Where("title = ? AND org_id = ?", ualert.GENERAL_FOLDER, o.ID).Get(&generalFolder)
require.NoError(t, err)
require.NotNil(t, generalFolder)
for _, rule := range rules {
var expectedFolder dashboards.Dashboard
if rule.Title == a1.Name {
expectedFolder = *folder1
} else {
expectedFolder = generalFolder
}
require.Equal(t, expectedFolder.UID, rule.NamespaceUID)
}
})
}
const (

@ -267,10 +267,35 @@ func (m *migration) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
// cache for the general folders
generalFolderCache := make(map[int64]*dashboard)
folderHelper := folderHelper{
sess: sess,
mg: mg,
}
gf := func(dash dashboard, da dashAlert) (*dashboard, error) {
f, ok := generalFolderCache[dash.OrgId]
if !ok {
// get or create general folder
f, err = folderHelper.getOrCreateGeneralFolder(dash.OrgId)
if err != nil {
return nil, MigrationError{
Err: fmt.Errorf("failed to get or create general folder under organisation %d: %w", dash.OrgId, err),
AlertId: da.Id,
}
}
generalFolderCache[dash.OrgId] = f
}
// No need to assign default permissions to general folder
// because they are included to the query result if it's a folder with no permissions
// https://github.com/grafana/grafana/blob/076e2ce06a6ecf15804423fcc8dca1b620a321e5/pkg/services/sqlstore/dashboard_acl.go#L109
return f, nil
}
// Per org map of newly created rules to which notification channels it should send to.
rulesPerOrg := make(map[int64]map[*alertRule][]uidOrID)
for _, da := range dashAlerts {
l := mg.Logger.New("ruleID", da.Id, "ruleName", da.Name, "dashboardUID", da.DashboardUID, "orgID", da.OrgId)
newCond, err := transConditions(*da.ParsedSettings, da.OrgId, dsIDMap)
if err != nil {
return err
@ -294,18 +319,13 @@ func (m *migration) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
}
}
folderHelper := folderHelper{
sess: sess,
mg: mg,
}
var folder *dashboard
switch {
case dash.HasACL:
folderName := getAlertFolderNameFromDashboard(&dash)
f, ok := folderCache[folderName]
if !ok {
mg.Logger.Info("create a new folder for alerts that belongs to dashboard because it has custom permissions", "org", dash.OrgId, "dashboard_uid", dash.Uid, "folder", folderName)
l.Info("create a new folder for alerts that belongs to dashboard because it has custom permissions", "folder", folderName)
// create folder and assign the permissions of the dashboard (included default and inherited)
f, err = folderHelper.createFolder(dash.OrgId, folderName)
if err != nil {
@ -335,29 +355,20 @@ func (m *migration) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
// get folder if exists
f, err := folderHelper.getFolder(dash, da)
if err != nil {
return MigrationError{
Err: err,
AlertId: da.Id,
// If folder does not exist then the dashboard is an orphan and we migrate the alert to the general folder.
l.Warn("Failed to find folder for dashboard. Migrate rule to the default folder", "rule_name", da.Name, "dashboard_uid", da.DashboardUID, "missing_folder_id", dash.FolderId)
folder, err = gf(dash, da)
if err != nil {
return err
}
} else {
folder = &f
}
folder = &f
default:
f, ok := generalFolderCache[dash.OrgId]
if !ok {
// get or create general folder
f, err = folderHelper.getOrCreateGeneralFolder(dash.OrgId)
if err != nil {
return MigrationError{
Err: fmt.Errorf("failed to get or create general folder under organisation %d: %w", dash.OrgId, err),
AlertId: da.Id,
}
}
generalFolderCache[dash.OrgId] = f
folder, err = gf(dash, da)
if err != nil {
return err
}
// No need to assign default permissions to general folder
// because they are included to the query result if it's a folder with no permissions
// https://github.com/grafana/grafana/blob/076e2ce06a6ecf15804423fcc8dca1b620a321e5/pkg/services/sqlstore/dashboard_acl.go#L109
folder = f
}
if folder.Uid == "" {

Loading…
Cancel
Save