Alerting: Enable interpolation for notification policies in file provisioning (#58956)

This commit is contained in:
Jean-Philippe Quéméner 2022-11-22 16:54:24 +01:00 committed by GitHub
parent d5274dfdda
commit 41b3398eb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 10 deletions

View File

@ -1,26 +1,54 @@
package alerting
import (
"encoding/json"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/provisioning/values"
)
type NotificiationPolicyV1 struct {
OrgID values.Int64Value `json:"orgId" yaml:"orgId"`
Policy definitions.Route `json:",inline" yaml:",inline"`
OrgID values.Int64Value `json:"orgId" yaml:"orgId"`
// We use JSONValue here, as we want to have interpolation the values.
Policy values.JSONValue `json:"-" yaml:"-"`
}
func (v1 *NotificiationPolicyV1) mapToModel() NotificiationPolicy {
func (v1 *NotificiationPolicyV1) UnmarshalYAML(unmarshal func(interface{}) error) error {
err := v1.Policy.UnmarshalYAML(unmarshal)
if err != nil {
return err
}
// As we also want to unmarshal the orgId and any other field that might be
// added in the future we create an alias type that prevents recursion
// and just uses the default marshler.
type plain NotificiationPolicyV1
return unmarshal((*plain)(v1))
}
func (v1 *NotificiationPolicyV1) mapToModel() (NotificiationPolicy, error) {
orgID := v1.OrgID.Value()
if orgID < 1 {
orgID = 1
}
// we don't need any further validation here as it's done by
// the notification policy service
var route definitions.Route
// We need the string json representation, so we marshal the policy back
// as a string and interpolate it at the same time.
data, err := json.Marshal(v1.Policy.Value())
if err != nil {
return NotificiationPolicy{}, err
}
// Now we can take the interpolated string json represtenation of the policy
// and unmarshal it in the concrete type.
err = json.Unmarshal(data, &route)
if err != nil {
return NotificiationPolicy{}, err
}
// We don't need any further validation here as it's done by
// the notification policy service.
return NotificiationPolicy{
OrgID: orgID,
Policy: v1.Policy,
}
Policy: route,
}, nil
}
type NotificiationPolicy struct {

View File

@ -0,0 +1,37 @@
package alerting
import (
"os"
"testing"
"gopkg.in/yaml.v2"
"github.com/stretchr/testify/require"
)
func TestNotificationPolicy(t *testing.T) {
const (
envKey = "NOTIFIER_EMAIL_REMINDER_FREQUENCY"
envValue = "4h"
)
err := os.Setenv(envKey, envValue)
require.NoError(t, err)
defer func() {
_ = os.Unsetenv(envKey)
}()
data := `orgId: 123
receiver: test
continue: true
repeat_interval: ${NOTIFIER_EMAIL_REMINDER_FREQUENCY}
`
var model NotificiationPolicyV1
err = yaml.Unmarshal([]byte(data), &model)
require.NoError(t, err)
np, err := model.mapToModel()
require.NoError(t, err)
require.Equal(t, int64(123), np.OrgID)
require.Equal(t, "test", np.Policy.Receiver)
require.True(t, np.Policy.Continue)
require.Equal(t, envValue, np.Policy.RepeatInterval.String())
}

View File

@ -51,7 +51,9 @@ func (fileV1 *AlertingFileV1) MapToModel() (AlertingFile, error) {
if err := fileV1.mapContactPoint(&alertingFile); err != nil {
return AlertingFile{}, fmt.Errorf("failure parsing contact points: %w", err)
}
fileV1.mapPolicies(&alertingFile)
if err := fileV1.mapPolicies(&alertingFile); err != nil {
return AlertingFile{}, fmt.Errorf("failure parsing policies: %w", err)
}
if err := fileV1.mapMuteTimes(&alertingFile); err != nil {
return AlertingFile{}, fmt.Errorf("failure parsing mute times: %w", err)
}
@ -89,13 +91,18 @@ func (fileV1 *AlertingFileV1) mapMuteTimes(alertingFile *AlertingFile) error {
return nil
}
func (fileV1 *AlertingFileV1) mapPolicies(alertingFile *AlertingFile) {
func (fileV1 *AlertingFileV1) mapPolicies(alertingFile *AlertingFile) error {
for _, npV1 := range fileV1.Policies {
alertingFile.Policies = append(alertingFile.Policies, npV1.mapToModel())
np, err := npV1.mapToModel()
if err != nil {
return err
}
alertingFile.Policies = append(alertingFile.Policies, np)
}
for _, orgIDV1 := range fileV1.ResetPolicies {
alertingFile.ResetPolicies = append(alertingFile.ResetPolicies, OrgID(orgIDV1.Value()))
}
return nil
}
func (fileV1 *AlertingFileV1) mapContactPoint(alertingFile *AlertingFile) error {