CloudMigrations: save snapshot of alert rule groups (#100109)

This commit is contained in:
Matheus Macabu
2025-02-06 12:35:59 +01:00
committed by GitHub
parent 7d3a77a45c
commit fde475e3d9
15 changed files with 194 additions and 7 deletions

View File

@@ -821,8 +821,11 @@ func setUpServiceTest(t *testing.T, withDashboardMock bool, cfgOverrides ...conf
secretsService := secretsfakes.NewFakeSecretsService()
rr := routing.NewRouteRegister()
tracer := tracing.InitializeTracerForTest()
fakeFolder := &folder.Folder{UID: "folderUID", Title: "Folder"}
mockFolder := &foldertest.FakeService{
ExpectedFolder: &folder.Folder{UID: "folderUID", Title: "Folder"},
ExpectedFolders: []*folder.Folder{fakeFolder},
ExpectedFolder: fakeFolder,
}
cfg := setting.NewCfg()

View File

@@ -43,6 +43,7 @@ var currentMigrationTypes = []cloudmigration.MigrateDataType{
cloudmigration.NotificationTemplateType,
cloudmigration.ContactPointType,
cloudmigration.NotificationPolicyType,
cloudmigration.AlertRuleGroupType,
cloudmigration.AlertRuleType,
cloudmigration.PluginDataType,
}
@@ -106,6 +107,13 @@ func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.S
return nil, err
}
// Alerts: Alert Rule Groups
alertRuleGroups, err := s.getAlertRuleGroups(ctx, signedInUser)
if err != nil {
s.log.Error("Failed to get alert rule groups", "err", err)
return nil, err
}
// Alerts: Alert Rules
alertRules, err := s.getAlertRules(ctx, signedInUser)
if err != nil {
@@ -209,6 +217,15 @@ func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.S
})
}
for _, alertRuleGroup := range alertRuleGroups {
migrationDataSlice = append(migrationDataSlice, cloudmigration.MigrateDataRequestItem{
Type: cloudmigration.AlertRuleGroupType,
RefID: alertRuleGroup.Title, // no UID available
Name: alertRuleGroup.Title,
Data: alertRuleGroup,
})
}
for _, alertRule := range alertRules {
migrationDataSlice = append(migrationDataSlice, cloudmigration.MigrateDataRequestItem{
Type: cloudmigration.AlertRuleType,

View File

@@ -180,3 +180,61 @@ func (s *Service) getAlertRules(ctx context.Context, signedInUser *user.SignedIn
return provisionedAlertRules, nil
}
type alertRuleGroup struct {
Title string `json:"title"`
FolderUID string `json:"folderUid"`
Interval int64 `json:"interval"`
Rules []alertRule `json:"rules"`
}
func (s *Service) getAlertRuleGroups(ctx context.Context, signedInUser *user.SignedInUser) ([]alertRuleGroup, error) {
alertRuleGroupsWithFolder, err := s.ngAlert.Api.AlertRules.GetAlertGroupsWithFolderFullpath(ctx, signedInUser, nil)
if err != nil {
return nil, fmt.Errorf("fetching alert rule groups with folders: %w", err)
}
settingAlertRulesPaused := s.cfg.CloudMigration.AlertRulesState == setting.GMSAlertRulesPaused
alertRuleGroups := make([]alertRuleGroup, 0, len(alertRuleGroupsWithFolder))
for _, ruleGroup := range alertRuleGroupsWithFolder {
provisionedAlertRules := make([]alertRule, 0, len(ruleGroup.Rules))
for _, rule := range ruleGroup.Rules {
isPaused := rule.IsPaused
if settingAlertRulesPaused {
isPaused = true
}
provisionedAlertRules = append(provisionedAlertRules, alertRule{
ID: rule.ID,
UID: rule.UID,
OrgID: rule.OrgID,
FolderUID: rule.NamespaceUID,
RuleGroup: rule.RuleGroup,
Title: rule.Title,
For: model.Duration(rule.For),
Condition: rule.Condition,
Data: ngalertapi.ApiAlertQueriesFromAlertQueries(rule.Data),
Updated: rule.Updated,
NoDataState: rule.NoDataState.String(),
ExecErrState: rule.ExecErrState.String(),
Annotations: rule.Annotations,
Labels: rule.Labels,
IsPaused: isPaused,
NotificationSettings: ngalertapi.AlertRuleNotificationSettingsFromNotificationSettings(rule.NotificationSettings),
Record: ngalertapi.ApiRecordFromModelRecord(rule.Record),
})
}
alertRuleGroups = append(alertRuleGroups, alertRuleGroup{
Title: ruleGroup.Title,
FolderUID: ruleGroup.FolderUID,
Interval: ruleGroup.Interval,
Rules: provisionedAlertRules,
})
}
return alertRuleGroups, nil
}

View File

@@ -121,7 +121,7 @@ func TestGetAlertRules(t *testing.T) {
user := &user.SignedInUser{OrgID: 1}
alertRule := createAlertRule(t, ctx, s, user, false)
alertRule := createAlertRule(t, ctx, s, user, false, "")
alertRules, err := s.getAlertRules(ctx, user)
require.NoError(t, err)
@@ -138,10 +138,10 @@ func TestGetAlertRules(t *testing.T) {
user := &user.SignedInUser{OrgID: 1}
alertRulePaused := createAlertRule(t, ctx, s, user, true)
alertRulePaused := createAlertRule(t, ctx, s, user, true, "")
require.True(t, alertRulePaused.IsPaused)
alertRuleUnpaused := createAlertRule(t, ctx, s, user, false)
alertRuleUnpaused := createAlertRule(t, ctx, s, user, false, "")
require.False(t, alertRuleUnpaused.IsPaused)
alertRules, err := s.getAlertRules(ctx, user)
@@ -152,6 +152,83 @@ func TestGetAlertRules(t *testing.T) {
})
}
func TestGetAlertRuleGroups(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("it returns the alert rule groups", func(t *testing.T) {
s := setUpServiceTest(t, false).(*Service)
user := &user.SignedInUser{OrgID: 1}
ruleGroupTitle := "ruleGroupTitle"
alertRule1 := createAlertRule(t, ctx, s, user, true, ruleGroupTitle)
alertRule2 := createAlertRule(t, ctx, s, user, false, ruleGroupTitle)
alertRule3 := createAlertRule(t, ctx, s, user, false, "anotherRuleGroup")
createAlertRuleGroup(t, ctx, s, user, ruleGroupTitle, []models.AlertRule{alertRule1, alertRule2})
ruleGroups, err := s.getAlertRuleGroups(ctx, user)
require.NoError(t, err)
require.Len(t, ruleGroups, 2)
for _, ruleGroup := range ruleGroups {
alertRuleUIDs := make([]string, 0)
for _, alertRule := range ruleGroup.Rules {
alertRuleUIDs = append(alertRuleUIDs, alertRule.UID)
}
if ruleGroup.Title == ruleGroupTitle {
require.Len(t, ruleGroup.Rules, 2)
require.ElementsMatch(t, []string{alertRule1.UID, alertRule2.UID}, alertRuleUIDs)
} else {
require.Len(t, ruleGroup.Rules, 1)
require.ElementsMatch(t, []string{alertRule3.UID}, alertRuleUIDs)
}
}
})
t.Run("with the alert rules state set to paused, it returns the alert rule groups with alert rules paused", func(t *testing.T) {
alertRulesState := func(c *setting.Cfg) {
c.CloudMigration.AlertRulesState = setting.GMSAlertRulesPaused
}
s := setUpServiceTest(t, false, alertRulesState).(*Service)
user := &user.SignedInUser{OrgID: 1}
ruleGroupTitle := "ruleGroupTitle"
alertRule1 := createAlertRule(t, ctx, s, user, true, ruleGroupTitle)
alertRule2 := createAlertRule(t, ctx, s, user, false, ruleGroupTitle)
alertRule3 := createAlertRule(t, ctx, s, user, false, "anotherRuleGroup")
createAlertRuleGroup(t, ctx, s, user, ruleGroupTitle, []models.AlertRule{alertRule1, alertRule2})
ruleGroups, err := s.getAlertRuleGroups(ctx, user)
require.NoError(t, err)
require.Len(t, ruleGroups, 2)
for _, ruleGroup := range ruleGroups {
alertRuleUIDs := make([]string, 0)
for _, alertRule := range ruleGroup.Rules {
alertRuleUIDs = append(alertRuleUIDs, alertRule.UID)
require.True(t, alertRule.IsPaused)
}
if ruleGroup.Title == ruleGroupTitle {
require.Len(t, ruleGroup.Rules, 2)
require.ElementsMatch(t, []string{alertRule1.UID, alertRule2.UID}, alertRuleUIDs)
} else {
require.Len(t, ruleGroup.Rules, 1)
require.ElementsMatch(t, []string{alertRule3.UID}, alertRuleUIDs)
}
}
})
}
func createMuteTiming(t *testing.T, ctx context.Context, service *Service, user *user.SignedInUser) definitions.MuteTimeInterval {
t.Helper()
@@ -267,12 +344,12 @@ func updateNotificationPolicyTree(t *testing.T, ctx context.Context, service *Se
require.NoError(t, err)
}
func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *user.SignedInUser, isPaused bool) models.AlertRule {
func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *user.SignedInUser, isPaused bool, ruleGroup string) models.AlertRule {
t.Helper()
rule := models.AlertRule{
OrgID: user.GetOrgID(),
Title: fmt.Sprintf("Alert Rule SLO (Paused: %v)", isPaused),
Title: fmt.Sprintf("Alert Rule SLO (Paused: %v) - %v", isPaused, ruleGroup),
NamespaceUID: "folderUID",
Condition: "A",
Data: []models.AlertQuery{
@@ -286,7 +363,7 @@ func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *
},
},
IsPaused: isPaused,
RuleGroup: "ruleGroup",
RuleGroup: ruleGroup,
For: time.Minute,
IntervalSeconds: 60,
NoDataState: models.OK,
@@ -298,3 +375,19 @@ func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *
return createdRule
}
func createAlertRuleGroup(t *testing.T, ctx context.Context, service *Service, user *user.SignedInUser, title string, rules []models.AlertRule) models.AlertRuleGroup {
t.Helper()
group := models.AlertRuleGroup{
Title: title,
FolderUID: "folderUID",
Interval: 300,
Rules: rules,
}
err := service.ngAlert.Api.AlertRules.ReplaceRuleGroup(ctx, user, group, "")
require.NoError(t, err)
return group
}