grafana/pkg/services/ngalert/provisioning/templates.go
Matthew Jacobson c16f1f5e99
Alerting: Fix provisioned templates being ignored by alertmanager (#69485)
* Alerting: Fix provisioned templates being ignored by alertmanager

Template provisioning sets the template in cfg.TemplateFiles while a recent change
made it so that alertmanager reads cfg.AlertmanagerConfig.Templates instead.

This change fixes the issue on both ends, by having provisioning set boths fields and
reverts the change on the alertmanager side so that it uses cfg.TemplateFiles.
2023-06-02 15:47:43 -04:00

131 lines
3.3 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"
)
type TemplateService struct {
config AMConfigStore
prov ProvisioningStore
xact TransactionManager
log log.Logger
}
func NewTemplateService(config AMConfigStore, prov ProvisioningStore, xact TransactionManager, log log.Logger) *TemplateService {
return &TemplateService{
config: config,
prov: prov,
xact: xact,
log: log,
}
}
func (t *TemplateService) GetTemplates(ctx context.Context, orgID int64) (map[string]string, error) {
revision, err := getLastConfiguration(ctx, orgID, t.config)
if err != nil {
return nil, err
}
if revision.cfg.TemplateFiles == nil {
return map[string]string{}, nil
}
return revision.cfg.TemplateFiles, nil
}
func (t *TemplateService) SetTemplate(ctx context.Context, orgID int64, tmpl definitions.NotificationTemplate) (definitions.NotificationTemplate, error) {
err := tmpl.Validate()
if err != nil {
return definitions.NotificationTemplate{}, fmt.Errorf("%w: %s", ErrValidation, err.Error())
}
revision, err := getLastConfiguration(ctx, orgID, t.config)
if err != nil {
return definitions.NotificationTemplate{}, err
}
if revision.cfg.TemplateFiles == nil {
revision.cfg.TemplateFiles = map[string]string{}
}
revision.cfg.TemplateFiles[tmpl.Name] = tmpl.Template
tmpls := make([]string, 0, len(revision.cfg.TemplateFiles))
for name := range revision.cfg.TemplateFiles {
tmpls = append(tmpls, name)
}
revision.cfg.AlertmanagerConfig.Templates = tmpls
serialized, err := serializeAlertmanagerConfig(*revision.cfg)
if err != nil {
return definitions.NotificationTemplate{}, err
}
cmd := models.SaveAlertmanagerConfigurationCmd{
AlertmanagerConfiguration: string(serialized),
ConfigurationVersion: revision.version,
FetchedConfigurationHash: revision.concurrencyToken,
Default: false,
OrgID: orgID,
}
err = t.xact.InTransaction(ctx, func(ctx context.Context) error {
err = PersistConfig(ctx, t.config, &cmd)
if err != nil {
return err
}
err = t.prov.SetProvenance(ctx, &tmpl, orgID, models.Provenance(tmpl.Provenance))
if err != nil {
return err
}
return nil
})
if err != nil {
return definitions.NotificationTemplate{}, err
}
return tmpl, nil
}
func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, name string) error {
revision, err := getLastConfiguration(ctx, orgID, t.config)
if err != nil {
return err
}
delete(revision.cfg.TemplateFiles, name)
serialized, err := serializeAlertmanagerConfig(*revision.cfg)
if err != nil {
return err
}
cmd := models.SaveAlertmanagerConfigurationCmd{
AlertmanagerConfiguration: string(serialized),
ConfigurationVersion: revision.version,
FetchedConfigurationHash: revision.concurrencyToken,
Default: false,
OrgID: orgID,
}
err = t.xact.InTransaction(ctx, func(ctx context.Context) error {
err = PersistConfig(ctx, t.config, &cmd)
if err != nil {
return err
}
tgt := definitions.NotificationTemplate{
Name: name,
}
err = t.prov.DeleteProvenance(ctx, &tgt, orgID)
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
}