Files
grafana/pkg/services/provisioning/notifiers/config_reader.go
T

191 lines
5.1 KiB
Go
Raw Normal View History

2019-01-28 20:39:09 +01:00
package notifiers
2018-11-28 16:35:42 +02:00
import (
"context"
2018-12-14 11:53:50 +02:00
"fmt"
2022-08-11 11:21:12 +00:00
"io/fs"
2018-11-28 16:35:42 +02:00
"os"
"path/filepath"
"strings"
2019-05-13 14:45:54 +08:00
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
2018-11-28 16:35:42 +02:00
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/setting"
2018-11-28 16:35:42 +02:00
"gopkg.in/yaml.v2"
)
type configReader struct {
encryptionService encryption.Internal
notificationService *notifications.NotificationService
orgStore utils.OrgStore
log log.Logger
2018-11-28 16:35:42 +02:00
}
2021-11-03 11:31:56 +01:00
func (cr *configReader) readConfig(ctx context.Context, path string) ([]*notificationsAsConfig, error) {
2018-11-28 16:35:42 +02:00
var notifications []*notificationsAsConfig
cr.log.Debug("Looking for alert notification provisioning files", "path", path)
2022-08-11 11:21:12 +00:00
files, err := os.ReadDir(path)
2018-11-28 16:35:42 +02:00
if err != nil {
cr.log.Error("Can't read alert notification provisioning files from directory", "path", path, "error", err)
2018-11-28 16:35:42 +02:00
return notifications, nil
}
for _, file := range files {
if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") {
cr.log.Debug("Parsing alert notifications provisioning file", "path", path, "file.Name", file.Name())
notifs, err := cr.parseNotificationConfig(path, file)
if err != nil {
return nil, err
}
if notifs != nil {
notifications = append(notifications, notifs)
}
}
}
cr.log.Debug("Validating alert notifications")
if err = cr.validateRequiredField(notifications); err != nil {
2018-12-14 11:53:50 +02:00
return nil, err
}
2021-11-03 11:31:56 +01:00
if err := cr.checkOrgIDAndOrgName(ctx, notifications); err != nil {
return nil, err
}
2018-11-28 16:35:42 +02:00
if err := cr.validateNotifications(notifications); err != nil {
2018-11-28 16:35:42 +02:00
return nil, err
}
return notifications, nil
}
2022-08-11 11:21:12 +00:00
func (cr *configReader) parseNotificationConfig(path string, file fs.DirEntry) (*notificationsAsConfig, error) {
2018-11-28 16:35:42 +02:00
filename, _ := filepath.Abs(filepath.Join(path, file.Name()))
// nolint:gosec
// We can ignore the gosec G304 warning on this one because `filename` comes from ps.Cfg.ProvisioningPath
2022-08-10 13:37:51 +00:00
yamlFile, err := os.ReadFile(filename)
2018-11-28 16:35:42 +02:00
if err != nil {
return nil, err
}
var cfg *notificationsAsConfigV0
2018-11-28 16:35:42 +02:00
err = yaml.Unmarshal(yamlFile, &cfg)
if err != nil {
return nil, err
}
return cfg.mapToNotificationFromConfig(), nil
}
2021-11-03 11:31:56 +01:00
func (cr *configReader) checkOrgIDAndOrgName(ctx context.Context, notifications []*notificationsAsConfig) error {
2018-11-28 16:35:42 +02:00
for i := range notifications {
for _, notification := range notifications[i].Notifications {
if notification.OrgID < 1 {
if notification.OrgName == "" {
notification.OrgID = 1
} else {
notification.OrgID = 0
}
} else {
if err := utils.CheckOrgExists(ctx, cr.orgStore, notification.OrgID); err != nil {
return fmt.Errorf("failed to provision %q notification: %w", notification.Name, err)
}
2018-11-28 16:35:42 +02:00
}
}
for _, notification := range notifications[i].DeleteNotifications {
if notification.OrgID < 1 {
if notification.OrgName == "" {
notification.OrgID = 1
} else {
notification.OrgID = 0
}
2018-11-28 16:35:42 +02:00
}
}
}
return nil
2018-11-28 16:35:42 +02:00
}
2019-01-28 20:39:09 +01:00
func (cr *configReader) validateRequiredField(notifications []*notificationsAsConfig) error {
2018-12-14 11:53:50 +02:00
for i := range notifications {
var errStrings []string
for index, notification := range notifications[i].Notifications {
if notification.Name == "" {
errStrings = append(
errStrings,
fmt.Sprintf("Added alert notification item %d in configuration doesn't contain required field name", index+1),
)
}
2019-01-28 20:39:09 +01:00
if notification.UID == "" {
2018-12-14 11:53:50 +02:00
errStrings = append(
errStrings,
fmt.Sprintf("Added alert notification item %d in configuration doesn't contain required field uid", index+1),
)
}
}
for index, notification := range notifications[i].DeleteNotifications {
if notification.Name == "" {
errStrings = append(
errStrings,
fmt.Sprintf("Deleted alert notification item %d in configuration doesn't contain required field name", index+1),
)
}
2019-01-28 20:39:09 +01:00
if notification.UID == "" {
2018-12-14 11:53:50 +02:00
errStrings = append(
errStrings,
fmt.Sprintf("Deleted alert notification item %d in configuration doesn't contain required field uid", index+1),
)
}
}
2019-01-28 20:39:09 +01:00
2018-12-14 11:53:50 +02:00
if len(errStrings) != 0 {
return fmt.Errorf(strings.Join(errStrings, "\n"))
}
}
2019-01-28 20:39:09 +01:00
2018-12-14 11:53:50 +02:00
return nil
}
2018-11-28 16:35:42 +02:00
func (cr *configReader) validateNotifications(notifications []*notificationsAsConfig) error {
2018-11-28 16:35:42 +02:00
for i := range notifications {
if notifications[i].Notifications == nil {
continue
}
for _, notification := range notifications[i].Notifications {
encryptedSecureSettings, err := cr.encryptionService.EncryptJsonData(
context.Background(),
notification.SecureSettings,
setting.SecretKey,
)
if err != nil {
return err
}
_, err = alerting.InitNotifier(&models.AlertNotification{
Name: notification.Name,
Settings: notification.SettingsToJSON(),
SecureSettings: encryptedSecureSettings,
Type: notification.Type,
}, cr.encryptionService.GetDecryptedValue, cr.notificationService)
2019-01-28 20:39:09 +01:00
if err != nil {
return err
2018-11-28 16:35:42 +02:00
}
}
}
return nil
}