Skip to content

Commit

Permalink
[v9.3.x] Alerting: Enable interpolation for notification policies in …
Browse files Browse the repository at this point in the history
…file provisioning (#59140)

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

(cherry picked from commit 41b3398)

Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>
  • Loading branch information
grafanabot and JohnnyQQQQ committed Nov 22, 2022
1 parent 692bd0a commit a2263b9
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 10 deletions.
42 changes: 35 additions & 7 deletions pkg/services/provisioning/alerting/notification_policy_types.go
@@ -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) 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 {
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 {
Expand Down
@@ -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())
}
13 changes: 10 additions & 3 deletions pkg/services/provisioning/alerting/types.go
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit a2263b9

Please sign in to comment.