mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 04:04:00 -06:00
2188516a21
Terraform Issue: grafana/terraform-provider-grafana#1007 Nested routes should be allowed to inherit the contact point from the root (or direct parent) route but this fails in the provisioning API (it works in the UI)
157 lines
4.8 KiB
Go
157 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
|
|
}
|
|
|
|
receivers[""] = struct{}{} // Allow empty receiver (inheriting from parent)
|
|
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")
|
|
}
|