mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
494f36e0bd
* extract get and save operations to a alertmanagerConfigStore. this removes duplicated code in service (currently only mute timings) and improves testing * replace generic errors with errutils one with better messages. * update provisioning services to use new store --------- Co-authored-by: Alexander Weaver <weaver.alex.d@gmail.com>
156 lines
4.8 KiB
Go
156 lines
4.8 KiB
Go
package provisioning
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
type NotificationPolicyService struct {
|
|
configStore *alertmanagerConfigStoreImpl
|
|
provenanceStore ProvisioningStore
|
|
xact TransactionManager
|
|
log log.Logger
|
|
settings setting.UnifiedAlertingSettings
|
|
}
|
|
|
|
func NewNotificationPolicyService(am AMConfigStore, prov ProvisioningStore,
|
|
xact TransactionManager, settings setting.UnifiedAlertingSettings, log log.Logger) *NotificationPolicyService {
|
|
return &NotificationPolicyService{
|
|
configStore: &alertmanagerConfigStoreImpl{store: am},
|
|
provenanceStore: prov,
|
|
xact: xact,
|
|
log: log,
|
|
settings: settings,
|
|
}
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) GetAMConfigStore() AMConfigStore {
|
|
return nps.configStore.store
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
|
|
rev, err := nps.configStore.Get(ctx, orgID)
|
|
if err != nil {
|
|
return definitions.Route{}, err
|
|
}
|
|
|
|
if rev.cfg.AlertmanagerConfig.Config.Route == nil {
|
|
return definitions.Route{}, fmt.Errorf("no route present in current alertmanager config")
|
|
}
|
|
|
|
provenance, err := nps.provenanceStore.GetProvenance(ctx, rev.cfg.AlertmanagerConfig.Route, orgID)
|
|
if err != nil {
|
|
return definitions.Route{}, err
|
|
}
|
|
|
|
result := *rev.cfg.AlertmanagerConfig.Route
|
|
result.Provenance = definitions.Provenance(provenance)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) UpdatePolicyTree(ctx context.Context, orgID int64, tree definitions.Route, p models.Provenance) error {
|
|
err := tree.Validate()
|
|
if err != nil {
|
|
return fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
|
}
|
|
|
|
revision, err := nps.configStore.Get(ctx, orgID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
receivers, err := nps.receiversToMap(revision.cfg.AlertmanagerConfig.Receivers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = tree.ValidateReceivers(receivers)
|
|
if err != nil {
|
|
return fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
|
}
|
|
|
|
muteTimes := map[string]struct{}{}
|
|
for _, mt := range revision.cfg.AlertmanagerConfig.MuteTimeIntervals {
|
|
muteTimes[mt.Name] = struct{}{}
|
|
}
|
|
err = tree.ValidateMuteTimes(muteTimes)
|
|
if err != nil {
|
|
return fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
|
}
|
|
|
|
revision.cfg.AlertmanagerConfig.Config.Route = &tree
|
|
|
|
return nps.xact.InTransaction(ctx, func(ctx context.Context) error {
|
|
if err := nps.configStore.Save(ctx, revision, orgID); err != nil {
|
|
return err
|
|
}
|
|
return nps.provenanceStore.SetProvenance(ctx, &tree, orgID, p)
|
|
})
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) ResetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
|
|
defaultCfg, err := deserializeAlertmanagerConfig([]byte(nps.settings.DefaultConfiguration))
|
|
if err != nil {
|
|
nps.log.Error("Failed to parse default alertmanager config: %w", err)
|
|
return definitions.Route{}, fmt.Errorf("failed to parse default alertmanager config: %w", err)
|
|
}
|
|
route := defaultCfg.AlertmanagerConfig.Route
|
|
|
|
revision, err := nps.configStore.Get(ctx, orgID)
|
|
if err != nil {
|
|
return definitions.Route{}, err
|
|
}
|
|
revision.cfg.AlertmanagerConfig.Config.Route = route
|
|
err = nps.ensureDefaultReceiverExists(revision.cfg, defaultCfg)
|
|
if err != nil {
|
|
return definitions.Route{}, err
|
|
}
|
|
|
|
err = nps.xact.InTransaction(ctx, func(ctx context.Context) error {
|
|
if err := nps.configStore.Save(ctx, revision, orgID); err != nil {
|
|
return err
|
|
}
|
|
return nps.provenanceStore.DeleteProvenance(ctx, route, orgID)
|
|
})
|
|
|
|
if err != nil {
|
|
return definitions.Route{}, nil
|
|
} // TODO should be error?
|
|
|
|
return *route, nil
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) receiversToMap(records []*definitions.PostableApiReceiver) (map[string]struct{}, error) {
|
|
receivers := map[string]struct{}{}
|
|
for _, receiver := range records {
|
|
receivers[receiver.Name] = struct{}{}
|
|
}
|
|
return receivers, nil
|
|
}
|
|
|
|
func (nps *NotificationPolicyService) ensureDefaultReceiverExists(cfg *definitions.PostableUserConfig, defaultCfg *definitions.PostableUserConfig) error {
|
|
defaultRcv := cfg.AlertmanagerConfig.Route.Receiver
|
|
|
|
for _, rcv := range cfg.AlertmanagerConfig.Receivers {
|
|
if rcv.Name == defaultRcv {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
for _, rcv := range defaultCfg.AlertmanagerConfig.Receivers {
|
|
if rcv.Name == defaultRcv {
|
|
cfg.AlertmanagerConfig.Receivers = append(cfg.AlertmanagerConfig.Receivers, rcv)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
nps.log.Error("Grafana Alerting has been configured with a default configuration that is internally inconsistent! The default configuration's notification policy must have a corresponding receiver.")
|
|
return fmt.Errorf("inconsistent default configuration")
|
|
}
|