mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 10:20:29 -06:00
Alerting: Basic support for time_intervals (#83216)
This commit adds basic support for time_intervals, as mute_time_intervals is deprecated in Alertmanager and scheduled to be removed before 1.0. It does not add support for time_intervals in API or file provisioning, nor does it support exporting time intervals. This will be added in later commits to keep the changes as simple as possible.
This commit is contained in:
parent
13cb09b178
commit
1ed1242358
2
go.mod
2
go.mod
@ -59,7 +59,7 @@ require (
|
||||
github.com/google/uuid v1.6.0 // @grafana/backend-platform
|
||||
github.com/google/wire v0.5.0 // @grafana/backend-platform
|
||||
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/grafana/alerting v0.0.0-20240213130827-92f64f0f2a12 // @grafana/alerting-squad-backend
|
||||
github.com/grafana/alerting v0.0.0-20240222104113-abfafef9a7d2 // @grafana/alerting-squad-backend
|
||||
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
|
||||
github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources
|
||||
github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources
|
||||
|
6
go.sum
6
go.sum
@ -2505,8 +2505,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gotestyourself/gotestyourself v1.3.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||
github.com/grafana/alerting v0.0.0-20240213130827-92f64f0f2a12 h1:QepaY7wUP3U1hFiU1Lnv+tymnovzK21KQ/evMDpYsEw=
|
||||
github.com/grafana/alerting v0.0.0-20240213130827-92f64f0f2a12/go.mod h1:brTFeACal/cSZAR8XO/4LPKs7rzNfS86okl6QjSP1eY=
|
||||
github.com/grafana/alerting v0.0.0-20240222104113-abfafef9a7d2 h1:fmUMdtP7ditGgJFdXCwVxDrKnondHNNe0TkhN5YaIAI=
|
||||
github.com/grafana/alerting v0.0.0-20240222104113-abfafef9a7d2/go.mod h1:brTFeACal/cSZAR8XO/4LPKs7rzNfS86okl6QjSP1eY=
|
||||
github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw=
|
||||
github.com/grafana/codejen v0.0.3/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
|
||||
github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ=
|
||||
@ -2530,8 +2530,6 @@ github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkr
|
||||
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs=
|
||||
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.211.0 h1:hYtieOoYvsv/BcFbtspml4OzfuYrv1d14nESdf13qxQ=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.211.0/go.mod h1:qsI4ktDf0lig74u8SLPJf9zRdVxWV/W4Wi+Ox6gifgs=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.212.0 h1:ohgMktFAasLTzAhKhcIzk81O60E29Za6ly02GhEqGIU=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.212.0/go.mod h1:qsI4ktDf0lig74u8SLPJf9zRdVxWV/W4Wi+Ox6gifgs=
|
||||
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo=
|
||||
|
@ -739,6 +739,8 @@ func (c *GettableApiAlertingConfig) GetReceivers() []*GettableApiReceiver {
|
||||
return c.Receivers
|
||||
}
|
||||
|
||||
func (c *GettableApiAlertingConfig) GetTimeIntervals() []config.TimeInterval { return c.TimeIntervals }
|
||||
|
||||
func (c *GettableApiAlertingConfig) GetMuteTimeIntervals() []config.MuteTimeInterval {
|
||||
return c.MuteTimeIntervals
|
||||
}
|
||||
@ -803,6 +805,7 @@ type Config struct {
|
||||
Global *config.GlobalConfig `yaml:"global,omitempty" json:"global,omitempty"`
|
||||
Route *Route `yaml:"route,omitempty" json:"route,omitempty"`
|
||||
InhibitRules []config.InhibitRule `yaml:"inhibit_rules,omitempty" json:"inhibit_rules,omitempty"`
|
||||
TimeIntervals []config.TimeInterval `yaml:"time_intervals,omitempty" json:"time_intervals,omitempty"`
|
||||
MuteTimeIntervals []config.MuteTimeInterval `yaml:"mute_time_intervals,omitempty" json:"mute_time_intervals,omitempty"`
|
||||
Templates []string `yaml:"templates" json:"templates"`
|
||||
}
|
||||
@ -936,6 +939,15 @@ func (c *Config) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
tiNames := make(map[string]struct{})
|
||||
for _, ti := range c.TimeIntervals {
|
||||
if ti.Name == "" {
|
||||
return fmt.Errorf("missing name in time interval")
|
||||
}
|
||||
if _, ok := tiNames[ti.Name]; ok {
|
||||
return fmt.Errorf("time interval %q is not unique", ti.Name)
|
||||
}
|
||||
tiNames[ti.Name] = struct{}{}
|
||||
}
|
||||
for _, mt := range c.MuteTimeIntervals {
|
||||
if mt.Name == "" {
|
||||
return fmt.Errorf("missing name in mute time interval")
|
||||
@ -976,6 +988,8 @@ func (c *PostableApiAlertingConfig) GetReceivers() []*PostableApiReceiver {
|
||||
return c.Receivers
|
||||
}
|
||||
|
||||
func (c *PostableApiAlertingConfig) GetTimeIntervals() []config.TimeInterval { return c.TimeIntervals }
|
||||
|
||||
func (c *PostableApiAlertingConfig) GetMuteTimeIntervals() []config.MuteTimeInterval {
|
||||
return c.MuteTimeIntervals
|
||||
}
|
||||
|
@ -485,7 +485,50 @@ func Test_ConfigUnmashaling(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "empty mute time name should error",
|
||||
desc: "missing time interval name should error",
|
||||
err: errors.New("missing name in time interval"),
|
||||
input: `
|
||||
{
|
||||
"route": {
|
||||
"receiver": "grafana-default-email"
|
||||
},
|
||||
"time_intervals": [
|
||||
{
|
||||
"name": "",
|
||||
"time_intervals": [
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"end_time": "12:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": null,
|
||||
"receivers": [
|
||||
{
|
||||
"name": "grafana-default-email",
|
||||
"grafana_managed_receiver_configs": [
|
||||
{
|
||||
"uid": "uxwfZvtnz",
|
||||
"name": "email receiver",
|
||||
"type": "email",
|
||||
"disableResolveMessage": false,
|
||||
"settings": {
|
||||
"addresses": "<example@email.com>"
|
||||
},
|
||||
"secureFields": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
}, {
|
||||
desc: "missing mute time interval name should error",
|
||||
err: errors.New("missing name in mute time interval"),
|
||||
input: `
|
||||
{
|
||||
@ -529,7 +572,64 @@ func Test_ConfigUnmashaling(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "not unique mute time names should error",
|
||||
desc: "duplicate time interval names should error",
|
||||
err: errors.New("time interval \"test1\" is not unique"),
|
||||
input: `
|
||||
{
|
||||
"route": {
|
||||
"receiver": "grafana-default-email"
|
||||
},
|
||||
"time_intervals": [
|
||||
{
|
||||
"name": "test1",
|
||||
"time_intervals": [
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"end_time": "12:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "test1",
|
||||
"time_intervals": [
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"end_time": "12:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": null,
|
||||
"receivers": [
|
||||
{
|
||||
"name": "grafana-default-email",
|
||||
"grafana_managed_receiver_configs": [
|
||||
{
|
||||
"uid": "uxwfZvtnz",
|
||||
"name": "email receiver",
|
||||
"type": "email",
|
||||
"disableResolveMessage": false,
|
||||
"settings": {
|
||||
"addresses": "<example@email.com>"
|
||||
},
|
||||
"secureFields": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "duplicate mute time interval names should error",
|
||||
err: errors.New("mute time interval \"test1\" is not unique"),
|
||||
input: `
|
||||
{
|
||||
@ -585,6 +685,65 @@ func Test_ConfigUnmashaling(t *testing.T) {
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "duplicate time and mute time interval names should error",
|
||||
err: errors.New("mute time interval \"test1\" is not unique"),
|
||||
input: `
|
||||
{
|
||||
"route": {
|
||||
"receiver": "grafana-default-email"
|
||||
},
|
||||
"mute_time_intervals": [
|
||||
{
|
||||
"name": "test1",
|
||||
"time_intervals": [
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"end_time": "12:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"time_intervals": [
|
||||
{
|
||||
"name": "test1",
|
||||
"time_intervals": [
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"end_time": "12:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": null,
|
||||
"receivers": [
|
||||
{
|
||||
"name": "grafana-default-email",
|
||||
"grafana_managed_receiver_configs": [
|
||||
{
|
||||
"uid": "uxwfZvtnz",
|
||||
"name": "email receiver",
|
||||
"type": "email",
|
||||
"disableResolveMessage": false,
|
||||
"settings": {
|
||||
"addresses": "<example@email.com>"
|
||||
},
|
||||
"secureFields": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "mute time intervals on root route should error",
|
||||
err: errors.New("root route must not have any mute time intervals"),
|
||||
|
@ -111,6 +111,10 @@ func (a AlertingConfiguration) InhibitRules() []alertingNotify.InhibitRule {
|
||||
return a.alertmanagerConfig.InhibitRules
|
||||
}
|
||||
|
||||
func (a AlertingConfiguration) TimeIntervals() []alertingNotify.TimeInterval {
|
||||
return a.alertmanagerConfig.TimeIntervals
|
||||
}
|
||||
|
||||
func (a AlertingConfiguration) MuteTimeIntervals() []alertingNotify.MuteTimeInterval {
|
||||
return a.alertmanagerConfig.MuteTimeIntervals
|
||||
}
|
||||
|
@ -21,12 +21,13 @@ type NotificationSettingsValidator interface {
|
||||
// staticValidator is a NotificationSettingsValidator that uses static pre-fetched values for available receivers and mute timings.
|
||||
type staticValidator struct {
|
||||
availableReceivers map[string]struct{}
|
||||
availableMuteTimings map[string]struct{}
|
||||
availableTimeIntervals map[string]struct{}
|
||||
}
|
||||
|
||||
// apiAlertingConfig contains the methods required to validate NotificationSettings and create autogen routes.
|
||||
type apiAlertingConfig[R receiver] interface {
|
||||
GetReceivers() []R
|
||||
GetTimeIntervals() []config.TimeInterval
|
||||
GetMuteTimeIntervals() []config.MuteTimeInterval
|
||||
GetRoute() *definitions.Route
|
||||
}
|
||||
@ -42,14 +43,17 @@ func NewNotificationSettingsValidator[R receiver](am apiAlertingConfig[R]) Notif
|
||||
availableReceivers[receiver.GetName()] = struct{}{}
|
||||
}
|
||||
|
||||
availableMuteTimings := make(map[string]struct{})
|
||||
availableTimeIntervals := make(map[string]struct{})
|
||||
for _, interval := range am.GetTimeIntervals() {
|
||||
availableTimeIntervals[interval.Name] = struct{}{}
|
||||
}
|
||||
for _, interval := range am.GetMuteTimeIntervals() {
|
||||
availableMuteTimings[interval.Name] = struct{}{}
|
||||
availableTimeIntervals[interval.Name] = struct{}{}
|
||||
}
|
||||
|
||||
return staticValidator{
|
||||
availableReceivers: availableReceivers,
|
||||
availableMuteTimings: availableMuteTimings,
|
||||
availableTimeIntervals: availableTimeIntervals,
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +67,7 @@ func (n staticValidator) Validate(settings models.NotificationSettings) error {
|
||||
errs = append(errs, fmt.Errorf("receiver '%s' does not exist", settings.Receiver))
|
||||
}
|
||||
for _, interval := range settings.MuteTimeIntervals {
|
||||
if _, ok := n.availableMuteTimings[interval]; !ok {
|
||||
if _, ok := n.availableTimeIntervals[interval]; !ok {
|
||||
errs = append(errs, fmt.Errorf("mute time interval '%s' does not exist", interval))
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/prometheus/alertmanager/timeinterval"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -192,6 +193,69 @@ func TestIntegrationAlertmanagerConfiguration(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "configuration with time intervals",
|
||||
cfg: apimodels.PostableUserConfig{
|
||||
AlertmanagerConfig: apimodels.PostableApiAlertingConfig{
|
||||
Config: apimodels.Config{
|
||||
Route: &apimodels.Route{
|
||||
Receiver: "test",
|
||||
Routes: []*apimodels.Route{{
|
||||
MuteTimeIntervals: []string{"weekends"},
|
||||
}},
|
||||
},
|
||||
TimeIntervals: []config.TimeInterval{{
|
||||
Name: "weekends",
|
||||
TimeIntervals: []timeinterval.TimeInterval{{
|
||||
Weekdays: []timeinterval.WeekdayRange{{
|
||||
InclusiveRange: timeinterval.InclusiveRange{
|
||||
Begin: 1,
|
||||
End: 5,
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Receivers: []*apimodels.PostableApiReceiver{{
|
||||
Receiver: config.Receiver{
|
||||
Name: "test",
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
// TODO: Mute time intervals is deprecated in Alertmanager and scheduled to be
|
||||
// removed before version 1.0. Remove this test when support for mute time
|
||||
// intervals is removed.
|
||||
name: "configuration with mute time intervals",
|
||||
cfg: apimodels.PostableUserConfig{
|
||||
AlertmanagerConfig: apimodels.PostableApiAlertingConfig{
|
||||
Config: apimodels.Config{
|
||||
Route: &apimodels.Route{
|
||||
Receiver: "test",
|
||||
Routes: []*apimodels.Route{{
|
||||
MuteTimeIntervals: []string{"weekends"},
|
||||
}},
|
||||
},
|
||||
MuteTimeIntervals: []config.MuteTimeInterval{{
|
||||
Name: "weekends",
|
||||
TimeIntervals: []timeinterval.TimeInterval{{
|
||||
Weekdays: []timeinterval.WeekdayRange{{
|
||||
InclusiveRange: timeinterval.InclusiveRange{
|
||||
Begin: 1,
|
||||
End: 5,
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
Receivers: []*apimodels.PostableApiReceiver{{
|
||||
Receiver: config.Receiver{
|
||||
Name: "test",
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
Loading…
Reference in New Issue
Block a user