mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Factor out shared code for working with configs in provisioning package (#49419)
* Factor out shared code for working with configs * Refactor in notification policies and contact points * Better file ordering * Address feedback
This commit is contained in:
53
pkg/services/ngalert/provisioning/config.go
Normal file
53
pkg/services/ngalert/provisioning/config.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package provisioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func deserializeAlertmanagerConfig(config []byte) (*definitions.PostableUserConfig, error) {
|
||||||
|
result := definitions.PostableUserConfig{}
|
||||||
|
if err := json.Unmarshal(config, &result); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize alertmanager configuration: %w", err)
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeAlertmanagerConfig(config definitions.PostableUserConfig) ([]byte, error) {
|
||||||
|
return json.Marshal(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfgRevision struct {
|
||||||
|
cfg *definitions.PostableUserConfig
|
||||||
|
concurrencyToken string
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLastConfiguration(ctx context.Context, orgID int64, store AMConfigStore) (*cfgRevision, error) {
|
||||||
|
q := models.GetLatestAlertmanagerConfigurationQuery{
|
||||||
|
OrgID: orgID,
|
||||||
|
}
|
||||||
|
if err := store.GetLatestAlertmanagerConfiguration(ctx, &q); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if q.Result == nil {
|
||||||
|
return nil, fmt.Errorf("no alertmanager configuration present in this org")
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrencyToken := q.Result.ConfigurationHash
|
||||||
|
cfg, err := deserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfgRevision{
|
||||||
|
cfg: cfg,
|
||||||
|
concurrencyToken: concurrencyToken,
|
||||||
|
version: q.Result.ConfigurationVersion,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ func NewContactPointService(store store.AlertingStore, encryptionService secrets
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int64) ([]apimodels.EmbeddedContactPoint, error) {
|
func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int64) ([]apimodels.EmbeddedContactPoint, error) {
|
||||||
cfg, _, err := ecp.getCurrentConfig(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, ecp.amStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int6
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
contactPoints := []apimodels.EmbeddedContactPoint{}
|
contactPoints := []apimodels.EmbeddedContactPoint{}
|
||||||
for _, contactPoint := range cfg.GetGrafanaReceiverMap() {
|
for _, contactPoint := range revision.cfg.GetGrafanaReceiverMap() {
|
||||||
embeddedContactPoint := apimodels.EmbeddedContactPoint{
|
embeddedContactPoint := apimodels.EmbeddedContactPoint{
|
||||||
UID: contactPoint.UID,
|
UID: contactPoint.UID,
|
||||||
Type: contactPoint.Type,
|
Type: contactPoint.Type,
|
||||||
@@ -77,11 +77,11 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int6
|
|||||||
|
|
||||||
// internal only
|
// internal only
|
||||||
func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, orgID int64, uid string) (apimodels.EmbeddedContactPoint, error) {
|
func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, orgID int64, uid string) (apimodels.EmbeddedContactPoint, error) {
|
||||||
cfg, _, err := ecp.getCurrentConfig(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, ecp.amStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apimodels.EmbeddedContactPoint{}, err
|
return apimodels.EmbeddedContactPoint{}, err
|
||||||
}
|
}
|
||||||
for _, receiver := range cfg.GetGrafanaReceiverMap() {
|
for _, receiver := range revision.cfg.GetGrafanaReceiverMap() {
|
||||||
if receiver.UID != uid {
|
if receiver.UID != uid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
|||||||
return apimodels.EmbeddedContactPoint{}, fmt.Errorf("contact point is not valid: %w", err)
|
return apimodels.EmbeddedContactPoint{}, fmt.Errorf("contact point is not valid: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, fetchedHash, err := ecp.getCurrentConfig(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, ecp.amStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apimodels.EmbeddedContactPoint{}, err
|
return apimodels.EmbeddedContactPoint{}, err
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
|||||||
}
|
}
|
||||||
|
|
||||||
receiverFound := false
|
receiverFound := false
|
||||||
for _, receiver := range cfg.AlertmanagerConfig.Receivers {
|
for _, receiver := range revision.cfg.AlertmanagerConfig.Receivers {
|
||||||
if receiver.Name == contactPoint.Name {
|
if receiver.Name == contactPoint.Name {
|
||||||
receiver.PostableGrafanaReceivers.GrafanaManagedReceivers = append(receiver.PostableGrafanaReceivers.GrafanaManagedReceivers, grafanaReceiver)
|
receiver.PostableGrafanaReceivers.GrafanaManagedReceivers = append(receiver.PostableGrafanaReceivers.GrafanaManagedReceivers, grafanaReceiver)
|
||||||
receiverFound = true
|
receiverFound = true
|
||||||
@@ -151,7 +151,7 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !receiverFound {
|
if !receiverFound {
|
||||||
cfg.AlertmanagerConfig.Receivers = append(cfg.AlertmanagerConfig.Receivers, &apimodels.PostableApiReceiver{
|
revision.cfg.AlertmanagerConfig.Receivers = append(revision.cfg.AlertmanagerConfig.Receivers, &apimodels.PostableApiReceiver{
|
||||||
Receiver: config.Receiver{
|
Receiver: config.Receiver{
|
||||||
Name: grafanaReceiver.Name,
|
Name: grafanaReceiver.Name,
|
||||||
},
|
},
|
||||||
@@ -161,7 +161,7 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(cfg)
|
data, err := json.Marshal(revision.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apimodels.EmbeddedContactPoint{}, err
|
return apimodels.EmbeddedContactPoint{}, err
|
||||||
}
|
}
|
||||||
@@ -169,8 +169,8 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
|||||||
err = ecp.xact.InTransaction(ctx, func(ctx context.Context) error {
|
err = ecp.xact.InTransaction(ctx, func(ctx context.Context) error {
|
||||||
err = ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
err = ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
||||||
AlertmanagerConfiguration: string(data),
|
AlertmanagerConfiguration: string(data),
|
||||||
FetchedConfigurationHash: fetchedHash,
|
FetchedConfigurationHash: revision.concurrencyToken,
|
||||||
ConfigurationVersion: "v1",
|
ConfigurationVersion: revision.version,
|
||||||
Default: false,
|
Default: false,
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
})
|
})
|
||||||
@@ -242,11 +242,11 @@ func (ecp *ContactPointService) UpdateContactPoint(ctx context.Context, orgID in
|
|||||||
SecureSettings: extractedSecrets,
|
SecureSettings: extractedSecrets,
|
||||||
}
|
}
|
||||||
// save to store
|
// save to store
|
||||||
cfg, fetchedHash, err := ecp.getCurrentConfig(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, ecp.amStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, receiver := range cfg.AlertmanagerConfig.Receivers {
|
for _, receiver := range revision.cfg.AlertmanagerConfig.Receivers {
|
||||||
if receiver.Name == contactPoint.Name {
|
if receiver.Name == contactPoint.Name {
|
||||||
receiverNotFound := true
|
receiverNotFound := true
|
||||||
for i, grafanaReceiver := range receiver.GrafanaManagedReceivers {
|
for i, grafanaReceiver := range receiver.GrafanaManagedReceivers {
|
||||||
@@ -261,15 +261,15 @@ func (ecp *ContactPointService) UpdateContactPoint(ctx context.Context, orgID in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(cfg)
|
data, err := json.Marshal(revision.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ecp.xact.InTransaction(ctx, func(ctx context.Context) error {
|
return ecp.xact.InTransaction(ctx, func(ctx context.Context) error {
|
||||||
err = ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
err = ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
||||||
AlertmanagerConfiguration: string(data),
|
AlertmanagerConfiguration: string(data),
|
||||||
FetchedConfigurationHash: fetchedHash,
|
FetchedConfigurationHash: revision.concurrencyToken,
|
||||||
ConfigurationVersion: "v1",
|
ConfigurationVersion: revision.version,
|
||||||
Default: false,
|
Default: false,
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
})
|
})
|
||||||
@@ -286,7 +286,7 @@ func (ecp *ContactPointService) UpdateContactPoint(ctx context.Context, orgID in
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID int64, uid string) error {
|
func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID int64, uid string) error {
|
||||||
cfg, fetchedHash, err := ecp.getCurrentConfig(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, ecp.amStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID in
|
|||||||
// Name of the contact point that will be removed, might be used if a
|
// Name of the contact point that will be removed, might be used if a
|
||||||
// full removal is done to check if it's referenced in any route.
|
// full removal is done to check if it's referenced in any route.
|
||||||
name := ""
|
name := ""
|
||||||
for i, receiver := range cfg.AlertmanagerConfig.Receivers {
|
for i, receiver := range revision.cfg.AlertmanagerConfig.Receivers {
|
||||||
for j, grafanaReceiver := range receiver.GrafanaManagedReceivers {
|
for j, grafanaReceiver := range receiver.GrafanaManagedReceivers {
|
||||||
if grafanaReceiver.UID == uid {
|
if grafanaReceiver.UID == uid {
|
||||||
name = grafanaReceiver.Name
|
name = grafanaReceiver.Name
|
||||||
@@ -305,16 +305,16 @@ func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID in
|
|||||||
// if this was the last receiver we removed, we remove the whole receiver
|
// if this was the last receiver we removed, we remove the whole receiver
|
||||||
if len(receiver.GrafanaManagedReceivers) == 0 {
|
if len(receiver.GrafanaManagedReceivers) == 0 {
|
||||||
fullRemoval = true
|
fullRemoval = true
|
||||||
cfg.AlertmanagerConfig.Receivers = append(cfg.AlertmanagerConfig.Receivers[:i], cfg.AlertmanagerConfig.Receivers[i+1:]...)
|
revision.cfg.AlertmanagerConfig.Receivers = append(revision.cfg.AlertmanagerConfig.Receivers[:i], revision.cfg.AlertmanagerConfig.Receivers[i+1:]...)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fullRemoval && isContactPointInUse(name, []*apimodels.Route{cfg.AlertmanagerConfig.Route}) {
|
if fullRemoval && isContactPointInUse(name, []*apimodels.Route{revision.cfg.AlertmanagerConfig.Route}) {
|
||||||
return fmt.Errorf("contact point '%s' is currently used by a notification policy", name)
|
return fmt.Errorf("contact point '%s' is currently used by a notification policy", name)
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(cfg)
|
data, err := json.Marshal(revision.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -328,29 +328,14 @@ func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID in
|
|||||||
}
|
}
|
||||||
return ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
return ecp.amStore.UpdateAlertmanagerConfiguration(ctx, &models.SaveAlertmanagerConfigurationCmd{
|
||||||
AlertmanagerConfiguration: string(data),
|
AlertmanagerConfiguration: string(data),
|
||||||
FetchedConfigurationHash: fetchedHash,
|
FetchedConfigurationHash: revision.concurrencyToken,
|
||||||
ConfigurationVersion: "v1",
|
ConfigurationVersion: revision.version,
|
||||||
Default: false,
|
Default: false,
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ecp *ContactPointService) getCurrentConfig(ctx context.Context, orgID int64) (*apimodels.PostableUserConfig, string, error) {
|
|
||||||
query := &models.GetLatestAlertmanagerConfigurationQuery{
|
|
||||||
OrgID: orgID,
|
|
||||||
}
|
|
||||||
err := ecp.amStore.GetLatestAlertmanagerConfiguration(ctx, query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
cfg, err := DeserializeAlertmanagerConfig([]byte(query.Result.AlertmanagerConfiguration))
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
return cfg, query.Result.ConfigurationHash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isContactPointInUse(name string, routes []*apimodels.Route) bool {
|
func isContactPointInUse(name string, routes []*apimodels.Route) bool {
|
||||||
if len(routes) == 0 {
|
if len(routes) == 0 {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ package provisioning
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MuteTimingService struct {
|
type MuteTimingService struct {
|
||||||
@@ -26,25 +24,17 @@ func NewMuteTimingService(config AMConfigStore, prov ProvisioningStore, xact Tra
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MuteTimingService) GetMuteTimings(ctx context.Context, orgID int64) ([]definitions.MuteTiming, error) {
|
func (m *MuteTimingService) GetMuteTimings(ctx context.Context, orgID int64) ([]definitions.MuteTiming, error) {
|
||||||
q := models.GetLatestAlertmanagerConfigurationQuery{
|
rev, err := getLastConfiguration(ctx, orgID, m.config)
|
||||||
OrgID: orgID,
|
|
||||||
}
|
|
||||||
err := m.config.GetLatestAlertmanagerConfiguration(ctx, &q)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.Result == nil {
|
if rev.cfg.AlertmanagerConfig.MuteTimeIntervals == nil {
|
||||||
return nil, fmt.Errorf("no alertmanager configuration present in this org")
|
return []definitions.MuteTiming{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := DeserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
result := make([]definitions.MuteTiming, 0, len(rev.cfg.AlertmanagerConfig.MuteTimeIntervals))
|
||||||
if err != nil {
|
for _, interval := range rev.cfg.AlertmanagerConfig.MuteTimeIntervals {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]definitions.MuteTiming, 0, len(cfg.AlertmanagerConfig.MuteTimeIntervals))
|
|
||||||
for _, interval := range cfg.AlertmanagerConfig.MuteTimeIntervals {
|
|
||||||
result = append(result, definitions.MuteTiming{MuteTimeInterval: interval})
|
result = append(result, definitions.MuteTiming{MuteTimeInterval: interval})
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func TestMuteTimingService(t *testing.T) {
|
|||||||
require.Equal(t, "asdf", result[0].Name)
|
require.Equal(t, "asdf", result[0].Name)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("service returns empty map when config file contains no templates", func(t *testing.T) {
|
t.Run("service returns empty list when config file contains no mute timings", func(t *testing.T) {
|
||||||
sut := createMuteTimingSvcSut()
|
sut := createMuteTimingSvcSut()
|
||||||
sut.config.(*MockAMConfigStore).EXPECT().
|
sut.config.(*MockAMConfigStore).EXPECT().
|
||||||
getsConfig(models.AlertConfiguration{
|
getsConfig(models.AlertConfiguration{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (nps *NotificationPolicyService) GetPolicyTree(ctx context.Context, orgID i
|
|||||||
return definitions.Route{}, err
|
return definitions.Route{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := DeserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
cfg, err := deserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return definitions.Route{}, err
|
return definitions.Route{}, err
|
||||||
}
|
}
|
||||||
@@ -63,31 +63,21 @@ func (nps *NotificationPolicyService) UpdatePolicyTree(ctx context.Context, orgI
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
return fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
||||||
}
|
}
|
||||||
|
revision, err := getLastConfiguration(ctx, orgID, nps.amStore)
|
||||||
q := models.GetLatestAlertmanagerConfigurationQuery{
|
|
||||||
OrgID: orgID,
|
|
||||||
}
|
|
||||||
err = nps.amStore.GetLatestAlertmanagerConfiguration(ctx, &q)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
concurrencyToken := q.Result.ConfigurationHash
|
revision.cfg.AlertmanagerConfig.Config.Route = &tree
|
||||||
cfg, err := DeserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.AlertmanagerConfig.Config.Route = &tree
|
serialized, err := serializeAlertmanagerConfig(*revision.cfg)
|
||||||
|
|
||||||
serialized, err := SerializeAlertmanagerConfig(*cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd := models.SaveAlertmanagerConfigurationCmd{
|
cmd := models.SaveAlertmanagerConfigurationCmd{
|
||||||
AlertmanagerConfiguration: string(serialized),
|
AlertmanagerConfiguration: string(serialized),
|
||||||
ConfigurationVersion: q.Result.ConfigurationVersion,
|
ConfigurationVersion: revision.version,
|
||||||
FetchedConfigurationHash: concurrencyToken,
|
FetchedConfigurationHash: revision.concurrencyToken,
|
||||||
Default: false,
|
Default: false,
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package provisioning
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DeserializeAlertmanagerConfig(config []byte) (*definitions.PostableUserConfig, error) {
|
|
||||||
result := definitions.PostableUserConfig{}
|
|
||||||
if err := json.Unmarshal(config, &result); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize alertmanager configuration: %w", err)
|
|
||||||
}
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SerializeAlertmanagerConfig(config definitions.PostableUserConfig) ([]byte, error) {
|
|
||||||
return json.Marshal(config)
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ func NewTemplateService(config AMConfigStore, prov ProvisioningStore, xact Trans
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateService) GetTemplates(ctx context.Context, orgID int64) (map[string]string, error) {
|
func (t *TemplateService) GetTemplates(ctx context.Context, orgID int64) (map[string]string, error) {
|
||||||
revision, err := t.getLastConfiguration(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, t.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ func (t *TemplateService) SetTemplate(ctx context.Context, orgID int64, tmpl def
|
|||||||
return definitions.MessageTemplate{}, fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
return definitions.MessageTemplate{}, fmt.Errorf("%w: %s", ErrValidation, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
revision, err := t.getLastConfiguration(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, t.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return definitions.MessageTemplate{}, err
|
return definitions.MessageTemplate{}, err
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ func (t *TemplateService) SetTemplate(ctx context.Context, orgID int64, tmpl def
|
|||||||
}
|
}
|
||||||
revision.cfg.TemplateFiles[tmpl.Name] = tmpl.Template
|
revision.cfg.TemplateFiles[tmpl.Name] = tmpl.Template
|
||||||
|
|
||||||
serialized, err := SerializeAlertmanagerConfig(*revision.cfg)
|
serialized, err := serializeAlertmanagerConfig(*revision.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return definitions.MessageTemplate{}, err
|
return definitions.MessageTemplate{}, err
|
||||||
}
|
}
|
||||||
@@ -84,14 +84,14 @@ func (t *TemplateService) SetTemplate(ctx context.Context, orgID int64, tmpl def
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, name string) error {
|
func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, name string) error {
|
||||||
revision, err := t.getLastConfiguration(ctx, orgID)
|
revision, err := getLastConfiguration(ctx, orgID, t.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(revision.cfg.TemplateFiles, name)
|
delete(revision.cfg.TemplateFiles, name)
|
||||||
|
|
||||||
serialized, err := SerializeAlertmanagerConfig(*revision.cfg)
|
serialized, err := serializeAlertmanagerConfig(*revision.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -123,35 +123,3 @@ func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, name
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TemplateService) getLastConfiguration(ctx context.Context, orgID int64) (*cfgRevision, error) {
|
|
||||||
q := models.GetLatestAlertmanagerConfigurationQuery{
|
|
||||||
OrgID: orgID,
|
|
||||||
}
|
|
||||||
err := t.config.GetLatestAlertmanagerConfiguration(ctx, &q)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if q.Result == nil {
|
|
||||||
return nil, fmt.Errorf("no alertmanager configuration present in this org")
|
|
||||||
}
|
|
||||||
|
|
||||||
concurrencyToken := q.Result.ConfigurationHash
|
|
||||||
cfg, err := DeserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfgRevision{
|
|
||||||
cfg: cfg,
|
|
||||||
concurrencyToken: concurrencyToken,
|
|
||||||
version: q.Result.ConfigurationVersion,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type cfgRevision struct {
|
|
||||||
cfg *definitions.PostableUserConfig
|
|
||||||
concurrencyToken string
|
|
||||||
version string
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user