mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudMigrations: save snapshot of alert rule groups (#100109)
This commit is contained in:
parent
7d3a77a45c
commit
fde475e3d9
@ -127,6 +127,7 @@ const (
|
|||||||
FolderDataType MigrateDataType = "FOLDER"
|
FolderDataType MigrateDataType = "FOLDER"
|
||||||
LibraryElementDataType MigrateDataType = "LIBRARY_ELEMENT"
|
LibraryElementDataType MigrateDataType = "LIBRARY_ELEMENT"
|
||||||
AlertRuleType MigrateDataType = "ALERT_RULE"
|
AlertRuleType MigrateDataType = "ALERT_RULE"
|
||||||
|
AlertRuleGroupType MigrateDataType = "ALERT_RULE_GROUP"
|
||||||
ContactPointType MigrateDataType = "CONTACT_POINT"
|
ContactPointType MigrateDataType = "CONTACT_POINT"
|
||||||
NotificationPolicyType MigrateDataType = "NOTIFICATION_POLICY"
|
NotificationPolicyType MigrateDataType = "NOTIFICATION_POLICY"
|
||||||
NotificationTemplateType MigrateDataType = "NOTIFICATION_TEMPLATE"
|
NotificationTemplateType MigrateDataType = "NOTIFICATION_TEMPLATE"
|
||||||
|
@ -821,8 +821,11 @@ func setUpServiceTest(t *testing.T, withDashboardMock bool, cfgOverrides ...conf
|
|||||||
secretsService := secretsfakes.NewFakeSecretsService()
|
secretsService := secretsfakes.NewFakeSecretsService()
|
||||||
rr := routing.NewRouteRegister()
|
rr := routing.NewRouteRegister()
|
||||||
tracer := tracing.InitializeTracerForTest()
|
tracer := tracing.InitializeTracerForTest()
|
||||||
|
|
||||||
|
fakeFolder := &folder.Folder{UID: "folderUID", Title: "Folder"}
|
||||||
mockFolder := &foldertest.FakeService{
|
mockFolder := &foldertest.FakeService{
|
||||||
ExpectedFolder: &folder.Folder{UID: "folderUID", Title: "Folder"},
|
ExpectedFolders: []*folder.Folder{fakeFolder},
|
||||||
|
ExpectedFolder: fakeFolder,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
|
@ -43,6 +43,7 @@ var currentMigrationTypes = []cloudmigration.MigrateDataType{
|
|||||||
cloudmigration.NotificationTemplateType,
|
cloudmigration.NotificationTemplateType,
|
||||||
cloudmigration.ContactPointType,
|
cloudmigration.ContactPointType,
|
||||||
cloudmigration.NotificationPolicyType,
|
cloudmigration.NotificationPolicyType,
|
||||||
|
cloudmigration.AlertRuleGroupType,
|
||||||
cloudmigration.AlertRuleType,
|
cloudmigration.AlertRuleType,
|
||||||
cloudmigration.PluginDataType,
|
cloudmigration.PluginDataType,
|
||||||
}
|
}
|
||||||
@ -106,6 +107,13 @@ func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.S
|
|||||||
return nil, err
|
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
|
// Alerts: Alert Rules
|
||||||
alertRules, err := s.getAlertRules(ctx, signedInUser)
|
alertRules, err := s.getAlertRules(ctx, signedInUser)
|
||||||
if err != nil {
|
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 {
|
for _, alertRule := range alertRules {
|
||||||
migrationDataSlice = append(migrationDataSlice, cloudmigration.MigrateDataRequestItem{
|
migrationDataSlice = append(migrationDataSlice, cloudmigration.MigrateDataRequestItem{
|
||||||
Type: cloudmigration.AlertRuleType,
|
Type: cloudmigration.AlertRuleType,
|
||||||
|
@ -180,3 +180,61 @@ func (s *Service) getAlertRules(ctx context.Context, signedInUser *user.SignedIn
|
|||||||
|
|
||||||
return provisionedAlertRules, nil
|
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
|
||||||
|
}
|
||||||
|
@ -121,7 +121,7 @@ func TestGetAlertRules(t *testing.T) {
|
|||||||
|
|
||||||
user := &user.SignedInUser{OrgID: 1}
|
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)
|
alertRules, err := s.getAlertRules(ctx, user)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -138,10 +138,10 @@ func TestGetAlertRules(t *testing.T) {
|
|||||||
|
|
||||||
user := &user.SignedInUser{OrgID: 1}
|
user := &user.SignedInUser{OrgID: 1}
|
||||||
|
|
||||||
alertRulePaused := createAlertRule(t, ctx, s, user, true)
|
alertRulePaused := createAlertRule(t, ctx, s, user, true, "")
|
||||||
require.True(t, alertRulePaused.IsPaused)
|
require.True(t, alertRulePaused.IsPaused)
|
||||||
|
|
||||||
alertRuleUnpaused := createAlertRule(t, ctx, s, user, false)
|
alertRuleUnpaused := createAlertRule(t, ctx, s, user, false, "")
|
||||||
require.False(t, alertRuleUnpaused.IsPaused)
|
require.False(t, alertRuleUnpaused.IsPaused)
|
||||||
|
|
||||||
alertRules, err := s.getAlertRules(ctx, user)
|
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 {
|
func createMuteTiming(t *testing.T, ctx context.Context, service *Service, user *user.SignedInUser) definitions.MuteTimeInterval {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -267,12 +344,12 @@ func updateNotificationPolicyTree(t *testing.T, ctx context.Context, service *Se
|
|||||||
require.NoError(t, err)
|
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()
|
t.Helper()
|
||||||
|
|
||||||
rule := models.AlertRule{
|
rule := models.AlertRule{
|
||||||
OrgID: user.GetOrgID(),
|
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",
|
NamespaceUID: "folderUID",
|
||||||
Condition: "A",
|
Condition: "A",
|
||||||
Data: []models.AlertQuery{
|
Data: []models.AlertQuery{
|
||||||
@ -286,7 +363,7 @@ func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
IsPaused: isPaused,
|
IsPaused: isPaused,
|
||||||
RuleGroup: "ruleGroup",
|
RuleGroup: ruleGroup,
|
||||||
For: time.Minute,
|
For: time.Minute,
|
||||||
IntervalSeconds: 60,
|
IntervalSeconds: 60,
|
||||||
NoDataState: models.OK,
|
NoDataState: models.OK,
|
||||||
@ -298,3 +375,19 @@ func createAlertRule(t *testing.T, ctx context.Context, service *Service, user *
|
|||||||
|
|
||||||
return createdRule
|
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
|
||||||
|
}
|
||||||
|
@ -88,6 +88,7 @@ const (
|
|||||||
FolderDataType MigrateDataType = "FOLDER"
|
FolderDataType MigrateDataType = "FOLDER"
|
||||||
LibraryElementDataType MigrateDataType = "LIBRARY_ELEMENT"
|
LibraryElementDataType MigrateDataType = "LIBRARY_ELEMENT"
|
||||||
AlertRuleType MigrateDataType = "ALERT_RULE"
|
AlertRuleType MigrateDataType = "ALERT_RULE"
|
||||||
|
AlertRuleGroupType MigrateDataType = "ALERT_RULE_GROUP"
|
||||||
ContactPointType MigrateDataType = "CONTACT_POINT"
|
ContactPointType MigrateDataType = "CONTACT_POINT"
|
||||||
NotificationPolicyType MigrateDataType = "NOTIFICATION_POLICY"
|
NotificationPolicyType MigrateDataType = "NOTIFICATION_POLICY"
|
||||||
NotificationTemplateType MigrateDataType = "NOTIFICATION_TEMPLATE"
|
NotificationTemplateType MigrateDataType = "NOTIFICATION_TEMPLATE"
|
||||||
|
@ -5670,6 +5670,7 @@
|
|||||||
"FOLDER",
|
"FOLDER",
|
||||||
"LIBRARY_ELEMENT",
|
"LIBRARY_ELEMENT",
|
||||||
"ALERT_RULE",
|
"ALERT_RULE",
|
||||||
|
"ALERT_RULE_GROUP",
|
||||||
"CONTACT_POINT",
|
"CONTACT_POINT",
|
||||||
"NOTIFICATION_POLICY",
|
"NOTIFICATION_POLICY",
|
||||||
"NOTIFICATION_TEMPLATE",
|
"NOTIFICATION_TEMPLATE",
|
||||||
|
@ -17182,6 +17182,7 @@
|
|||||||
"FOLDER",
|
"FOLDER",
|
||||||
"LIBRARY_ELEMENT",
|
"LIBRARY_ELEMENT",
|
||||||
"ALERT_RULE",
|
"ALERT_RULE",
|
||||||
|
"ALERT_RULE_GROUP",
|
||||||
"CONTACT_POINT",
|
"CONTACT_POINT",
|
||||||
"NOTIFICATION_POLICY",
|
"NOTIFICATION_POLICY",
|
||||||
"NOTIFICATION_TEMPLATE",
|
"NOTIFICATION_TEMPLATE",
|
||||||
|
@ -194,6 +194,7 @@ export type MigrateDataResponseItemDto = {
|
|||||||
| 'FOLDER'
|
| 'FOLDER'
|
||||||
| 'LIBRARY_ELEMENT'
|
| 'LIBRARY_ELEMENT'
|
||||||
| 'ALERT_RULE'
|
| 'ALERT_RULE'
|
||||||
|
| 'ALERT_RULE_GROUP'
|
||||||
| 'CONTACT_POINT'
|
| 'CONTACT_POINT'
|
||||||
| 'NOTIFICATION_POLICY'
|
| 'NOTIFICATION_POLICY'
|
||||||
| 'NOTIFICATION_TEMPLATE'
|
| 'NOTIFICATION_TEMPLATE'
|
||||||
|
@ -231,6 +231,8 @@ function ResourceIcon({ resource }: { resource: ResourceTableItem }) {
|
|||||||
return <Icon size="xl" name="bell" />;
|
return <Icon size="xl" name="bell" />;
|
||||||
case 'ALERT_RULE':
|
case 'ALERT_RULE':
|
||||||
return <Icon size="xl" name="bell" />;
|
return <Icon size="xl" name="bell" />;
|
||||||
|
case 'ALERT_RULE_GROUP':
|
||||||
|
return <Icon size="xl" name="bell" />;
|
||||||
case 'PLUGIN':
|
case 'PLUGIN':
|
||||||
if (pluginLogo) {
|
if (pluginLogo) {
|
||||||
return <img className={styles.icon} src={pluginLogo} alt="" />;
|
return <img className={styles.icon} src={pluginLogo} alt="" />;
|
||||||
|
@ -23,6 +23,8 @@ export function prettyTypeName(type: ResourceTableItem['type']) {
|
|||||||
return t('migrate-to-cloud.resource-type.notification_policy', 'Notification Policy');
|
return t('migrate-to-cloud.resource-type.notification_policy', 'Notification Policy');
|
||||||
case 'ALERT_RULE':
|
case 'ALERT_RULE':
|
||||||
return t('migrate-to-cloud.resource-type.alert_rule', 'Alert Rule');
|
return t('migrate-to-cloud.resource-type.alert_rule', 'Alert Rule');
|
||||||
|
case 'ALERT_RULE_GROUP':
|
||||||
|
return t('migrate-to-cloud.resource-type.alert_rule_group', 'Alert Rule Group');
|
||||||
case 'PLUGIN':
|
case 'PLUGIN':
|
||||||
return t('migrate-to-cloud.resource-type.plugin', 'Plugin');
|
return t('migrate-to-cloud.resource-type.plugin', 'Plugin');
|
||||||
default:
|
default:
|
||||||
|
@ -62,6 +62,8 @@ function getTranslatedMessage(snapshot: GetSnapshotResponseDto) {
|
|||||||
types.push(t('migrate-to-cloud.migrated-counts.notification_policies', 'notification policies'));
|
types.push(t('migrate-to-cloud.migrated-counts.notification_policies', 'notification policies'));
|
||||||
} else if (type === 'ALERT_RULE') {
|
} else if (type === 'ALERT_RULE') {
|
||||||
types.push(t('migrate-to-cloud.migrated-counts.alert_rules', 'alert rules'));
|
types.push(t('migrate-to-cloud.migrated-counts.alert_rules', 'alert rules'));
|
||||||
|
} else if (type === 'ALERT_RULE_GROUP') {
|
||||||
|
types.push(t('migrate-to-cloud.migrated-counts.alert_rule_groups', 'alert rule groups'));
|
||||||
} else if (type === 'PLUGIN') {
|
} else if (type === 'PLUGIN') {
|
||||||
types.push(t('migrate-to-cloud.migrated-counts.plugins', 'plugins'));
|
types.push(t('migrate-to-cloud.migrated-counts.plugins', 'plugins'));
|
||||||
}
|
}
|
||||||
|
@ -2117,6 +2117,7 @@
|
|||||||
"title": "Let us help you migrate to this stack"
|
"title": "Let us help you migrate to this stack"
|
||||||
},
|
},
|
||||||
"migrated-counts": {
|
"migrated-counts": {
|
||||||
|
"alert_rule_groups": "alert rule groups",
|
||||||
"alert_rules": "alert rules",
|
"alert_rules": "alert rules",
|
||||||
"contact_points": "contact points",
|
"contact_points": "contact points",
|
||||||
"dashboards": "dashboards",
|
"dashboards": "dashboards",
|
||||||
@ -2221,6 +2222,7 @@
|
|||||||
},
|
},
|
||||||
"resource-type": {
|
"resource-type": {
|
||||||
"alert_rule": "Alert Rule",
|
"alert_rule": "Alert Rule",
|
||||||
|
"alert_rule_group": "Alert Rule Group",
|
||||||
"contact_point": "Contact Point",
|
"contact_point": "Contact Point",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"datasource": "Data source",
|
"datasource": "Data source",
|
||||||
|
@ -2117,6 +2117,7 @@
|
|||||||
"title": "Ŀęŧ ūş ĥęľp yőū mįģřäŧę ŧő ŧĥįş şŧäčĸ"
|
"title": "Ŀęŧ ūş ĥęľp yőū mįģřäŧę ŧő ŧĥįş şŧäčĸ"
|
||||||
},
|
},
|
||||||
"migrated-counts": {
|
"migrated-counts": {
|
||||||
|
"alert_rule_groups": "äľęřŧ řūľę ģřőūpş",
|
||||||
"alert_rules": "äľęřŧ řūľęş",
|
"alert_rules": "äľęřŧ řūľęş",
|
||||||
"contact_points": "čőʼnŧäčŧ pőįʼnŧş",
|
"contact_points": "čőʼnŧäčŧ pőįʼnŧş",
|
||||||
"dashboards": "đäşĥþőäřđş",
|
"dashboards": "đäşĥþőäřđş",
|
||||||
@ -2221,6 +2222,7 @@
|
|||||||
},
|
},
|
||||||
"resource-type": {
|
"resource-type": {
|
||||||
"alert_rule": "Åľęřŧ Ŗūľę",
|
"alert_rule": "Åľęřŧ Ŗūľę",
|
||||||
|
"alert_rule_group": "Åľęřŧ Ŗūľę Ğřőūp",
|
||||||
"contact_point": "Cőʼnŧäčŧ Pőįʼnŧ",
|
"contact_point": "Cőʼnŧäčŧ Pőįʼnŧ",
|
||||||
"dashboard": "Đäşĥþőäřđ",
|
"dashboard": "Đäşĥþőäřđ",
|
||||||
"datasource": "Đäŧä şőūřčę",
|
"datasource": "Đäŧä şőūřčę",
|
||||||
|
@ -7250,6 +7250,7 @@
|
|||||||
"FOLDER",
|
"FOLDER",
|
||||||
"LIBRARY_ELEMENT",
|
"LIBRARY_ELEMENT",
|
||||||
"ALERT_RULE",
|
"ALERT_RULE",
|
||||||
|
"ALERT_RULE_GROUP",
|
||||||
"CONTACT_POINT",
|
"CONTACT_POINT",
|
||||||
"NOTIFICATION_POLICY",
|
"NOTIFICATION_POLICY",
|
||||||
"NOTIFICATION_TEMPLATE",
|
"NOTIFICATION_TEMPLATE",
|
||||||
|
Loading…
Reference in New Issue
Block a user