Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds: Active time interval #2779

Merged
merged 49 commits into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
652057f
add active time interval
dubyte Nov 27, 2021
2ba3521
fix active time interval
dubyte Nov 27, 2021
4b1db50
fix unittests for active time interval
dubyte Dec 2, 2021
95c6b29
Update notify/notify.go
dubyte Dec 20, 2021
4de7970
Update dispatch/route.go
dubyte Jan 10, 2022
754faa3
split the stage for active and mute intervals
dubyte Jan 10, 2022
d226412
Update notify/notify.go
dubyte Jan 19, 2022
ffb9820
Update notify/notify.go
dubyte Jan 19, 2022
7f5207d
Update notify/notify.go
dubyte Jan 19, 2022
9141e7c
Update notify/notify.go
dubyte Jan 19, 2022
a7c0045
fix code after commit suggestions
dubyte Jan 19, 2022
2293d8b
Making mute_time_interval and time_intervals can coexist in the config
dubyte Jan 19, 2022
50ce242
docs: configuration's doc has been updated about time intervals
dubyte Jan 19, 2022
497b7d3
Update config/config.go
dubyte Jan 25, 2022
a784fce
Update docs/configuration.md
dubyte Jan 25, 2022
fa944d9
Update docs/configuration.md
dubyte Jan 25, 2022
5de6bd1
Update docs/configuration.md
dubyte Jan 25, 2022
dbc872d
Update docs/configuration.md
dubyte Jan 25, 2022
a8cacb2
updates configuration readme to improve active time description
dubyte Jan 26, 2022
c1e5b67
merge deprecated mute_time_intervals and time_intervals
dubyte Jan 26, 2022
ec857b9
Update docs/configuration.md
dubyte Jan 26, 2022
166933e
Update docs/configuration.md
dubyte Jan 26, 2022
eb239f4
Update docs/configuration.md
dubyte Jan 26, 2022
c78ba45
Update docs/configuration.md
dubyte Jan 26, 2022
6af2dec
Update docs/configuration.md
dubyte Jan 26, 2022
9119821
Update docs/configuration.md
dubyte Jan 26, 2022
30c5934
Update cmd/alertmanager/main.go
dubyte Jan 26, 2022
0cb6d97
Update cmd/alertmanager/main.go
dubyte Jan 26, 2022
84e499a
fmt main.go
dubyte Jan 26, 2022
b93b7ab
Update docs/configuration.md
dubyte Jan 26, 2022
8a04f54
Update docs/configuration.md
dubyte Jan 26, 2022
7fb3e5c
fix lint error
clyang82 Dec 9, 2021
f51a3c5
Document that matchers are ANDed together
mac-chaffee Nov 7, 2021
240651b
Remove extra parentheticals
mac-chaffee Nov 9, 2021
c03dcc8
config: root route should have empty matchers
philipgough Dec 2, 2021
6fda5ae
chore: Let git ignore temporary files for ui/app
nekketsuuu Oct 24, 2021
a70b893
adding max_alerts parameter to slack webhook config
Nov 26, 2021
979d234
*: bump to Go 1.17 (#2792)
simonpasquier Dec 22, 2021
b9c04d1
Automate CSS-inlining for default HTML email template (#2798)
bison Jan 3, 2022
d9ce2e3
go.{mod,sum}: update Go dependencies
simonpasquier Dec 17, 2021
677a55d
amtool to support http_config to access alertmanager (#2764)
clyang82 Jan 19, 2022
196ed1c
notify/sns: detect FIFO topic based on the rendered value
simonpasquier Jan 21, 2022
d7d335e
config: delegate Sigv4 validation to the inner type
simonpasquier Jan 5, 2022
d2cafa8
Merge branch 'main' into active_time_interval
dubyte Jan 26, 2022
9b569a3
fix unittests
dubyte Jan 26, 2022
db0f715
fix comment about active time interval
dubyte Feb 18, 2022
745372b
fix another comment about active time interval
dubyte Feb 18, 2022
5ee5e18
Update docs/configuration.md
dubyte Feb 22, 2022
17a5f5e
Update docs/configuration.md
dubyte Feb 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions cmd/alertmanager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,14 @@ func run() int {
integrationsNum += len(integrations)
}

// Build the map of time interval names to mute time definitions.
muteTimes := make(map[string][]timeinterval.TimeInterval, len(conf.MuteTimeIntervals))
// Build the map of time interval names to time interval definitions.
timeIntervals := make(map[string][]timeinterval.TimeInterval, len(conf.MuteTimeIntervals)+len(conf.TimeIntervals))
for _, ti := range conf.MuteTimeIntervals {
muteTimes[ti.Name] = ti.TimeIntervals
timeIntervals[ti.Name] = ti.TimeIntervals
}

for _, ti := range conf.TimeIntervals {
timeIntervals[ti.Name] = ti.TimeIntervals
}

inhibitor.Stop()
Expand All @@ -461,7 +465,7 @@ func run() int {
waitFunc,
inhibitor,
silencer,
muteTimes,
timeIntervals,
notificationLog,
pipelinePeer,
)
Expand Down
69 changes: 54 additions & 15 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,34 @@ func (mt *MuteTimeInterval) UnmarshalYAML(unmarshal func(interface{}) error) err
return nil
}

// TimeInterval represents a named set of time intervals for which a route should be muted.
type TimeInterval struct {
Name string `yaml:"name" json:"name"`
TimeIntervals []timeinterval.TimeInterval `yaml:"time_intervals" json:"time_intervals"`
}

// UnmarshalYAML implements the yaml.Unmarshaler interface for MuteTimeInterval.
func (ti *TimeInterval) UnmarshalYAML(unmarshal func(interface{}) error) error {
type plain TimeInterval
if err := unmarshal((*plain)(ti)); err != nil {
return err
}
if ti.Name == "" {
return fmt.Errorf("missing name in time interval")
}
return nil
}

// Config is the top-level configuration for Alertmanager's config files.
type Config struct {
Global *GlobalConfig `yaml:"global,omitempty" json:"global,omitempty"`
Route *Route `yaml:"route,omitempty" json:"route,omitempty"`
InhibitRules []*InhibitRule `yaml:"inhibit_rules,omitempty" json:"inhibit_rules,omitempty"`
Receivers []*Receiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
Templates []string `yaml:"templates" json:"templates"`
Global *GlobalConfig `yaml:"global,omitempty" json:"global,omitempty"`
Route *Route `yaml:"route,omitempty" json:"route,omitempty"`
InhibitRules []*InhibitRule `yaml:"inhibit_rules,omitempty" json:"inhibit_rules,omitempty"`
Receivers []*Receiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
Templates []string `yaml:"templates" json:"templates"`
// Deprecated. Remove before v1.0 release.
MuteTimeIntervals []MuteTimeInterval `yaml:"mute_time_intervals,omitempty" json:"mute_time_intervals,omitempty"`
TimeIntervals []TimeInterval `yaml:"time_intervals,omitempty" json:"time_intervals,omitempty"`

// original is the input from which the config was parsed.
original string
Expand Down Expand Up @@ -478,18 +498,32 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
return fmt.Errorf("root route must not have any mute time intervals")
}

if len(c.Route.ActiveTimeIntervals) > 0 {
return fmt.Errorf("root route must not have any active time intervals")
}

// Validate that all receivers used in the routing tree are defined.
if err := checkReceiver(c.Route, names); err != nil {
return err
}

tiNames := make(map[string]struct{})

// read mute time intervals until deprecated
for _, mt := range c.MuteTimeIntervals {
if _, ok := tiNames[mt.Name]; ok {
return fmt.Errorf("mute time interval %q is not unique", mt.Name)
}
tiNames[mt.Name] = struct{}{}
}

for _, mt := range c.TimeIntervals {
if _, ok := tiNames[mt.Name]; ok {
return fmt.Errorf("time interval %q is not unique", mt.Name)
}
tiNames[mt.Name] = struct{}{}
}

return checkTimeInterval(c.Route, tiNames)
}

Expand All @@ -516,12 +550,16 @@ func checkTimeInterval(r *Route, timeIntervals map[string]struct{}) error {
return err
}
}
if len(r.MuteTimeIntervals) == 0 {
return nil

for _, ti := range r.ActiveTimeIntervals {
if _, ok := timeIntervals[ti]; !ok {
return fmt.Errorf("undefined time interval %q used in route", ti)
}
}
for _, mt := range r.MuteTimeIntervals {
if _, ok := timeIntervals[mt]; !ok {
return fmt.Errorf("undefined time interval %q used in route", mt)

for _, tm := range r.MuteTimeIntervals {
if _, ok := timeIntervals[tm]; !ok {
return fmt.Errorf("undefined time interval %q used in route", tm)
}
}
return nil
Expand Down Expand Up @@ -679,11 +717,12 @@ type Route struct {
// Deprecated. Remove before v1.0 release.
Match map[string]string `yaml:"match,omitempty" json:"match,omitempty"`
// Deprecated. Remove before v1.0 release.
MatchRE MatchRegexps `yaml:"match_re,omitempty" json:"match_re,omitempty"`
Matchers Matchers `yaml:"matchers,omitempty" json:"matchers,omitempty"`
MuteTimeIntervals []string `yaml:"mute_time_intervals,omitempty" json:"mute_time_intervals,omitempty"`
Continue bool `yaml:"continue" json:"continue,omitempty"`
Routes []*Route `yaml:"routes,omitempty" json:"routes,omitempty"`
MatchRE MatchRegexps `yaml:"match_re,omitempty" json:"match_re,omitempty"`
Matchers Matchers `yaml:"matchers,omitempty" json:"matchers,omitempty"`
MuteTimeIntervals []string `yaml:"mute_time_intervals,omitempty" json:"mute_time_intervals,omitempty"`
ActiveTimeIntervals []string `yaml:"active_time_intervals,omitempty" json:"active_time_intervals,omitempty"`
Continue bool `yaml:"continue" json:"continue,omitempty"`
Routes []*Route `yaml:"routes,omitempty" json:"routes,omitempty"`

GroupWait *model.Duration `yaml:"group_wait,omitempty" json:"group_wait,omitempty"`
GroupInterval *model.Duration `yaml:"group_interval,omitempty" json:"group_interval,omitempty"`
Expand Down
61 changes: 58 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,35 @@ receivers:

}

func TestMuteTimeHasName(t *testing.T) {
func TestActiveTimeExists(t *testing.T) {
in := `
mute_time_intervals:
route:
receiver: team-Y
routes:
- match:
severity: critical
active_time_intervals:
- business_hours

receivers:
- name: 'team-Y'
`
_, err := Load(in)

expected := "undefined time interval \"business_hours\" used in route"

if err == nil {
t.Fatalf("no error returned, expected:\n%q", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%q\ngot:\n%q", expected, err.Error())
}

}

func TestTimeIntervalHasName(t *testing.T) {
in := `
time_intervals:
- name:
time_intervals:
- times:
Expand All @@ -199,7 +225,7 @@ route:
`
_, err := Load(in)

expected := "missing name in mute time interval"
expected := "missing name in time interval"

if err == nil {
t.Fatalf("no error returned, expected:\n%q", expected)
Expand Down Expand Up @@ -358,6 +384,35 @@ route:

}

func TestRootRouteNoActiveTimes(t *testing.T) {
in := `
time_intervals:
- name: my_active_time
time_intervals:
- times:
- start_time: '09:00'
end_time: '17:00'

receivers:
- name: 'team-X-mails'

route:
receiver: 'team-X-mails'
active_time_intervals:
- my_active_time
`
_, err := Load(in)

expected := "root route must not have any active time intervals"

if err == nil {
t.Fatalf("no error returned, expected:\n%q", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%q\ngot:\n%q", expected, err.Error())
}
}

func TestRootRouteHasNoMatcher(t *testing.T) {
testCases := []struct {
name string
Expand Down
1 change: 1 addition & 0 deletions dispatch/dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ func (ag *aggrGroup) run(nf notifyFunc) {
ctx = notify.WithReceiverName(ctx, ag.opts.Receiver)
ctx = notify.WithRepeatInterval(ctx, ag.opts.RepeatInterval)
ctx = notify.WithMuteTimeIntervals(ctx, ag.opts.MuteTimeIntervals)
ctx = notify.WithActiveTimeIntervals(ctx, ag.opts.ActiveTimeIntervals)

// Wait the configured interval before calling flush again.
ag.mtx.Lock()
Expand Down
4 changes: 4 additions & 0 deletions dispatch/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func NewRoute(cr *config.Route, parent *Route) *Route {
sort.Sort(matchers)

opts.MuteTimeIntervals = cr.MuteTimeIntervals
opts.ActiveTimeIntervals = cr.ActiveTimeIntervals

route := &Route{
parent: parent,
Expand Down Expand Up @@ -210,6 +211,9 @@ type RouteOpts struct {

// A list of time intervals for which the route is muted.
MuteTimeIntervals []string

// A list of time intervals for which the route is active.
ActiveTimeIntervals []string
}

func (ro *RouteOpts) String() string {
Expand Down
41 changes: 38 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,14 @@ receivers:
inhibit_rules:
[ - <inhibit_rule> ... ]

# DEPRECATED: use time_intervals below.
# A list of mute time intervals for muting routes.
mute_time_intervals:
[ - <mute_time_interval> ... ]

# A list of time intervals for muting/activating routes.
time_intervals:
[ - <time_interval> ... ]
```

## `<route>`
Expand Down Expand Up @@ -189,6 +194,16 @@ matchers:
mute_time_intervals:
[ - <string> ...]

dubyte marked this conversation as resolved.
Show resolved Hide resolved
# Times when the route should be active. These must match the name of a
dubyte marked this conversation as resolved.
Show resolved Hide resolved
# time interval defined in the time_intervals section. An empty value
# means that the route is always active.
# Additionally, the root node cannot have any active times.
# The route will send notifications only when active, but otherwise
# acts normally (including ending the route-matching process
# if the `continue` option is not set).
active_time_intervals:
[ - <string> ...]

# Zero or more child routes.
routes:
[ - <route> ... ]
Expand Down Expand Up @@ -221,12 +236,32 @@ route:
group_by: [product, environment]
matchers:
- team="frontend"

# All alerts with the service=inhouse-service label match this sub-route.
# the route will be muted during offhours and holidays time intervals.
# even if it matches, it will continue to the next sub-route
- receiver: 'dev-pager'
matchers:
- service="inhouse-service"
mute_time_intervals:
- offhours
- holidays
continue: true

# All alerts with the service=inhouse-service label match this sub-route
# the route will be active only during offhours and holidays time intervals.
- receiver: 'on-call-pager'
matchers:
- service="inhouse-service"
active_time_intervals:
- offhours
- holidays
```

## `<mute_time_interval>`
## `<time_interval>`

A `mute_time_interval` specifies a named interval of time that may be referenced
in the routing tree to mute particular routes for particular times of the day.
A `time_interval` specifies a named interval of time that may be referenced
in the routing tree to mute/activate particular routes for particular times of the day.

```yaml
name: <string>
Expand Down
Loading