From 016dea11434a3269c565a3f5b2615bb03e856cc4 Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Tue, 15 Oct 2024 12:55:33 +0200 Subject: [PATCH] CloudMigrations: create snapshot for Notification Templates (#94676) * CloudMigrations: create snapshot for Notification Templates * CloudMigrations: add notification templates resource to frontend --- .../cloudmigrationimpl/cloudmigration_test.go | 3 -- .../cloudmigrationimpl/snapshot_mgmt.go | 20 ++++++++- .../snapshot_mgmt_alerts.go | 27 ++++++++++++ .../snapshot_mgmt_alerts_test.go | 42 +++++++++++++++++++ .../migrate-to-cloud/onprem/NameCell.tsx | 2 + .../migrate-to-cloud/onprem/TypeCell.tsx | 2 + .../onprem/useNotifyOnSuccess.tsx | 2 + public/locales/en-US/grafana.json | 4 +- public/locales/pseudo-LOCALE/grafana.json | 4 +- 9 files changed, 100 insertions(+), 6 deletions(-) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go index 3b0825e67ae..cbe6b060754 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go @@ -799,9 +799,6 @@ func setUpServiceTest(t *testing.T, withDashboardMock bool) cloudmigration.Servi require.NoError(t, err) var validConfig = `{ - "template_files": { - "a": "template" - }, "alertmanager_config": { "route": { "receiver": "grafana-default-email" diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go index 94c82a101da..952106e1608 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go @@ -33,6 +33,7 @@ var currentMigrationTypes = []cloudmigration.MigrateDataType{ cloudmigration.LibraryElementDataType, cloudmigration.DashboardDataType, cloudmigration.MuteTimingType, + cloudmigration.NotificationTemplateType, } func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.SignedInUser) (*cloudmigration.MigrateDataRequest, error) { @@ -66,9 +67,17 @@ func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.S return nil, err } + // Alerts: Notification Templates + notificationTemplates, err := s.getNotificationTemplates(ctx, signedInUser) + if err != nil { + s.log.Error("Failed to get alert notification templates", "err", err) + return nil, err + } + migrationDataSlice := make( []cloudmigration.MigrateDataRequestItem, 0, - len(dataSources)+len(dashs)+len(folders)+len(libraryElements)+len(muteTimings), + len(dataSources)+len(dashs)+len(folders)+len(libraryElements)+ + len(muteTimings)+len(notificationTemplates), ) for _, ds := range dataSources { @@ -124,6 +133,15 @@ func (s *Service) getMigrationDataJSON(ctx context.Context, signedInUser *user.S }) } + for _, notificationTemplate := range notificationTemplates { + migrationDataSlice = append(migrationDataSlice, cloudmigration.MigrateDataRequestItem{ + Type: cloudmigration.NotificationTemplateType, + RefID: notificationTemplate.Name, + Name: notificationTemplate.Name, + Data: notificationTemplate, + }) + } + // Obtain the names of parent elements for Dashboard and Folders data types parentNamesByType, err := s.getParentNames(ctx, signedInUser, dashs, folders, libraryElements) if err != nil { diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go index 8869882e8a6..94879e227f2 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go @@ -39,3 +39,30 @@ func (s *Service) getAlertMuteTimings(ctx context.Context, signedInUser *user.Si return muteTimeIntervals, nil } + +type notificationTemplate struct { + Name string `json:"name"` + Template string `json:"template"` +} + +func (s *Service) getNotificationTemplates(ctx context.Context, signedInUser *user.SignedInUser) ([]notificationTemplate, error) { + if !s.features.IsEnabledGlobally(featuremgmt.FlagOnPremToCloudMigrationsAlerts) { + return nil, nil + } + + templates, err := s.ngAlert.Api.Templates.GetTemplates(ctx, signedInUser.OrgID) + if err != nil { + return nil, fmt.Errorf("fetching ngalert notification templates: %w", err) + } + + notificationTemplates := make([]notificationTemplate, 0, len(templates)) + + for _, template := range templates { + notificationTemplates = append(notificationTemplates, notificationTemplate{ + Name: template.Name, + Template: template.Template, + }) + } + + return notificationTemplates, nil +} diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go index 7ff8cadc1bc..e1fed6720f9 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go @@ -42,6 +42,36 @@ func TestGetAlertMuteTimings(t *testing.T) { }) } +func TestGetNotificationTemplates(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + t.Run("when the feature flag `onPremToCloudMigrationsAlerts` is not enabled it returns nil", func(t *testing.T) { + s := setUpServiceTest(t, false).(*Service) + s.features = featuremgmt.WithFeatures(featuremgmt.FlagOnPremToCloudMigrations) + + notificationTemplates, err := s.getNotificationTemplates(ctx, nil) + require.NoError(t, err) + require.Nil(t, notificationTemplates) + }) + + t.Run("when the feature flag `onPremToCloudMigrationsAlerts` is enabled it returns the notification templates", func(t *testing.T) { + s := setUpServiceTest(t, false).(*Service) + s.features = featuremgmt.WithFeatures(featuremgmt.FlagOnPremToCloudMigrations, featuremgmt.FlagOnPremToCloudMigrationsAlerts) + + var orgID int64 = 1 + user := &user.SignedInUser{OrgID: orgID} + + createdTemplate := createNotificationTemplate(t, ctx, s, orgID) + + notificationTemplates, err := s.getNotificationTemplates(ctx, user) + require.NoError(t, err) + require.NotNil(t, notificationTemplates) + require.Len(t, notificationTemplates, 1) + require.Equal(t, createdTemplate.Name, notificationTemplates[0].Name) + }) +} + func createMuteTiming(t *testing.T, ctx context.Context, service *Service, orgID int64) definitions.MuteTimeInterval { t.Helper() @@ -67,3 +97,15 @@ func createMuteTiming(t *testing.T, ctx context.Context, service *Service, orgID return createdTiming } + +func createNotificationTemplate(t *testing.T, ctx context.Context, service *Service, orgID int64) definitions.NotificationTemplate { + tmpl := definitions.NotificationTemplate{ + Name: "MyTestNotificationTemplate", + Template: "This is a test template\n{{ .ExternalURL }}", + } + + createdTemplate, err := service.ngAlert.Api.Templates.CreateTemplate(ctx, orgID, tmpl) + require.NoError(t, err) + + return createdTemplate +} diff --git a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx index 94fd342ad6c..3f5ea7984ed 100644 --- a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx +++ b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx @@ -221,6 +221,8 @@ function ResourceIcon({ resource }: { resource: ResourceTableItem }) { return ; case 'MUTE_TIMING': return ; + case 'NOTIFICATION_TEMPLATE': + return ; default: return undefined; } diff --git a/public/app/features/migrate-to-cloud/onprem/TypeCell.tsx b/public/app/features/migrate-to-cloud/onprem/TypeCell.tsx index ca8e29b046a..afecc880de4 100644 --- a/public/app/features/migrate-to-cloud/onprem/TypeCell.tsx +++ b/public/app/features/migrate-to-cloud/onprem/TypeCell.tsx @@ -15,6 +15,8 @@ export function prettyTypeName(type: ResourceTableItem['type']) { return t('migrate-to-cloud.resource-type.library_element', 'Library Element'); case 'MUTE_TIMING': return t('migrate-to-cloud.resource-type.mute_timing', 'Mute Timing'); + case 'NOTIFICATION_TEMPLATE': + return t('migrate-to-cloud.resource-type.notification_template', 'Notification Template'); default: return t('migrate-to-cloud.resource-type.unknown', 'Unknown'); } diff --git a/public/app/features/migrate-to-cloud/onprem/useNotifyOnSuccess.tsx b/public/app/features/migrate-to-cloud/onprem/useNotifyOnSuccess.tsx index 0f50d7b6fe0..e83c6c5b553 100644 --- a/public/app/features/migrate-to-cloud/onprem/useNotifyOnSuccess.tsx +++ b/public/app/features/migrate-to-cloud/onprem/useNotifyOnSuccess.tsx @@ -54,6 +54,8 @@ function getTranslatedMessage(snapshot: GetSnapshotResponseDto) { types.push(t('migrate-to-cloud.migrated-counts.library_elements', 'library elements')); } else if (type === 'MUTE_TIMING') { types.push(t('migrate-to-cloud.migrated-counts.mute_timings', 'mute timings')); + } else if (type === 'NOTIFICATION_TEMPLATE') { + types.push(t('migrate-to-cloud.migrated-counts.notification_templates', 'notification templates')); } distinctItems += 1; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 03f75af7079..bd56d8aff4e 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1409,7 +1409,8 @@ "datasources": "data sources", "folders": "folders", "library_elements": "library elements", - "mute_timings": "mute timings" + "mute_timings": "mute timings", + "notification_templates": "notification templates" }, "migration-token": { "delete-button": "Delete token", @@ -1494,6 +1495,7 @@ "folder": "Folder", "library_element": "Library Element", "mute_timing": "Mute Timing", + "notification_template": "Notification Template", "unknown": "Unknown" }, "summary": { diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index b65e42aa873..a6f27524603 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1409,7 +1409,8 @@ "datasources": "đäŧä şőūřčęş", "folders": "ƒőľđęřş", "library_elements": "ľįþřäřy ęľęmęʼnŧş", - "mute_timings": "mūŧę ŧįmįʼnģş" + "mute_timings": "mūŧę ŧįmįʼnģş", + "notification_templates": "ʼnőŧįƒįčäŧįőʼn ŧęmpľäŧęş" }, "migration-token": { "delete-button": "Đęľęŧę ŧőĸęʼn", @@ -1494,6 +1495,7 @@ "folder": "Főľđęř", "library_element": "Ŀįþřäřy Ēľęmęʼnŧ", "mute_timing": "Mūŧę Ŧįmįʼnģ", + "notification_template": "Ńőŧįƒįčäŧįőʼn Ŧęmpľäŧę", "unknown": "Ůʼnĸʼnőŵʼn" }, "summary": {