2022-04-05 16:48:51 -05:00
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"
2022-07-08 16:23:18 -05:00
"github.com/grafana/grafana/pkg/setting"
2022-04-05 16:48:51 -05:00
)
type NotificationPolicyService struct {
2024-01-05 15:15:18 -06:00
configStore * alertmanagerConfigStoreImpl
2022-04-05 16:48:51 -05:00
provenanceStore ProvisioningStore
xact TransactionManager
log log . Logger
2022-07-08 16:23:18 -05:00
settings setting . UnifiedAlertingSettings
2022-04-05 16:48:51 -05:00
}
2022-07-05 11:09:57 -05:00
func NewNotificationPolicyService ( am AMConfigStore , prov ProvisioningStore ,
2022-07-08 16:23:18 -05:00
xact TransactionManager , settings setting . UnifiedAlertingSettings , log log . Logger ) * NotificationPolicyService {
2022-04-05 16:48:51 -05:00
return & NotificationPolicyService {
2024-01-05 15:15:18 -06:00
configStore : & alertmanagerConfigStoreImpl { store : am } ,
2022-04-05 16:48:51 -05:00
provenanceStore : prov ,
xact : xact ,
log : log ,
2022-07-08 16:23:18 -05:00
settings : settings ,
2022-04-05 16:48:51 -05:00
}
}
func ( nps * NotificationPolicyService ) GetAMConfigStore ( ) AMConfigStore {
2024-01-05 15:15:18 -06:00
return nps . configStore . store
2022-04-05 16:48:51 -05:00
}
2022-04-22 11:57:56 -05:00
func ( nps * NotificationPolicyService ) GetPolicyTree ( ctx context . Context , orgID int64 ) ( definitions . Route , error ) {
2024-01-05 15:15:18 -06:00
rev , err := nps . configStore . Get ( ctx , orgID )
2022-04-05 16:48:51 -05:00
if err != nil {
2022-04-22 11:57:56 -05:00
return definitions . Route { } , err
2022-04-05 16:48:51 -05:00
}
2024-01-05 15:15:18 -06:00
if rev . cfg . AlertmanagerConfig . Config . Route == nil {
2022-04-22 11:57:56 -05:00
return definitions . Route { } , fmt . Errorf ( "no route present in current alertmanager config" )
2022-04-05 16:48:51 -05:00
}
2024-01-05 15:15:18 -06:00
provenance , err := nps . provenanceStore . GetProvenance ( ctx , rev . cfg . AlertmanagerConfig . Route , orgID )
2022-04-05 16:48:51 -05:00
if err != nil {
2022-04-22 11:57:56 -05:00
return definitions . Route { } , err
2022-04-05 16:48:51 -05:00
}
2024-01-05 15:15:18 -06:00
result := * rev . cfg . AlertmanagerConfig . Route
2023-02-27 16:57:15 -06:00
result . Provenance = definitions . Provenance ( provenance )
2022-04-05 16:48:51 -05:00
return result , nil
}
func ( nps * NotificationPolicyService ) UpdatePolicyTree ( ctx context . Context , orgID int64 , tree definitions . Route , p models . Provenance ) error {
2022-04-27 15:15:41 -05:00
err := tree . Validate ( )
if err != nil {
return fmt . Errorf ( "%w: %s" , ErrValidation , err . Error ( ) )
}
2022-07-05 11:09:57 -05:00
2024-01-05 15:15:18 -06:00
revision , err := nps . configStore . Get ( ctx , orgID )
2022-04-05 16:48:51 -05:00
if err != nil {
return err
}
2022-07-05 11:09:57 -05:00
receivers , err := nps . receiversToMap ( revision . cfg . AlertmanagerConfig . Receivers )
2023-02-23 08:10:03 -06:00
if err != nil {
return err
}
2022-07-05 11:09:57 -05:00
err = tree . ValidateReceivers ( receivers )
if err != nil {
return fmt . Errorf ( "%w: %s" , ErrValidation , err . Error ( ) )
}
2022-07-05 12:09:17 -05:00
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 ( ) )
}
2022-05-23 18:16:03 -05:00
revision . cfg . AlertmanagerConfig . Config . Route = & tree
2022-04-05 16:48:51 -05:00
2024-01-05 15:15:18 -06:00
return nps . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
if err := nps . configStore . Save ( ctx , revision , orgID ) ; err != nil {
2022-04-05 16:48:51 -05:00
return err
}
2024-01-05 15:15:18 -06:00
return nps . provenanceStore . SetProvenance ( ctx , & tree , orgID , p )
2022-04-05 16:48:51 -05:00
} )
}
2022-07-05 11:09:57 -05:00
2022-07-08 16:23:18 -05:00
func ( nps * NotificationPolicyService ) ResetPolicyTree ( ctx context . Context , orgID int64 ) ( definitions . Route , error ) {
defaultCfg , err := deserializeAlertmanagerConfig ( [ ] byte ( nps . settings . DefaultConfiguration ) )
if err != nil {
2023-09-04 11:46:34 -05:00
nps . log . Error ( "Failed to parse default alertmanager config: %w" , err )
2022-07-08 16:23:18 -05:00
return definitions . Route { } , fmt . Errorf ( "failed to parse default alertmanager config: %w" , err )
}
route := defaultCfg . AlertmanagerConfig . Route
2024-01-05 15:15:18 -06:00
revision , err := nps . configStore . Get ( ctx , orgID )
2022-07-08 16:23:18 -05:00
if err != nil {
return definitions . Route { } , err
}
revision . cfg . AlertmanagerConfig . Config . Route = route
2022-09-07 09:28:10 -05:00
err = nps . ensureDefaultReceiverExists ( revision . cfg , defaultCfg )
if err != nil {
return definitions . Route { } , err
}
2022-07-08 16:23:18 -05:00
err = nps . xact . InTransaction ( ctx , func ( ctx context . Context ) error {
2024-01-05 15:15:18 -06:00
if err := nps . configStore . Save ( ctx , revision , orgID ) ; err != nil {
2022-07-08 16:23:18 -05:00
return err
}
2024-01-05 15:15:18 -06:00
return nps . provenanceStore . DeleteProvenance ( ctx , route , orgID )
2022-07-08 16:23:18 -05:00
} )
2024-01-05 15:15:18 -06:00
2022-07-08 16:23:18 -05:00
if err != nil {
return definitions . Route { } , nil
2024-01-05 15:15:18 -06:00
} // TODO should be error?
2022-07-08 16:23:18 -05:00
return * route , nil
}
2022-07-05 11:09:57 -05:00
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
}
2022-09-07 09:28:10 -05:00
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" )
}