mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[Alerting] Ensure upstream validations are run (#34333)
* use embedded validations via noop yaml unmarshaler * lint * fixes integration tests now that groupings are handled
This commit is contained in:
parent
aed1c013c0
commit
d6c4c2fcd5
@ -413,6 +413,17 @@ func (c *GettableApiAlertingConfig) UnmarshalJSON(b []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since Config implements json.Unmarshaler, we must handle _all_ other fields independently.
|
||||||
|
// Otherwise, the json decoder will detect this and only use the embedded type.
|
||||||
|
// Additionally, we'll use pointers to slices in order to reference the intended target.
|
||||||
|
type overrides struct {
|
||||||
|
Receivers *[]*GettableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &overrides{Receivers: &c.Receivers}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return c.validate()
|
return c.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,10 +463,42 @@ type Config struct {
|
|||||||
Global *config.GlobalConfig `yaml:"global,omitempty" json:"global,omitempty"`
|
Global *config.GlobalConfig `yaml:"global,omitempty" json:"global,omitempty"`
|
||||||
Route *config.Route `yaml:"route,omitempty" json:"route,omitempty"`
|
Route *config.Route `yaml:"route,omitempty" json:"route,omitempty"`
|
||||||
InhibitRules []*config.InhibitRule `yaml:"inhibit_rules,omitempty" json:"inhibit_rules,omitempty"`
|
InhibitRules []*config.InhibitRule `yaml:"inhibit_rules,omitempty" json:"inhibit_rules,omitempty"`
|
||||||
Receivers []*config.Receiver `yaml:"-" json:"receivers,omitempty"`
|
|
||||||
Templates []string `yaml:"templates" json:"templates"`
|
Templates []string `yaml:"templates" json:"templates"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config is the entrypoint for the embedded Alertmanager config with the exception of receivers.
|
||||||
|
// Prometheus historically uses yaml files as the method of configuration and thus some
|
||||||
|
// post-validation is included in the UnmarshalYAML method. Here we simply run this with
|
||||||
|
// a noop unmarshaling function in order to benefit from said validation.
|
||||||
|
func (c *Config) UnmarshalJSON(b []byte) error {
|
||||||
|
type plain Config
|
||||||
|
if err := json.Unmarshal(b, (*plain)(c)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
noopUnmarshal := func(_ interface{}) error { return nil }
|
||||||
|
|
||||||
|
if c.Global != nil {
|
||||||
|
if err := c.Global.UnmarshalYAML(noopUnmarshal); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Route != nil {
|
||||||
|
if err := c.Route.UnmarshalYAML(noopUnmarshal); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range c.InhibitRules {
|
||||||
|
if err := r.UnmarshalYAML(noopUnmarshal); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type PostableApiAlertingConfig struct {
|
type PostableApiAlertingConfig struct {
|
||||||
Config `yaml:",inline"`
|
Config `yaml:",inline"`
|
||||||
|
|
||||||
@ -469,6 +512,17 @@ func (c *PostableApiAlertingConfig) UnmarshalJSON(b []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since Config implements json.Unmarshaler, we must handle _all_ other fields independently.
|
||||||
|
// Otherwise, the json decoder will detect this and only use the embedded type.
|
||||||
|
// Additionally, we'll use pointers to slices in order to reference the intended target.
|
||||||
|
type overrides struct {
|
||||||
|
Receivers *[]*PostableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &overrides{Receivers: &c.Receivers}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return c.validate()
|
return c.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/alertmanager/config"
|
"github.com/prometheus/alertmanager/config"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@ -563,3 +564,14 @@ func Test_ReceiverMatchesBackend(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Marshaling_Validation(t *testing.T) {
|
||||||
|
jsonEncoded, err := ioutil.ReadFile("alertmanager_test_artifact.json")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
var tmp GettableUserConfig
|
||||||
|
require.Nil(t, json.Unmarshal(jsonEncoded, &tmp))
|
||||||
|
|
||||||
|
expected := []model.LabelName{"alertname"}
|
||||||
|
require.Equal(t, expected, tmp.AlertmanagerConfig.Config.Route.GroupBy)
|
||||||
|
}
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
],
|
],
|
||||||
"route": {
|
"route": {
|
||||||
"continue": false,
|
"continue": false,
|
||||||
|
"group_by": [
|
||||||
|
"alertname"
|
||||||
|
],
|
||||||
"receiver": "am",
|
"receiver": "am",
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ alertmanager_config: |
|
|||||||
name: am
|
name: am
|
||||||
route:
|
route:
|
||||||
continue: false
|
continue: false
|
||||||
|
group_by:
|
||||||
|
- alertname
|
||||||
receiver: am
|
receiver: am
|
||||||
routes:
|
routes:
|
||||||
- continue: false
|
- continue: false
|
||||||
|
@ -748,10 +748,10 @@ var expNotifications = map[string][]string{
|
|||||||
"icon_url": "https://awesomeemoji.com/rocket",
|
"icon_url": "https://awesomeemoji.com/rocket",
|
||||||
"attachments": [
|
"attachments": [
|
||||||
{
|
{
|
||||||
"title": "Integration Test [FIRING:1] (SlackAlert1 UID_SlackAlert1)",
|
"title": "Integration Test [FIRING:1] SlackAlert1 (UID_SlackAlert1)",
|
||||||
"title_link": "http:/localhost:3000/alerting/list",
|
"title_link": "http:/localhost:3000/alerting/list",
|
||||||
"text": "Integration Test ",
|
"text": "Integration Test ",
|
||||||
"fallback": "Integration Test [FIRING:1] (SlackAlert1 UID_SlackAlert1)",
|
"fallback": "Integration Test [FIRING:1] SlackAlert1 (UID_SlackAlert1)",
|
||||||
"footer": "Grafana v",
|
"footer": "Grafana v",
|
||||||
"footer_icon": "https://grafana.com/assets/img/fav32.png",
|
"footer_icon": "https://grafana.com/assets/img/fav32.png",
|
||||||
"color": "#D63232",
|
"color": "#D63232",
|
||||||
@ -775,10 +775,10 @@ var expNotifications = map[string][]string{
|
|||||||
"username": "Integration Test",
|
"username": "Integration Test",
|
||||||
"attachments": [
|
"attachments": [
|
||||||
{
|
{
|
||||||
"title": "[FIRING:1] (SlackAlert2 UID_SlackAlert2)",
|
"title": "[FIRING:1] SlackAlert2 (UID_SlackAlert2)",
|
||||||
"title_link": "http:/localhost:3000/alerting/list",
|
"title_link": "http:/localhost:3000/alerting/list",
|
||||||
"text": "\n**Firing**\nLabels:\n - alertname = SlackAlert2\n - __alert_rule_uid__ = UID_SlackAlert2\nAnnotations:\nSource: \n\n\n\n\n",
|
"text": "\n**Firing**\nLabels:\n - alertname = SlackAlert2\n - __alert_rule_uid__ = UID_SlackAlert2\nAnnotations:\nSource: \n\n\n\n\n",
|
||||||
"fallback": "[FIRING:1] (SlackAlert2 UID_SlackAlert2)",
|
"fallback": "[FIRING:1] SlackAlert2 (UID_SlackAlert2)",
|
||||||
"footer": "Grafana v",
|
"footer": "Grafana v",
|
||||||
"footer_icon": "https://grafana.com/assets/img/fav32.png",
|
"footer_icon": "https://grafana.com/assets/img/fav32.png",
|
||||||
"color": "#D63232",
|
"color": "#D63232",
|
||||||
@ -799,11 +799,11 @@ var expNotifications = map[string][]string{
|
|||||||
"pagerduty_recvX/pagerduty_testX": {
|
"pagerduty_recvX/pagerduty_testX": {
|
||||||
`{
|
`{
|
||||||
"routing_key": "pagerduty_recv/pagerduty_test",
|
"routing_key": "pagerduty_recv/pagerduty_test",
|
||||||
"dedup_key": "718643b9694d44f7f2b21458afd1b079cb403cf264e51894ff3c9745238bcced",
|
"dedup_key": "234edb34441f942f713f3c2ccf58b1d719d921b4cbe34e57a1630f1dee847e3b",
|
||||||
"description": "[FIRING:1] (PagerdutyAlert UID_PagerdutyAlert)",
|
"description": "[FIRING:1] PagerdutyAlert (UID_PagerdutyAlert)",
|
||||||
"event_action": "trigger",
|
"event_action": "trigger",
|
||||||
"payload": {
|
"payload": {
|
||||||
"summary": "Integration Test [FIRING:1] (PagerdutyAlert UID_PagerdutyAlert)",
|
"summary": "Integration Test [FIRING:1] PagerdutyAlert (UID_PagerdutyAlert)",
|
||||||
"source": "%s",
|
"source": "%s",
|
||||||
"severity": "warning",
|
"severity": "warning",
|
||||||
"class": "testclass",
|
"class": "testclass",
|
||||||
@ -831,7 +831,7 @@ var expNotifications = map[string][]string{
|
|||||||
"link": {
|
"link": {
|
||||||
"messageUrl": "dingtalk://dingtalkclient/page/link?pc_slide=false&url=http%3A%2Flocalhost%3A3000%2Falerting%2Flist",
|
"messageUrl": "dingtalk://dingtalkclient/page/link?pc_slide=false&url=http%3A%2Flocalhost%3A3000%2Falerting%2Flist",
|
||||||
"text": "\n**Firing**\nLabels:\n - alertname = DingDingAlert\n - __alert_rule_uid__ = UID_DingDingAlert\nAnnotations:\nSource: \n\n\n\n\n",
|
"text": "\n**Firing**\nLabels:\n - alertname = DingDingAlert\n - __alert_rule_uid__ = UID_DingDingAlert\nAnnotations:\nSource: \n\n\n\n\n",
|
||||||
"title": "[FIRING:1] (DingDingAlert UID_DingDingAlert)"
|
"title": "[FIRING:1] DingDingAlert (UID_DingDingAlert)"
|
||||||
},
|
},
|
||||||
"msgtype": "link"
|
"msgtype": "link"
|
||||||
}`,
|
}`,
|
||||||
@ -859,9 +859,9 @@ var expNotifications = map[string][]string{
|
|||||||
"title": "Details"
|
"title": "Details"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": "[FIRING:1] (TeamsAlert UID_TeamsAlert)",
|
"summary": "[FIRING:1] TeamsAlert (UID_TeamsAlert)",
|
||||||
"themeColor": "#D63232",
|
"themeColor": "#D63232",
|
||||||
"title": "[FIRING:1] (TeamsAlert UID_TeamsAlert)"
|
"title": "[FIRING:1] TeamsAlert (UID_TeamsAlert)"
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
"webhook_recv/webhook_test": {
|
"webhook_recv/webhook_test": {
|
||||||
@ -882,7 +882,7 @@ var expNotifications = map[string][]string{
|
|||||||
"fingerprint": "929467973978d053"
|
"fingerprint": "929467973978d053"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"groupLabels": {},
|
"groupLabels": {"alertname": "WebhookAlert"},
|
||||||
"commonLabels": {
|
"commonLabels": {
|
||||||
"__alert_rule_uid__": "UID_WebhookAlert",
|
"__alert_rule_uid__": "UID_WebhookAlert",
|
||||||
"alertname": "WebhookAlert"
|
"alertname": "WebhookAlert"
|
||||||
@ -890,9 +890,9 @@ var expNotifications = map[string][]string{
|
|||||||
"commonAnnotations": {},
|
"commonAnnotations": {},
|
||||||
"externalURL": "http://localhost:3000/",
|
"externalURL": "http://localhost:3000/",
|
||||||
"version": "1",
|
"version": "1",
|
||||||
"groupKey": "{}/{alertname=\"WebhookAlert\"}:{}",
|
"groupKey": "{}/{alertname=\"WebhookAlert\"}:{alertname=\"WebhookAlert\"}",
|
||||||
"truncatedAlerts": 0,
|
"truncatedAlerts": 0,
|
||||||
"title": "[FIRING:1] (WebhookAlert UID_WebhookAlert)",
|
"title": "[FIRING:1] WebhookAlert (UID_WebhookAlert)",
|
||||||
"state": "alerting",
|
"state": "alerting",
|
||||||
"message": "\n**Firing**\nLabels:\n - alertname = WebhookAlert\n - __alert_rule_uid__ = UID_WebhookAlert\nAnnotations:\nSource: \n\n\n\n\n"
|
"message": "\n**Firing**\nLabels:\n - alertname = WebhookAlert\n - __alert_rule_uid__ = UID_WebhookAlert\nAnnotations:\nSource: \n\n\n\n\n"
|
||||||
}`,
|
}`,
|
||||||
|
Loading…
Reference in New Issue
Block a user